SFML community forums

Help => Graphics => Topic started by: Skorpion on October 16, 2015, 04:43:42 pm

Title: Overriding sf::Drawable::draw
Post by: Skorpion on October 16, 2015, 04:43:42 pm
Hi all,

here's my problem: I want to push some objects, that have textures and sprites into a vector from STL. I met some issues and I found on this forum that I have to override draw method. The problem is I just want to keep rest of my code untouched as long as it's possible, the best thing for me is to write same or similar code to original draw method.

Here is what I have:

*.h file:
class Wyswietlacz : public Drawable, public Transformable
{
public:
        void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};
 

*.cpp file:
void Wyswietlacz::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        //here is what I need you to help me with
}
 

some example classes to show you how I want to use it:
class example1 : public Wyswietlacz
{
private:
        Texture texture1;
        Sprite sprite1;
        // other stuff
};

class example2 : public Wyswietlacz
{
private:
        Texture texture2;
        Sprite sprite2;
        // other stuff
};

int main()
{
        vector<example1> EX1;
        vector<example2> EX2;

        // creating and pushing some objects into vectors
        // setting Sprites in right places and all other things needed
        // creating window

        window.draw(EX1[0].sprite1);
        window.draw(EX2[3].sprite2);
        window.draw(EX1[7].sprite1);
        window.draw(EX2[2].sprite2);
        window.draw(EX2[7].sprite2);
        return 0;
}
 

So I need help in what exactly should I write in those method's definition. I want it to work as originally. And, if it is possible, I'd love to see original draw definition (NOT declaration).

Sorry for my english and maybe stupid question :)
Title: Re: Overriding sf::Drawable::draw
Post by: eXpl0it3r on October 16, 2015, 04:50:20 pm
The documentation (http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1Drawable.php#details) is pretty verbose on that topic.

Let us know if you have trouble understanding it. :)
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 16, 2015, 05:52:05 pm
Thank you for fast reply.

Well, yes, I have troubles. I was trying to make something using those documentation, I also googled my answer for 3 days all my free time, so I read many ideas and so. The problem is I tried some of them and no one worked.
And the example you've linked. It looks for me as it is a class like my 'example1' and 'example2' classes, because that class from documentation has it's own Sprite to display. I want it to display Sprites from classes that inherit it.

Again, I'm sorry for my english.
Title: Re: Overriding sf::Drawable::draw
Post by: eXpl0it3r on October 16, 2015, 06:14:31 pm
You shouldn't inherit from a sprite, but your code isn't doing that anyways.
Since you put the sprite into the derived class, you need to override the draw function in the derived class.

Personally I'd suggest to add the sprite to the base class and implement the drawing there.
It's a bad idea to make the Entity hold the texture and the sprite, because whenever the entity is moved in memory the texture would need to be reset for the sprite, plus copying a texture costs quite a bit.
Additionally it's advised to stick to English names, that way you learn a bit more English and other people can easily read your code.

So here's an example that will

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

class Entity : public sf::Drawable, public sf::Transformable
{
public:
    Entity(sf::Texture& tex);
    void draw(sf::RenderTarget& target, sf::RenderStates states) const;

private:
    sf::Sprite m_sprite;
};

Entity::Entity(sf::Texture& tex)
: m_sprite(tex)
{

}

void Entity::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
    states.transform *= getTransform();
    target.draw(sprite, states);
}

class example1 : public Base
{
public:
    example1(sf::Texture& tex)
    : Base(tex)
    {

    }
};

class example2 : public Base
{

public:
    example2(sf::Texture& tex)
    : Base(tex)
    {

    }
};

int main()
{
    std::vector<example1> EX1;
    std::vector<example2> EX2;

    sf::Texture tex;

    // creating and pushing some objects into vectors
    // pass the texture at object creation
    // setting Sprites in right places and all other things needed
    // creating window

    window.draw(EX1[0]);
    window.draw(EX2[3]);
    window.draw(EX1[7]);
    window.draw(EX2[2]);
    window.draw(EX2[7]);
}
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 16, 2015, 06:33:56 pm
Oh, now that's clear to me :) Thank you!

EDIT:

You shouldn't inherit from a sprite, but your code isn't doing that anyways. (...)

I mean inherit from class Wyswietlacz, not from Sprite. Sorry for missleading sentence.

(...) Additionally it's advised to stick to English names, that way you learn a bit more English and other people can easily read your code. (...)

I'm writing it with people who don't know english so it's the only right way working on that project. I usualy don't use english names anyway.
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 22, 2015, 12:49:31 am
Well, I had much to do so I didn't check your code earlier and I'm doing it now. I have this:
//Base.h:
class Base
{
public:
        Texture texture;
        Sprite sprite;
        void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};

//Base.cpp:
void Base::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        states.transform *= getTransform();     // As in your code
        target.draw(sprite, states);
}

//Example1:
class Example1 : public Base   // Basicly I get texture and sprite from 'Base' class, so I can manipulate them
{
        texture.loadFromFile(//file directory);
        sprite.setTexture(texture);
}

//main:
int main()
{
        vector<Example1> EX1;
        Example1 exapmle = new Example;
        EX1.push_back(example);
        window.draw(EX1[0].sprite);     //worked when I stored my classes in table doesn't, when changed to
                                                        //vector
        window.draw(EX1[0]);    //doesn't work either
        return 0;
}
 

All I see is white shape of what that picture was. Maybe the problem is that the file is *.jpg?
Title: Re: Overriding sf::Drawable::draw
Post by: Gambit on October 22, 2015, 04:41:49 am
Your vector of Example1 should be a vector of (unique) pointers to example one. Your vector stores copies but you are trying to push_back a pointer. NEVER use naked new unless you are experienced and you know what you are doing and you clean it up. From your code it looks like you dont know what you are doing with it AND you never clean it up so enjoy memory leaks.
Title: Re: Overriding sf::Drawable::draw
Post by: Hapax on October 22, 2015, 09:02:36 pm
class Example1 doesn't seem to have any public members or methods nor constructor. It doesn't look like a class at all really; it looks more like a function.
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 22, 2015, 11:59:56 pm
Your vector of Example1 should be a vector of (unique) pointers to example one. Your vector stores copies but you are trying to push_back a pointer. NEVER use naked new unless you are experienced and you know what you are doing and you clean it up. From your code it looks like you dont know what you are doing with it AND you never clean it up so enjoy memory leaks.

Well, I'm sorry, I simplified my code in last post, so it had not so much to do with the original one. I also used 'new' while in my code I create whole objects, not only pointers. The 'main' function looks in fact more like this:

class My_Class
{
private:
        vector<Example1> EX1;
public:
        void my_fun1()
        {
                for(int i=0; i<10; i++)
                {
                        Example1 example;
                        example.do_things();    // method that
                        EX1.push_back(example);
                }
        }

