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

Author Topic: Sharing sfml textures between class instances  (Read 2852 times)

0 Members and 1 Guest are viewing this topic.

kingguru

  • Newbie
  • *
  • Posts: 12
    • View Profile
Sharing sfml textures between class instances
« on: July 29, 2015, 08:27:32 pm »
Hi there,

I'm fairly new to SFML so please bear over with me if this has been answered a million times before. I just haven't been able to find a good example of this and it feels like there's something basic I'm not getting.

Let's say I have a class representing some sprite with a texture and I want to have more than one instance of that class and put that in an STL container. Something like:

class Ball
{
public:
  Ball()
  {
    texture_.loadFromFile("ball.png");
    sprite_.setTexture(texture_);
  }
private:
  sf::Texture texture_;
  sf::Sprite sprite_;
}

std::vector<Ball> balls = { Ball(), Ball() };
 

This is just example code that might not even compile to give an idea of what I'm trying to accomplish, but assuming it does this will still not work because you cannot (I think) copy an SFML texture which results in the "white square problem" I've seen mentioned often.

I have some different ideas on how to solve this, but they all feel sort of "wrong" which is why I feel like I am misunderstanding something.

You could:
  • Use a static shared_ptr, and then construct that the first time the class is initialized. This is sort of dirty and the fact that a sprite takes a reference to a texture hints that this is not the way to do it.
  • Using a global texture manager or similar which each instance can use to retrieve the texture. This has all the usual issues with global variables.
  • Creating the texture outside of the class using it and then giving every instance a reference to that. This is fairly cumbersome and I think it would be nicer to have the class using the texture owning it.

I've looked also looked at the ResourceManager from the Thor library, but that doesn't really seem to be useful for this case.

I know this is not that much a question specific to SFML, but I'm just really interested to hear how others are doing something like this since I cannot imagine I'm the only one facing this.

Thanks a lot.

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Sharing sfml textures between class instances
« Reply #1 on: July 29, 2015, 08:47:33 pm »
In my current project I have a ResourceManager class that Iooks like this:

template<typename T>
class ResourceManager
{
public:
    T& get(const std::string& filename) const;

private:
    mutable std::map<std::string, std::unique_ptr<T>> m_resources;
};

template<typename T>
T& ResourceManager<T>::get(const std::string& filename) const
{
    auto found = m_resources.find(filename);
    if (found == m_resources.end()) {
        std::unique_ptr<T> resource(new T());
        if (!resource->loadFromFile(filename))
            throw std::runtime_error("ResourceManager failed to load '" + filename + "'");

        auto inserted = m_resources.emplace(std::make_pair(filename, std::move(resource)));
        assert(inserted.second);
        return *inserted.first->second;
    }
    return *found->second;
}

template<>
inline sf::Music& ResourceManager<sf::Music>::get(const std::string& filename) const
{
    auto found = m_resources.find(filename);
    if (found == m_resources.end()) {
        std::unique_ptr<sf::Music> resource(new sf::Music());
        if (!resource->openFromFile(filename))
            throw std::runtime_error("ResourceManager failed to open '" + filename + "'");

        auto inserted = m_resources.emplace(std::make_pair(filename, std::move(resource)));
        assert(inserted.second);
        return *inserted.first->second;
    }
    return *found->second;
}

Then I create one instance of
ResourceManager<sf::Texture> textures;
in main and pass a const reference to it to each of my classes that need to access textures. They can then obtain the texture(s) they need like so:

class Player : public sf::Drawable, public sf::Transformable
{
public:
    explicit Player(const ResourceManager<sf::Texture>& textures);
    ...
private:
    sf::Sprite m_sprite;
    ...
};

Player::Player(const ResourceManager<sf::Texture>& textures)
{
    m_sprite.setTexture(textures.get("gfx/player.png"));
}

Had I known about Thor's ResourceHolder at the time I probably would have just used that.
« Last Edit: July 29, 2015, 09:20:31 pm by Jesper Juhl »

kingguru

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Sharing sfml textures between class instances
« Reply #2 on: July 29, 2015, 09:36:48 pm »
Thanks a lot for your answer Jesper.

I was actually thinking about the same solution, just didn't like the idea of having to pass a reference to every object I create if I could avoid it. That's definitely more a question of general code design than specific for SFML and not the first time I've had to deal with this when writing C++ code. :-)

I'm still interested if someone else have solved this some other way though. It's always interesting to hear different ways to solve a problem.

I will try to use the ResourceHolder from Thor. It seems to be doing exactly what your ResourceManager class is doing and since I'm already using Thor for some animation stuff I already have a dependency on that library.

Thanks once again.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Sharing sfml textures between class instances
« Reply #3 on: July 30, 2015, 12:39:56 pm »
To start with Thor's Resource module, you could have a look at this tutorial.
The corresponding API documentation can be found here.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

kingguru

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Sharing sfml textures between class instances
« Reply #4 on: July 30, 2015, 01:15:19 pm »
I solved it using the Thor Rersource classes and passing a reference around like Jesper suggested.

Works perfectly and the code is fairly clean. I could even get rid of my private texture member variable since I can construct the sprite directly by acquiring the texure from the resource manager in the constructor, so I actually ended up with less code  :D

Thanks a lot to both of you.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Sharing sfml textures between class instances
« Reply #5 on: July 30, 2015, 11:36:53 pm »
Glad to hear this! :)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development: