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

Author Topic: glFlush() error. [SOLVED]  (Read 4715 times)

0 Members and 1 Guest are viewing this topic.

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
glFlush() error. [SOLVED]
« on: September 18, 2020, 10:39:01 pm »
This error comes when I'm working with textures sometimes and I don't know exactly what causes it, even weirder is that when i pops up there are no apparent issues, and everything seems to work just fine, but I want to know what causes it, and how I can avoid it:

Since I don't know exactly what causes the error I didn't post any code, but I'll do so if needed.

« Last Edit: September 25, 2020, 12:48:12 am by Riser »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: glFlush() error.
« Reply #1 on: September 19, 2020, 05:40:49 pm »
Are you doing any custom OpenGL calls or use multiple threads?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: glFlush() error.
« Reply #2 on: September 19, 2020, 09:34:02 pm »
Nope, I am merely trying to display a sprite.
I am using an Asset Manager like you recommended to me to when I first came here.
A texture that calls the Asset Manager is a member inside a Sprite class that I use to make working with sprites easier:

Sprite.h:

class Sprite {
public:
        AssetManager manager;
        sf::Texture m_Texture;
        sf::Sprite m_Sprite;

        sf::Vector2f sprite_scale;
        sf::Vector2u original_size;
        sf::Vector2f texture_size;

        Sprite(std::string path,sf::IntRect rect,sf::Vector2f size);
       
};
 

Sprite.cpp:

Sprite::Sprite(std::string path, sf::IntRect rect, sf::Vector2f size) {
        m_Texture = sf::Texture(AssetManager::LoadTexture(path));
        m_Sprite.setTextureRect(rect);
        m_Sprite.setTexture(m_Texture);

        original_size = m_Texture.getSize();

        texture_size.x = static_cast<float>(original_size.x);
        texture_size.y = static_cast<float>(original_size.y);

        sprite_scale.x = size.x / texture_size.x;
        sprite_scale.y = size.y / texture_size.y;

        m_Sprite.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
        m_Sprite.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));

}
 


An object of said Sprite class is itself a member inside an Entity class where I use assignment on said object to pass it arguments:

Entity.h:

class Entity {
public:
        Sprite entity_sprite = Sprite("res/wildcard.png", { 0,0,36,63 }, { 36,63 });
        int health;
        float speed;
        bool collision = false;

        bool entity_collision(sf::Sprite entity2_sprite);
       

};
 

This isn't exactly what I'm trying to do, I'm trying to create a Player class that inherits from this class and pass the arguments to that, but I'm having a completely separate problem with that and for now I want to see what this bug is all about.
Like I said, this code works, and the previous project this error popped up it in also worked, but I'm a bit worried about it.
« Last Edit: September 19, 2020, 10:26:11 pm by Riser »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: glFlush() error.
« Reply #3 on: September 20, 2020, 08:36:22 am »
Are you using a build from the master branch?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

fallahn

  • Sr. Member
  • ****
  • Posts: 492
  • Buns.
    • View Profile
    • Trederia
Re: glFlush() error.
« Reply #4 on: September 20, 2020, 12:19:16 pm »
The error is quite possibly caused by the fact that this line

m_Texture = sf::Texture(AssetManager::LoadTexture(path));


is copying the texture at least once. You should be storing references to your textures in the sprite, not copies.

To start with ensure that your asset manager returns a reference to the held textures, else you'll be getting a copy here (you haven't shared the code for your asset manager). It should look something like
sf::Texture& AssetManager::loadTexture(const std::string& path)

Then use a reference (or a pointer) to sf::Texture in your sprite class and use an initialiser list to  set it up correctly on construction.

As a side note: placing your asset manager as a sprite member is somewhat redundant, you'll be creating a new asset manager with every sprite. The idea of asset managers is that a single instance exists which can share its held resources with multiple sprites (or other types eg sounds etc). I'd suggest refactoring your sprite class to something like:

class Sprite {
public:
        sf::Texture& m_Texture;
        sf::Sprite m_Sprite;

        sf::Vector2f sprite_scale;
        sf::Vector2u original_size;
        sf::Vector2f texture_size;

        Sprite(sf::Texture&,sf::IntRect rect,sf::Vector2f size);    
};