        void my_fun2()
        {
                my_fun1();     
               
                //much stuff
       
                window.draw(EX1[0].sprite);     // <- this worked when I stored my classes in table stopped, when      
                                                                // changed to vector
                window.draw(EX1[0]);    // <-this doesn't work either
        }
};
 

Whole code:
(click to show/hide)

class Example1 doesn't seem to have any public members or methods nor constructor. It doesn't look like a class at all really; it looks more like a function.

Are you really intrested in class members that are not involved in this case? All my algorithms of moving things on the screen, getting events etc.? It's about 300 lines of code, when you can see those few that are manipulating on sprites up here and in my previous post.

Sorry for my english, I hope it's not so incomprehensible :)
Title: Re: Overriding sf::Drawable::draw
Post by: Hapax on October 23, 2015, 12:20:51 am
class Example1 doesn't seem to have any public members or methods nor constructor. It doesn't look like a class at all really; it looks more like a function.
Are you really intrested in class members that are not involved in this case? All my algorithms of moving things on the screen, getting events etc.?
No, but I am interested in how the Example1 class in constructed and how its copy constructor is implemented.
I'm not sure why you included code in that class that is not within a method of any sort.

This is a classic example of why a minimal and complete example (http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368) is suggested. It often ends with requiring one in the end anyway,
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 23, 2015, 01:17:58 am
I think I don't understand you a bit. Sorry, I'm not so good in english. But I think I understand that you want to see the whole code, don't you? The other thing is, you suggest that I must have an initial list and an constructor that pushes the texture it gets into the texture the class own. Is it really needed? I do it like this:
class Base : public Drawable, public Transformable
{
public:
        Texture texture;
        Sprite sprite;
        void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};

class Example1 : public Base   // Basicly I get texture and sprite from 'Base' class, so I can manipulate them
{
    texture.loadFromFile(//file directory);
    sprite.setTexture(texture);
}
 

This is exactly how I load and texture and connect it to sprite. Is THIS the problem I have? If I changed it, would it start displaying things properly?

Sorry 4 my english
Title: Re: Overriding sf::Drawable::draw
Post by: Hapax on October 23, 2015, 02:28:34 am
I think my question is, when does the following code (inside the Example1 class) get executed?
    texture.loadFromFile(//file directory);
    sprite.setTexture(texture);
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 23, 2015, 02:42:19 pm
Oh, now I see I made another mistake. It schould be in method 'do_things()', where those two lines and many others are executed, but only those two are related to texture and sprite. I'm really sorry, now I understand what were you talking about. But I think it doesn't change much as in my code it is in a method and still doesn't work :(

EDIT:

I was searching solution whole afternoon, I've changed something and then I found some code that wroks and, in my opinion, is completly IDENTICAL to mine (I mean to those which I wrote today) but mine still displays only white shapes of sprites. Look at this:


My code:
Base.h
class Base : public Drawable, Transformable
{
public:
   void set_up();
   Texture texture;
   Sprite sprite;
private:
   void draw(RenderTarget &target, RenderStates states) const;
};
 
Base.cpp
void Base::set_up()
{
   texture.loadFromFile(/*file directory*/);
   sprite.setTexture(texture);
}

void Base::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        states.transform *= getTransform();
        states.texture = NULL;
        target.draw(sprite, states);
}
 
Example.h
class Example
{
private:
        vector<Base> base_objects;
        void show(RenderWindow & win);
public:
        void do_things();
};
 
Example.cpp
void Example::do_things()
{
        for (int i = 0; i < 10; i++)
        {
                Base m;
                base_objects.push_back(m);
        }
}

void Example::show(RenderWindow & win)
{
        win.clear();
        win.draw(base_objects[0]);
        win.display();
}
 

Code identical to mine:
Base.h https://github.com/sheadovas/Kurs_SFML/blob/master/Lekcja%207/Bullet.h
Base.cpp https://github.com/sheadovas/Kurs_SFML/blob/master/Lekcja%207/Bullet.cpp
Example.h https://github.com/sheadovas/Kurs_SFML/blob/master/Lekcja%207/Engine.h
Example.cpp https://github.com/sheadovas/Kurs_SFML/blob/master/Lekcja%207/Engine.cpp

Can you tell me, where is the difference between those two, because I'm pretty sure I did my best to display those sprites properly. As I already said I see only white shapes of my sprites :(

Sorry for long post, much code and bad english!
Title: Re: Overriding sf::Drawable::draw
Post by: Laurent on October 23, 2015, 09:07:12 pm
Quote
Can you tell me, where is the difference between those two
You're copying the Base instances multiple times, but the Base class doesn't handle copy properly. The other code doesn't copy anything, as far as I can tell.
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 23, 2015, 11:20:30 pm
Can you tell me what exactly should I do (how to write it properly)? I don't understand why is my Base class not handling with all those objects created and pushed into vector correctly. I'm not very skilled programer.

EDIT:

Ok, I've studied virtual methods and found all I knew about them wasn't true so I've learned how to handle them properly, how to override them and make them doing what I want them to do, but I met another problem and maybe it is unable to do it in a way I want to do it, but if it is possible to do, please help me with following:

That's my code now:
Board.h
class Board : public Drawable, Transformable
{
public:
        bool set_up(int nrOfBoard, int level);  // that method sets all sprites and loads
                                                                        // from files coordinates of everything
private:
        Texture texture;        // texture of board
        Sprite background;      // sprite of board
        struct adds            
        {
                Vector2f coordinates;          
                Sprite add;                    
        };
        struct things
        {
                Vector2f coordinates;
                Sprite thing;
        };
        struct oneBoard
        {
                vector<adds> add_s;            
                vector<things> thing_s;
        };
        vector<oneBoard> map_of_all_boards;    

