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

Author Topic: Sprite manager issue  (Read 3693 times)

0 Members and 1 Guest are viewing this topic.

Grenthal

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Sprite manager issue
« on: February 15, 2016, 10:03:30 pm »
Hello,

I’ve been trying to create resource (sprites) manager, but ended up having problem. Idea was like this: image and texture are being loaded into memory only once (those files might be big), Sprites that are being created should point to those resources instead.

That’s for the vision, below something I’ve got so far:
Hpp class file
#ifndef OBJECTS_H
#define OBJECTS_H

#include <SFML/Graphics.hpp>
#include <memory>

class Objects {
    public:
        Objects();
        virtual ~Objects();
        void draw ( sf::RenderWindow *window );

    protected:
        void create ( void );
        sf::Sprite foo ( void );

    private:
        sf::Image image;
        sf::Texture texture;
        //std::vector < sf::Sprite > sprites;         // First approach -> Without pointers, it's working
        std::vector < sf::Sprite* > sprites;
        //std::vector < std::unique_ptr < sf::Sprite > > sprites; // Third approach - smart ptr's
};

#endif // OBJECTS_H

Cpp Class file:
#include "Objects.hpp"

Objects::Objects() {
    image.loadFromFile ( "image.png" ); // just some red 20x20 px square
    texture.loadFromImage( image );
    create();
}

Objects::~Objects() {
    //dtor
}

// Objects::create
void Objects::create ( void ) {
    sf::Sprite sprite;
    sprite.setTexture( texture );

    // sprites.push_back ( sprite ); // First approach - works, but we have unnecesary textures per sprite resisting in memory?
     sprites.push_back( &sprite ); // Second approach - not working
    // sprites.push_back( std::unique_ptr < sf::Sprite > ( &sprite ) ); // Third approach, not working as well

}// Objects::create

// Objects::draw
void Objects::draw ( sf::RenderWindow *window ) {
    //window->draw ( ( sprites[0] ) ); // First working approach
    window->draw ( ( *sprites[0] ) );  // Second and Third approach - not working
}// Objects::draw

In main.cpp, I’m, just creating class object and invoking draw function:
#include <SFML/Graphics.hpp>
#include "Objects.hpp"

int main() {
    Objects o;

    sf::RenderWindow window(sf::VideoMode( 800, 600 ), "Texture Loading Test!" );
    while ( window.isOpen() ) {
        sf::Event event;
        while ( window.pollEvent( event ) ) {
            if ( event.type == sf::Event::Closed ) {
                window.close();
            }
        }// while

        window.clear();
        o.draw( &window );
        window.display();

    }// while

    return 0;
}

As for Me... it should work  :), but (surprise)… it’s not. I believe we have some kind of memory leek here. I assume, the problem lies here (passing reference to object, pointing to null texture):
void Objects::create ( void ) {
    sf::Sprite sprite;
    sprite.setTexture( texture );
     sprites.push_back( &sprite );


I know I can ignore the pointers approach, and just stick to “first approach” mentioned above, but to my knowledge it will create unnecessary textures, resisting in memory (for example, creating 100 of sprites will create 100 of additional textures) – is my reasoning correct?

I must say, I’ve got no clue how to fix this... :( Any suggestions/hints/leads are most welcomed.

 
Thank You for help in advance.
« Last Edit: February 16, 2016, 09:21:30 am by Grenthal »

ratzlaff

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: Sprite manager issue
« Reply #1 on: February 15, 2016, 11:10:14 pm »
so...

I can see a number of issues with your code, but simply pointing them out will not help you debug your code on the future, so I will instead try to lead you down the path of discovery.

What errors does your debugger tell you when you run your code? Be as specific as possible.

Grenthal

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Re: Sprite manager issue
« Reply #2 on: February 15, 2016, 11:21:29 pm »
Hi ratzlaff,

as it is, program compiles without errors. Running it on the other hand result's in crash (white screen with "the program stopped working" message) plus "Process returned -107374189 (0xC0000005)" message in debug console

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
Re: Sprite manager issue
« Reply #3 on: February 16, 2016, 12:04:39 am »
void Objects::create ( void ) {
    sf::Sprite sprite;
    sprite.setTexture( texture );
    sprites.push_back( &sprite );
}
 

You may need to brush up on how scope works in C++. Your sprite variable is a local variable to the Objects::create() function. That means when the create function is finished, sprite will be destroyed. With that in mind, you can see how the above code is problematic. First the sprite variable is created and a texture is assigned to it, then the address of that variable is pushed onto a vector, and finally the sprite variable is destroyed. That means the address saved in the vector is now pointing to invalid memory. The sprite it used to point to no longer exists. (I didn't look through all of your code, so you may have other issues as well. This is just one I happened to notice when quickly glancing at it.)

As for your question on sprites and textures, the SFML tutorials do a good job of explaining them. In short, textures are big objects that contain your image data. Sprites are small objects that act as a "view" into the texture. Internally the sprite doesn't copy the texture, but instead is just holding a pointer to it. Creating a bunch of sprites won't create a bunch of unnecessary textures. In this case they will all just make use of the same texture.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Sprite manager issue
« Reply #4 on: February 16, 2016, 03:07:37 am »
As Arcade pointed out, that sprite is getting destroyed at the end of the function and the pointer that you store in the vector is therefore no longer valid.
The odd thing, though, is that you have the line that works here. You store the new sprite in the vector of sprites. It doesn't copy the texture, just the sprite.

Basically, a vector of sprites is what you want, not a vector of pointers to sprites (unless maybe you store all of those sprites somewhere else, which might be a bit messy!)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Grenthal

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Re: Sprite manager issue
« Reply #5 on: February 16, 2016, 09:44:29 am »
Internally the sprite doesn't copy the texture, but instead is just holding a pointer to it. Creating a bunch of sprites won't create a bunch of unnecessary textures. In this case they will all just make use of the same texture.

I was certain that line like sprite.setTexture( texture ) creates separate instance of texture objects, resisting in memory.

Because I like to see results on my own eyes (or on output console  :) ), I’ve done something I should from the very beginning – testing. Using only vector of sprites (std::vector < sf::Sprite > sprites in my code) I’ve compared program memory usage for: one and 1000 sprites objects. Results were like:
  • 1 sprite object - 22 412 K
  • 1000 objects - 22 676 K

As I see, difference in memory usage lost is very low.

Arcade, Hapax and ratzlaff - Thank You for You’re help and pointing out error in my logic of thinking  :).

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Sprite manager issue
« Reply #6 on: February 16, 2016, 05:18:14 pm »
You should read the Sprite tutorial and documentation; it's full of useful information  ;)

Quote
When you set the texture of a sprite, all it does internally is store a pointer to the texture instance.
Source: http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem

And, you're welcome. Glad to help  :)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*