Sprite::Sprite(sf::Texture& texture, sf::IntRect rect, sf::Vector2f size)
    : m_texture(texture),
    m_sprite(texture)
 {
        m_Sprite.setTextureRect(rect);

        original_size = m_Texture.getSize();

        texture_size.x = static_cast<float>(original_size.x);
        texture_size.y = static_cast<float>(original_size.y);

        sprite_scale.x = size.x / texture_size.x;
        sprite_scale.y = size.y / texture_size.y;

        m_Sprite.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
        m_Sprite.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));

}

 

Note that the texture is passed purely by reference, removing any copy operations (which should hopefully fix your OpenGL error). The sprite and texture members are both initialised with an initialiser list (which you should be using in all of your constructors, btw).To use this sprite class make sure to add a single instance of your asset manager to your game class (or wherever your sprites are created) then pass texture references from it like so:

Sprite spr1(m_assetManager.loadTexture(path), rect, size);
Sprite spr2(m_assetManager.loadTexture(otherPath), otherRect, otherSize);
 

This way your asset manager *owns* a single instance of each texture, references to which are passed out and shared with as many sprites which need them.






Although when all is said an done you can remove the sf::Texture member entirely: the sf::Sprite member will hold a reference for you and all your texture queries can be done through sf::Sprite::getTexture()

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: glFlush() error.
« Reply #5 on: September 20, 2020, 01:17:50 pm »
This is really just a bug that was already fixed on master: https://github.com/SFML/SFML/pull/1609
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: glFlush() error.
« Reply #6 on: September 20, 2020, 11:42:08 pm »
fallahn, I did as you said, but now it stopped working entirely, the thing is, the reason I wrote this line like this in the first place:
m_Texture = sf::Texture(AssetManager::LoadTexture(path));
Is because I couldn't pass arguments to objects normally for some reason, and had to use assignment.
So in the end I had to write it like this:
Sprite spr1=Sprite(m_assetManager::loadTexture(path), rect, size);
(Also I'm using a scope resolution operator because the Asset Manager is set up in a way that allows me to access the class directly without having to declare objects, there's supposed to be a single instance of it after all.)
Same thing for the Sprite object declared in the entity class, I have to use assignment there too, otherwise I get multiple errors such as "expected type specifier" and "call of an object of a class type without appropriate operator() or conversion function to pointer-to-function type", any idea why that's happening?

eXpl0it3r, I'll figure out how to update to the master build after I solve this issue, I've been using my own template that I setup following a Youtube tutorial (By Sonar Systems).
« Last Edit: September 20, 2020, 11:57:02 pm by Riser »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: glFlush() error.
« Reply #7 on: September 21, 2020, 07:46:33 am »
I hope, by "solve my issue" you don't mean the glFlush errors, because thise can only be fixed by updating SFML. :D
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

fallahn

  • Sr. Member
  • ****
  • Posts: 492
  • Buns.
    • View Profile
    • Trederia
Re: glFlush() error.
« Reply #8 on: September 21, 2020, 11:45:07 am »
I can't say for sure without knowing how your asset manager works. It seems really odd to me that you have to construct a texture from the return value like this

sf::Texture(AssetManager::LoadTexture(path));

when really you want to be able to do something like

sf::Texture& myTex = AssetManager::loadTexture(path);

The SFML Game Development book has a good chapter on resource management, the source of which is also available.

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: glFlush() error.
« Reply #9 on: September 21, 2020, 12:12:08 pm »
Alright here it is, it's the asset manager from the "SFML Essentials" book, but I added a method for fonts after seeing one in another asset manager tutorial on Youtube (Also by Sonar Systems):

AssetManager.h:

#pragma once
#include "Window/Window.h"
#include <map>


class AssetManager {
public:
        AssetManager();
       
        static sf::Texture& LoadTexture(std::string const& path);
        static sf::SoundBuffer& LoadSoundBuffer(std::string const& path);
        static sf::Font& LoadFont(std::string const& path);

private:
        std::map<std::string, sf::Texture> m_Textures;
        std::map<std::string, sf::SoundBuffer> m_SoundBuffers;
        std::map<std::string, sf::Font> m_Fonts;

        static AssetManager* sInstance;
};
 

AssetManager.cpp:

#include "AssetManager.h"
#include <assert.h>

AssetManager* AssetManager::sInstance = nullptr;