        virtual void draw(RenderTarget &target, RenderStates states) const;
};
 
Board.cpp
void Board::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        states.transform *= getTransform();
        states.texture = NULL;
        target.draw(background);
        for (int i = 0; i < map_of_all_boards[0].add_s.size(); i++)
                target.draw(map_of_all_boards[0].add_s[i].add, states);
        for (int i = 0; i < map_of_all_boards[0].thing_s.size(); i++)
                target.draw(map_of_all_boards[0].thing_s[i].thing, states);
}
 

As you can see I display 'map_of_all_boards[0]', the very first thing in my vector. I would like to change it and display those one which I want by changing:
virtual void draw(RenderTarget &target, RenderStates states) const;
 
in something like this:
virtual void draw(RenderTarget &target, RenderStates states, int board_number) const;
 
but I keep getting error:
error C2664: 'void sf::RenderTarget::draw(const sf::Vertex *,unsigned int,sf::PrimitiveType,const sf::RenderStates &)' : cannot convert argument 1 from 'int' to 'const sf::Drawable &'
Reason: cannot convert from 'int' to 'const sf::Drawable'
while I try to use it as following:
window.draw(Boards, 0);     // Boards is an object of class Board
 
I understand why I get it. I only ask you now to advise me how can I display one element of my vector, how can I pass the information of which element method should pick to my overrided draw?

Any help welcome! Please, I need it fast!

Sorry for my english!
Title: Re: Overriding sf::Drawable::draw
Post by: Laurent on October 24, 2015, 06:36:49 pm
You can't. The only way would be to use another function
Boards.setNextElementToDraw(0);
window.draw(Boards);
... but that's extremely ugly.

You know, you're not forced to inherit from sf::Drawable and use this draw function. You can just avoid sf::Drawable and create the draw function that suits your needs.

Boards.draw(window, 0);
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 24, 2015, 08:49:26 pm
Well, that's what I did. I mean I made a function that tells my object of class Board which element to pick. And yes, I see how ugly it is :)

The second solution you suggested seems good and profesional. Although I'm not sure if I'm able to write it, I'll try it.

Which of them is better (quicker to execute)?

Thank you for reply :)

EDIT:

I've changed my code a bit again so it handles displaying some of my sprites but there are still some that are appear as white shapes. Can I ask once again to tell me, where my mistake is? I tried everything, nothig worked :(

My code now:
Board.h
class Board : public Drawable, Transformable
{
public:
    bool set_up(int nrOfBoard, int level);  // that method sets all sprites and loads
                                    // from files coordinates of everything
    int what_board;
private:
    Texture texture;    // texture of board
    Sprite background;  // sprite of board
   
    struct oneBoard : public Drawable, public Transformable
    {
        vector<Sprite> adds;    
        vector<Sprite> things;
        virtual void draw(RenderTarget &target, RenderStates states) const
                {
                        for (int i = 0; i < adds.size(); i++)
                                target.draw(adds[i], states);
                        for (int i = 0; i < things.size(); i++)
                                target.draw(things[i], states);
                }
    };
    vector<oneBoard> map_of_all_boards;

    virtual void draw(RenderTarget &target, RenderStates states) const;
};
 
Board.cpp
bool Board::set_up(int nrOfBoard, int level)
{
        // some stuff, also determining the number_of_boards

        for (int i = 0; i < number_of_boards; i++)
        {
                Board board;
                oneBoard one;

                //again some stuff, determining amount_of_adds

                for (int i = 0; i < amount_of_adds; i++)
                {
                        Texture tex;
                        Sprite spr;
                        string directory;
                        Vector2f vec;

                        plik >> directory;
                        plik >> vec.x;
                        plik >> vec.y;

                        tex.loadFromFile(directory);
                        spr.setTexture(tex);
                        spr.setPosition(vec);
                        one.adds.push_back(spr);
                }
               
                // and again stuff, detrmining amount_of_things

                for (int i = 0; i < amount_of_things; i++)
                {
                        Texture tex;
                        Sprite spr;
                        string directory;
                        Vector2f vec;

                        plik >> directory;
                        plik >> vec.x;
                        plik >> vec.y;

                        tex.loadFromFile(directory);
                        spr.setTexture(tex);
                        spr.setPosition(vec);
                        one.things.push_back(spr);
                }
               
                // WEPCHNIECIE CALEGO POKOJU DO WEKTORA POKOI
                map_of_all_boards.push_back(one);

                plik.close();
        }
}

