SFML community forums

Help => Graphics => Topic started by: Beagle on June 15, 2014, 07:28:53 pm

Title: Very weird sprite behaviour (white rectangle when attempting to draw sprite)
Post by: Beagle on June 15, 2014, 07:28:53 pm
Hey everyone :)

So, I've come across a very weird type of behaviour that has left me stumped.

First of all, I have successfully managed to draw a rain cloud picture using this code:

main.cpp
int main()
{
        RenderWindow window(VideoMode(800, 500), "Rain Cloud");

        WorldEntity rainCloud = WorldEntity();

        while (window.isOpen())
        {
                Event event;

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

                window.clear();
                window.draw(rainCloud.getSprite());
                window.display();
        }

        return 0;
}

And here's my simple WorldEntity class:
/*
WorldEntity is a collection of basic properties needed by all objects that needs to exist within the game world
*/

class WorldEntity
{
private:
        Sprite m_sprite;
        Vector2f m_position;
        Texture mahTexture;
public:
        WorldEntity::WorldEntity()
        {
                mahTexture.loadFromFile("RainCloud.png");
                m_sprite = Sprite(mahTexture);
                m_position = Vector2f(0, 0);
        }

        void setPosition(float x, float y);
        void setPosition(Vector2f newPosition);
        Sprite getSprite();
};

#endif

Now, this code works perfectly and the rain cloud sprite is drawn. However... if I do the following change to the WorldEntity class:
        WorldEntity::WorldEntity(Texture test)
        {
                mahTexture.loadFromFile("RainCloud.png");
                m_sprite = Sprite(mahTexture);
                m_position = Vector2f(0, 0);
        }

That is, I now pass a texture called "test" by value (Notice I do NOT use it for anything at all!). And then change the first part of the main.cpp source code to pass a texture instead:
        Texture texture_rainCloud;
       
        if (!texture_rainCloud.loadFromFile("TheActual.png"))
                cout << "Dummy textureTexture failed to load" << endl;

        WorldEntity rainCloud = WorldEntity(texture_rainCloud);

It does not work anymore. That is, now I get a white rectangle drawn instead of the cloud! Notice that all I did was simply pass a texture into the WorldEntity class that I do not even use for anything at all. I changed literally nothing but the fact that a texture is now passed to the constructor, and I don't use that variable for anything.

What exactly is going on there!? :D Anyone has any ideas?
Title: Re: Very weird sprite behaviour (white rectangle when attempting to draw sprite)
Post by: binary1248 on June 15, 2014, 08:41:27 pm
In the original version, you got lucky and the compiler optimized away the copy of WorldEntity, meaning it got constructed in place and as such the address of the texture the sprite refers to did not change after you set it.

In the second version, you weren't so lucky and the compiler didn't optimize away the copy resulting in the whole WorldEntity being member-wise copied after you set the texture of the sprite. Copying the sprite consists of a member-wise copy as well, including copying the address of the texture in the temporary WorldEntity. When the temporary gets destroyed, the texture in it gets destroyed as well, and the address of the texture that the sprite refers to becomes invalid leading to the infamous white square.

Don't copy when you don't need to. Use more references. Or just enable C++11 and go for moves.
Title: Re: Very weird sprite behaviour (white rectangle when attempting to draw sprite)
Post by: Beagle on June 16, 2014, 09:33:25 am
Hey Binary1248!

Thank you so much for the reply :) I'm quite new to C++ but attempting to learn by simply throwing myself out in a project. Thank you, I did not realize that the syntax I used actually caused any copying! So what you are saying is that when you use syntax such as:

WorldEntity rainCloud = WorldEntity(...)

It will actually construct a worldEntity object and then copy it to the "rainCloud" variable due to the assignment operator? So if I instead use:
WorldEntity rainCloud(...)

Then I construct it "in place" for the rainCloud object? Which will not cause any copying.

Thank you for your time!
Title: Re: Very weird sprite behaviour (white rectangle when attempting to draw sprite)
Post by: Nexus on June 16, 2014, 10:32:55 am
Yes -- however, compilers are allowed to optimize this copy away.

Still, there's no need to name the type twice in a declaration.
WorldEntity rainCloud;      // default constructor
WorldEntity rainCloud(...); // parameter constructor

As a general advice, don't store resources (textures, sound buffers, fonts etc.) along with the game objects that use them. This will only cause trouble. Instead, think about storing resources in a centralized place.
Title: Re: Very weird sprite behaviour (white rectangle when attempting to draw sprite)
Post by: Beagle on June 16, 2014, 02:58:33 pm
Thank you, Nexus!  :)

Quote
As a general advice, don't store resources (textures, sound buffers, fonts etc.) along with the game objects that use them. This will only cause trouble. Instead, think about storing resources in a centralized place.

Aha, I see your point. I'll probably end up making some sort of resource manager which sprites can use then :)
Title: Re: Very weird sprite behaviour (white rectangle when attempting to draw sprite)
Post by: Nexus on June 16, 2014, 03:06:15 pm
As a simple start, you could use the ResourceHolder (https://github.com/SFML/SFML-Game-Development-Book/blob/master/02_Resources/Include/Book/) class template we made for the SFML book.
Title: Re: Very weird sprite behaviour (white rectangle when attempting to draw sprite)
Post by: Beagle on June 16, 2014, 05:12:00 pm
Thank you! :)

I actually just purchased the SFML book. Already started to read through it!