AssetManager::AssetManager() {
        assert(sInstance == nullptr);
        sInstance = this;
}

sf::Texture& AssetManager::LoadTexture(std::string const& path) {

        auto& texMap = sInstance->m_Textures;
        auto pairFound = texMap.find(path);

        if (pairFound != texMap.end()) {
                return pairFound->second;
        }
        else {
                auto& texture = texMap[path];
                texture.loadFromFile(path);
                return texture;
        }

}

sf::SoundBuffer& AssetManager::LoadSoundBuffer(std::string const& path) {

        auto& sBufferMap = sInstance->m_SoundBuffers;
        auto pairFound = sBufferMap.find(path);

        if (pairFound != sBufferMap.end()) {
                return pairFound->second;
        }
        else {
                auto& sBuffer = sBufferMap[path];
                sBuffer.loadFromFile(path);
                return sBuffer;
        }

}

sf::Font& AssetManager::LoadFont(std::string const& path) {

        auto& FontMap = sInstance->m_Fonts;
        auto pairFound = FontMap.find(path);

        if (pairFound != FontMap.end()) {
                return pairFound->second;
        }
        else {
                auto& font = FontMap[path];
                font.loadFromFile(path);
                return font;
        }

}
 

Right now I wanna learn how to do this correctly, as soon as I get it to work I'll update SFML, whether the glFlush() error was still there or not.
« Last Edit: September 21, 2020, 12:43:57 pm by Riser »

fallahn

  • Sr. Member
  • ****
  • Posts: 492
  • Buns.
    • View Profile
    • Trederia
Re: glFlush() error.
« Reply #10 on: September 21, 2020, 02:00:19 pm »
OK, seems reasonable to me (it works but my personal preference would be to stay away from singletons, although that's a whole different topic ;) ). I created this CME with your modified Sprite class, which works for me. Can you test it?


#include "AssetManager.h"

#include <SFML/Graphics.hpp>

class Sprite
{
public:
    Sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size)
        : m_texture(tx), m_sprite(tx)
    {
        m_sprite.setTextureRect(rect);

        original_size = m_texture.getSize();

        texture_size.x = static_cast<float>(original_size.x);
        texture_size.y = static_cast<float>(original_size.y);

        sprite_scale.x = size.x / texture_size.x;
        sprite_scale.y = size.y / texture_size.y;

        m_sprite.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
        m_sprite.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));
    }

    sf::Texture& m_texture;
    sf::Sprite m_sprite;

    sf::Vector2f sprite_scale;
    sf::Vector2u original_size;
    sf::Vector2f texture_size;
};

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "My window");

    AssetManager ass;

    auto& tx = AssetManager::LoadTexture("assets/images/flower.png");
    Sprite spr1(tx, sf::IntRect(0,0,64,192), sf::Vector2f(64.f, 192.f));
    spr1.m_sprite.setPosition(64.f, 128.f);

    Sprite spr2(AssetManager::LoadTexture("assets/images/flower.png"), sf::IntRect(0,0,64,192), sf::Vector2f(32.f, 96.f));
    spr2.m_sprite.setPosition(192.f, 128.f);

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

        window.clear(sf::Color::Black);
        window.draw(spr1.m_sprite);
        window.draw(spr2.m_sprite);
        window.display();
    }

    return 0;
}

 

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: glFlush() error.
« Reply #11 on: September 22, 2020, 12:28:33 am »
Ok, the code as is DOES work with zero issues, but when I try to use the asset manager from the Entity class, several issues start arising:
-I can't include a Sprite object because I get an error saying "no default constructor exists for class "Sprite"".
-I can't call the Sprite constructor inside the Entity constructor like so:
        Entity() {
                entity_texture = AssetManager::LoadTexture("res/wildcard.png");
                entity_sprite = Sprite(entity_texture, sf::IntRect(0, 0, 36, 63), { 36,63 }).m_sprite;
        }
 
Because the app immediately crashes.
-And I didn't bother trying global variables (Declaring the sf::Texture and the Sprite globally outside the Entity class) even though I have a suspicion it might work, because I've learned global variables are not a good idea.

Now what?

fallahn

  • Sr. Member
  • ****
  • Posts: 492
  • Buns.
    • View Profile
    • Trederia