void Board::which_board(int brd)
{
        what_board = brd;
}

void Board::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
        states.transform *= getTransform();
        states.texture = NULL;
        target.draw(background);
        target.draw(map_of_all_boards[what_board]);
}
 
I tought that the way I load all that sprites can have an impact on my problem, so I decided to show you more code this time.

So my problem is: my code loads and displays proprely backgroung and loads properly sprites into adds and things. No doubt it does. But on the screen I see my background and white shapes of sprites from vectors adds and things. Any solution? Can you tell me, if part of my code is incorrect, how to fix it?

Sorry for my english :)
Title: Re: Overriding sf::Drawable::draw
Post by: Nexus on October 25, 2015, 04:45:49 pm
for (int i = 0; i < amount_of_things; i++)
        {
            Texture tex;
            Sprite spr;
            string directory;
            Vector2f vec;

            plik >> directory;
            plik >> vec.x;
            plik >> vec.y;

            tex.loadFromFile(directory);
            spr.setTexture(tex);
            spr.setPosition(vec);
            one.things.push_back(spr);
        }
The texture is a local variable. You should really have a deeper look at C++, it's crucial to understand scopes, copy semantics and object ownership.

Furthermore, please avoid using namespace, it's a terrible habit that will lead to problems sooner or later.
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 26, 2015, 06:22:52 pm
(...) The texture is a local variable.(...)

I didn't know that it is needed. I tought that when I once push a texture to sprite using:
Texture tex;
Sprite spr;
spr.setTexture(tex);
 
the texture becomes a part of sprite and that sprite is a thing that is ready to be moved and displayed.

So if I make a structure of a texture and a sprite and then make a vector that structure's type my graphic should be displayed properly?

EDIT:

I tried it like I said. It didn't work.

Do you know what the problem is? I don't know how to do something, I ask you, but you don't give me precision answer. You keep telling me, that something is fundamental, something I should know etc. but I don't know it. If I knew I would do it properly. I don't know and that's why I ask you for help. Could anyone just write how can I make that textures visible for my sprites? I really need your help, when you write a code and comment it I could probably learn something but by keep telling me that I should know something, I search for it again and again and I can't find any answer to my questions. Is here anyone, who could help me, write that code and explain why did it in another way that I did?

Special "thank you in advance" to the person who will.

Sorry for my english.
Title: Re: Overriding sf::Drawable::draw
Post by: Nexus on October 26, 2015, 07:32:19 pm
I tought that when I once push a texture to sprite using:
Texture tex;
Sprite spr;
spr.setTexture(tex);
 
the texture becomes a part of sprite and that sprite is a thing that is ready to be moved and displayed.
Why do you assume that? This behavior is nowhere documented and very uncommon in C++. Even the opposite is documented, namely that the texture object must live as long as it's used.

So if I make a structure of a texture and a sprite
Don't do that. The whole reason why sf::Texture and sf::Sprite are two separate classes is to allow you to store them separately, and have multiple sprites that reference the same texture. This is precisely outlined in the tutorial, please read it carefully.

You should store textures in their own container (preferably not std::vector, because it invalidates pointers). There are also ready-to-use solutions like thor::ResourceHolder (http://www.bromeon.ch/libraries/thor/v2.0/tutorial-resources.html).
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 26, 2015, 10:15:16 pm
Why do you assume that?

Seemed logical to me. It's easier to move or change one object than many. If it doesn't work like that thank you for informating me. Now I know, now I know how to handle such situations in the future.


So if I make a structure of a texture and a sprite
Don't do that. The whole reason why sf::Texture and sf::Sprite are two separate classes is to allow you to store them separately, and have multiple sprites that reference the same texture. This is precisely outlined in the tutorial, please read it carefully.

Well, yes, that's something I didn't think about. That's good point of viev when you use one big texture, like a big tileset and you make multiple sprites from that. But my situation is one texture -> one sprite. This is why I want to store them together. Then I'll have the situation when pairs are in one place.


You should store textures in their own container (preferably not std::vector, because it invalidates pointers). There are also ready-to-use solutions like thor::ResourceHolder (http://www.bromeon.ch/libraries/thor/v2.0/tutorial-resources.html).

Should I use tables? I don't have time to learn a new library. I also tought about std::map. Would it work? Is it I definitly can't store those textures and sprites just like I want to or it is only the most painful way?

Thank you for fast replay and sorry for my english.
Title: Re: Overriding sf::Drawable::draw
Post by: Hapax on October 26, 2015, 10:22:48 pm
I tought that when I once push a texture to sprite[...]the texture becomes a part of sprite and that sprite is a thing that is ready to be moved and displayed.
Why do you assume that?
Seemed logical to me.
This is explain in the initial tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem).

It's easier to move or change one object than many.
This isn't true. Sprites are lightweight and can be copied, created and destroyed in real-time whereas textures are heavyweight and slow to copy, move, create or destroy.
Decoupling them gives a number of advantages. One simple advantage is the ability to use the same texture for multiple sprites.
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 26, 2015, 11:30:28 pm
This is explain in the initial tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem).

I red it 'till the end of "Ok, can I have my Sprite now" and gave up as I didn't found what I was looking for :/ That changes a lot. But now I (unexpectedly) changed my code once again. And now it loads textures directly to the structures. Then, when texture is in the right place and won't be moved from there I set textures to sprites. So I set textures that are in structure in vector in vector to the sprites that are in structure in vector in vector. And still dosen't work :(
Title: Re: Overriding sf::Drawable::draw
Post by: Hapax on October 27, 2015, 03:08:40 pm
This is explain in the initial tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem).
I red it 'till the end of "Ok, can I have my Sprite now" and gave up as I didn't found what I was looking for
You gave up when you got to "The White Square Problem" when because you didn't find the information on the problem that you are having with a white square?

But now I (unexpectedly) changed my code once again. And now it loads textures directly to the structures. Then, when texture is in the right place and won't be moved from there I set textures to sprites. So I set textures that are in structure in vector in vector to the sprites that are in structure in vector in vector. And still dosen't work :(
I don't understand what your code does from this description and what the result of it is.

Try storing your textures globally (not global scope but rather last the lifetime of the application) and pass reference/pointer to them to each class, function, method that uses them.
A simple local-sprite-using-long-term-texture could look something like this:
#include <SFML/Graphics.hpp>
int main()
{
    sf::RenderWindow window; // set up window how you need it
    sf::Texture texture;
    // load and set up texture here
    while (window.isOpen())
    {
        // event loop here

        sf::Sprite localTempSprite;
        localTempSprite.setTexture(texture);

        window.clear();
        window.draw(localTempSprite);
        window.display();
    }
    return EXIT_SUCCESS;
}
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 27, 2015, 05:10:56 pm
This is explain in the initial tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem).
I read it 'till the end of "Ok, can I have my Sprite now" and gave up as I didn't found what I was looking for
You gave up when you got to "The White Square Problem" when because you didn't find the information on the problem that you are having with a white square?

I read the "Ok, can I have my sprite now?"and then gave up, the "The White Square Problem" is under it and I didn't saw it. Other words I read everything 'till end of "Ok, can I have my sprite now?" and closed the tab.

I don't understand how exactly the sprites work. As these objects have a pointer to the texture then why when I store my textures in std::vector, then call sprite.setTexture(textures_in_vector[4]); it doesn't work properly? Is it I can't have a pointer to something that is stored in a vector and the class Sprite has a pointer so the value the pointer is indicating to is unreachable?

Sorry for my english.
Title: Re: Overriding sf::Drawable::draw
Post by: Laurent on October 27, 2015, 06:31:50 pm
When you call sprite.setTexture, the sprite stores the address of (pointer to) the texture object. So if you copy or move the texture around, the address stored in the sprite becomes invalid and all you get is a white square instead of the texture data.