Re: glFlush() error.
« Reply #12 on: September 22, 2020, 10:24:33 am »
The Sprite class is not default constructable because the Texture reference must always be initialised to a value. The most flexible fix is to add a default constructor to the Sprite class.

Either turn the texture reference into a pointer and initialise it to nullptr, and update the existing constructor accordingly:
Sprite()
  : m_texture(nullptr)
{

}

Sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size)
    : m_texture(&tx), m_sprite(tx)
{
    m_sprite.setTextureRect(rect);

    original_size = m_texture->getSize();

    texture_size.x = static_cast<float>(original_size.x);
    texture_size.y = static_cast<float>(original_size.y);

    sprite_scale.x = size.x / texture_size.x;
    sprite_scale.y = size.y / texture_size.y;

    m_sprite.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
    m_sprite.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));
}
 

Or remove the texture member completely. As I mentioned in a previous post, sf::Sprite can be used to handle the texture reference.

Sprite()
{

}

Sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size)
    :  m_sprite(tx)
{
    m_sprite.setTextureRect(rect);

    original_size = m_sprite.getTexture()->getSize();

    texture_size.x = static_cast<float>(original_size.x);
    texture_size.y = static_cast<float>(original_size.y);

    sprite_scale.x = size.x / texture_size.x;
    sprite_scale.y = size.y / texture_size.y;

    m_sprite.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
    m_sprite.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));
}
 

HOWEVER from your entity constructor it looks like you're using the Sprite class to initialise and resize an sf::Sprite, which is then stored as a member of the Entity class. In which case why not use a simple function to set up your sprites?

sf::Sprite initSprite(sf::Texture& t, sf::IntRect rect, sf::Vector2f size)
{
    sf::Sprite sprite(t);
    sprite.setTextureRect(rect);

    sf::Vector2f texture_size(t.getSize());

    sprite.setScale(size.x / texture_size.x, size.y / texture_size.y );
    sprite.setOrigin(texture_size / 2.f);

    return sprite;
}

Entity()
{
    entity_sprite = initSprite(AssetManager::LoadTexture("res/wildcard.png"), sf::IntRect(0, 0, 36, 63), { 36,63 });
}

 

You're quite right to try avoiding globals, particularly with SFML types as SFML maintains its own global state which may get messed up. Using an asset manager implemented as a singleton probably constitutes global access, however :)

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: glFlush() error.
« Reply #13 on: September 22, 2020, 12:38:01 pm »
Didn't really follow the thread further, but if you want a "sprite" that also supports not having a texture, then it's probably better to just go with a sf::RectangleShape
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Riser

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: glFlush() error.
« Reply #14 on: September 22, 2020, 01:52:52 pm »
Yeah I've been working with sf::RectangleShape when I started for with SFML, but now I'm using sf::Sprite because almost all of the entities I'm using will have textures, plus you need Sprites when working with things like pixel-perfect collision and stuff.

Anyway, I refactored the code a bit following your advice, fallahn:

This is the Sprite class, it has a default constructor to get rid of that "no default constructor exists for class "Sprite"" error, and a method to set the Sprite, I also got rid of the Texture member as you said:

class Sprite{
public:
    sf::Sprite m_sprite;

    sf::Vector2f sprite_scale;
    sf::Vector2u original_size;
    sf::Vector2f texture_size;

    Sprite(){}
    sf::Sprite set_sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size);

};


sf::Sprite Sprite::set_sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size) {

    sf::Sprite spr(tx);

    spr.setTextureRect(rect);

    original_size =tx.getSize();

    texture_size.x = static_cast<float>(original_size.x);
    texture_size.y = static_cast<float>(original_size.y);

    sprite_scale.x = size.x / texture_size.x;
    sprite_scale.y = size.y / texture_size.y;

    spr.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
    spr.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));

    return spr;
}
 

And this is the Entity class:

class Entity {
public:
        Sprite spr;
        sf::Texture entity_texture;
        sf::Sprite entity_sprite;
        int health;
        float speed;
        bool collision = false;

        Entity() {
                entity_texture = AssetManager::LoadTexture("res/wildcard.png");
               
                entity_sprite = spr.set_sprite(entity_texture, { 0,0,36,63 }, { 36,63 });
        }
       
};
 

Same result, app still crashes immediately, what could possibly be causing this problem?
« Last Edit: September 22, 2020, 01:54:23 pm by Riser »

 

anything