The problem is that objects can easily be copied/moved in C++, even if you don't want them to. When you use a vector, for example, you insert copies into it, not original objects. And when the vector needs to grow, it goes elsewhere in memory and moves all its elements. All these operations invalidate the sprite's textures that were already stored.

So there are usually three solutions to this problem:

1. Use a texture manager, so that texture are managed and stored elsewhere and remain at the same location in memory, regardless of how you use them.

2. If you don't need to share textures (ie. one texture, one sprite) then the class that encapsulates them needs to handle copy/move operations properly. When you copy an instance of a class that holds a sprite and its texture, both are copied, and the sprite copy needs to use the texture copy, not the original texture (as its the case by default). So you need to write the code that does it, in the copy/move constructor and copy/move assignment operators. If you let the compiler generate the copy/move code for you, it will be wrong, the sprites will end up pointing to texture objects that don't exist anymore.

3. Make sure that no copy or move ever happens, by reserving space in your vector or using containers that don't invalidate their elements (std::list). I don't like this approach, I don't consider it a clean solution (or a solution at all) to this design problem.
Title: Re: Overriding sf::Drawable::draw
Post by: Jesper Juhl on October 27, 2015, 07:33:41 pm
Basically, textures need lifetimes that are longer than the sprites that use them.
You need to know what operations on containers (etc) invalidates pointers, references and iterators pointing to textures.
This is essential C++ stuff you need to know for any object, not just textures.
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 27, 2015, 07:44:10 pm
When you call sprite.setTexture, the sprite stores the address of (pointer to) the texture object. So if you copy or move the texture around, the address stored in the sprite becomes invalid and all you get is a white square instead of the texture data.

At fitst I would like to thank you for briliant post with many useful informations for me. Now I see how much do I have to learn still to use C++ fluenltly. Thank you again. Still, as I'm qiuet noob in programing I have a few questions to you but I feel I'm beginning to understand what happens when my code is executed. That seems and for sure is really important.

(...)
So there are usually three solutions to this problem:

1. Use a texture manager, so that texture are managed and stored elsewhere and remain at the same location in memory, regardless of how you use them.

Is that something that is built-in in SFML or should it be a class wrote by myself? If it relays on me are there some other ways better than std::vector, std::list (which you metnioned in point 3 as not the best idea) and reallocing tables?

2. If you don't need to share textures (ie. one texture, one sprite) then the class that encapsulates them needs to handle copy/move operations properly. When you copy an instance of a class that holds a sprite and its texture, both are copied, and the sprite copy needs to use the texture copy, not the original texture (as its the case by default). So you need to write the code that does it, in the copy/move constructor and copy/move assignment operators. If you let the compiler generate the copy/move code for you, it will be wrong, the sprites will end up pointing to texture objects that don't exist anymore.

As my code looks now like this:
class CLASS
{
    struct 1
    {
        Sprite spr;
        Texture tex;
    }
    struct 2
    {
        Sprite spr;
        Texture tex;
    }
    struct 3
    {
        vector<1> one;
        vector<2> two;
    }
    vector<3> map;
}
 
Would it work, when I'm never touching those vectors after reading textures from file, if I matched sprites to the textures after reading last one thing at all into vector? I mean at first I read textures, other stuff, create some other variables and push everything to the vectors. The vectors are moved in memory a few times during that reading and creating variables. But then, do they finaly stand still at one place, that I could call spr.setTexture(tex); when nothing else would be pushed to the vectors or is it still possible, that dusring executing my programm vector would be moved (not intentionaly by me)?

3. Make sure that no copy or move ever happens, by reserving space in your vector or using containers that don't invalidate their elements (std::list). I don't like this approach, I don't consider it a clean solution (or a solution at all) to this design problem.

Well, that was what I liked most when I read all 3 your propositions :( But if you say it is bad...

Thank you for fast replay and I'm sorry for my english.
Title: Re: Overriding sf::Drawable::draw
Post by: Nexus on October 27, 2015, 09:33:59 pm
1. Use a texture manager, so that texture are managed and stored elsewhere and remain at the same location in memory, regardless of how you use them.
Is that something that is built-in in SFML or should it be a class wrote by myself?
SFML doesn't have it, but Thor does, as I mentioned earlier. You said you wouldn't want to use another library, but when you're considering yourself a beginner in these things, it may not be the best idea to write such a class from scratch ;)

If it relays on me are there some other ways better than std::vector, std::list (which you metnioned in point 3 as not the best idea) and reallocing tables?
You could use an associative container like std::map, and refer to the texture using some identifier (the key in the map). That's also a part of what thor::ResourceHolder does, it just simplifies many things on top of that.

But then, do they finaly stand still at one place, that I could call spr.setTexture(tex); when nothing else would be pushed to the vectors or is it still possible, that dusring executing my programm vector would be moved moved (not intentionaly by me)?
If you don't touch the vectors themselves, it's only possible if the object of the surrounding class (which contains the vector) is moved/copied.

And don't apologize for your English in every post, it's not that bad 8)
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 27, 2015, 10:49:55 pm
1. Use a texture manager, so that texture are managed and stored elsewhere and remain at the same location in memory, regardless of how you use them.
Is that something that is built-in in SFML or should it be a class wrote by myself?
SFML doesn't have it, but Thor does, as I mentioned earlier. You said you wouldn't want to use another library, but when you're considering yourself a beginner in these things, it may not be the best idea to write such a class from scratch ;)

If it relays on me are there some other ways better than std::vector, std::list (which you metnioned in point 3 as not the best idea) and reallocing tables?
You could use an associative container like std::map, and refer to the texture using some identifier (the key in the map). That's also a part of what thor::ResourceHolder does, it just simplifies many things on top of that.

The problem is more complex, I don't write it alone ;) But I'll try to convince our engraver to make one tileset for level, that would be more efective and simplify many things :) (Now I'm so smart, when you told me all that things :) )

But then, do they finaly stand still at one place, that I could call spr.setTexture(tex); when nothing else would be pushed to the vectors or is it still possible, that dusring executing my programm vector would be moved moved (not intentionaly by me)?
If you don't touch the vectors themselves, it's only possible if the object of the surrounding class (which contains the vector) is moved/copied.

Strange. I did it like I said, first made everything up, then called spr.setTexture(); and from then on never touched any vector or whole object. Still didn't worked.

And don't apologize for your English in every post, it's not that bad 8)

"it's not that bad" = still not perfect = still ther's something to apologize for, because it makes reading harder and I'm not an easy interlocutor; I write long posts and ask stupid questions ;)
Title: Re: Overriding sf::Drawable::draw
Post by: Nexus on October 27, 2015, 11:03:24 pm
Strange. I did it like I said, first made everything up, then called spr.setTexture(); and from then on never touched any vector or whole object. Still didn't worked.
You could use a debugger to check whether the addresses of the sf::Texture objects change, and if they do, where this happens.

You could also declare a vector of non-copyable but movable objects (e.g. std::vector<std::unique_ptr<int>>) in the same place, and see whether a compiler error resulting from a copy attempt occurs.
Title: Re: Overriding sf::Drawable::draw
Post by: Skorpion on October 28, 2015, 09:12:22 pm
Now I'm like John Snow; I know nothing.

I was tired of keeping trying to make that code work. As I wrote yesterday, I've made some changes and compiled the project. Once again I saw white squares and as I had a hard day I haven't time to write code. Today I entered the forum, saw your post and tought "Great idea, let's see how it works!". So I, making no changes from yesterday, debugged code and started a "new game". Everything was set up in it's place, displayed fullly properly. I have no idea why it didn't worked yesterday  :o

All in all thank you all for your time you spended here reading my sh*tty code and trying to help me. Now I know more about SFML and object oriented programing in C++. Thakns to you I started reading some more materials about both and I find it really helpful so far.

The solution to the problem for all that could look for this in the future:
1. Ensure that you don't move your Texture objects in memory after calling sprite.setTexture(texture);.
2. If you do you can do two things:
    a) change the code to don't move the Texture
    b) change the code to call sprite.setTexture(texture); always right after moving the Texture

In my opinion the case is closed, if I had some problems with it in the future I'll probably be able to handle with it on my own (thanks to you ofc ;)).

You guys are awesome! Thank you once again for what you did for me, for your patience and nerves :)

Best regards,
Skorpion