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

Author Topic: Vector of class not storing separate Textures  (Read 3112 times)

0 Members and 1 Guest are viewing this topic.

rogeriodec

  • Newbie
  • *
  • Posts: 42
    • View Profile
Vector of class not storing separate Textures
« on: June 02, 2018, 03:29:34 am »
I'm creating a car simulation using SFML.

As a matter of organization and logic, I created a single class "car", which also inherits sf::RectangleShape, and within this class there are other SFML objects, among them a Texture and a method to setup it.

I want to have multiple cars, so I created a vector of class "car".

In this example, I left only 2 cars with the images:


Here is an extract from the logic I'm using (I did a test program to make it easier to understand):

   
#include <iostream>
    #include <vector>
    #include <SFML/Graphics.hpp>
    #define debug(x) std::cout << #x << "=" << x << std::endl;
   
    using namespace std;
   
    class car : public sf::RectangleShape {
    public:
        string s;
        sf::Texture tex;
        sf::Sprite img;
   
        void imgInit(string imgFile) {
                tex.loadFromFile(imgFile);
                img.setTexture(tex);
                s = imgFile;
        }
    };
    int main()
    {
        vector<car> vecRet;
        car objRet;
   
        objRet.imgInit("car-red.png");
        objRet.setSize(sf::Vector2f(150, 70));
        objRet.setFillColor(sf::Color::Yellow);
        vecRet.push_back(objRet);
   
        objRet.imgInit("car-black.png");
        objRet.setPosition(sf::Vector2f(300, 300));
        objRet.img.setPosition(objRet.getPosition());
        vecRet.push_back(objRet);
   
        debug(vecRet[0].s);
        debug(vecRet[1].s);
            debug(vecRet[0].img.getTexture());
            debug(vecRet[1].img.getTexture());
   
        sf::RenderWindow window(sf::VideoMode(500,500), "Window", sf::Style::Close);
        window.setFramerateLimit(120);
   
        while (window.isOpen())
        {
                for (sf::Event event; window.pollEvent(event);) {
                        if (event.type == sf::Event::Closed)
                                window.close();
                }
   
                window.clear();
                window.draw(vecRet[0]);
                window.draw(vecRet[1]);
                window.draw(vecRet[0].img);
                window.draw(vecRet[1].img);
                window.display();
        }
   
        return EXIT_SUCCESS;
    }
 



There are two problems I can not solve:

1) Even doing `push_back` of the two cars, only the last image prevails.
Apparently, push_back refers to a single RAM address for the image.

Then the result looks like this:



That is, the second image (car-black.png) is probably overlapping the address of the first image.

The curious thing is that this only happens with the Texture class. In the example, the program `debug` a string within the class and in this case there is no overlap:

    vecRet[0].s=car-red.png
    vecRet[1].s=car-black.png

However the Texture objects within the class vector are pointing to the same memory address:

Code: [Select]
vecRet[0].img.getTexture()=000000C57A5FF250
vecRet[1].img.getTexture()=000000C57A5FF250

How to solve this?

 2) The second problem is that, for each `vecRet.push_back(objRet)`, the following errors appear in the console:

   
Code: [Select]
An internal OpenGL call failed in Texture.cpp(98).
    Expression:
       glFlush()
    Error description:
       GL_INVALID_OPERATION
       The specified operation is not allowed in the current state.

What i[1]: s this?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Vector of class not storing separate Textures
« Reply #1 on: June 02, 2018, 10:11:13 am »
You shouldn't manage your texture inside the entity class, as the texture is a heavy resource and when you copy the entity (e.g. when pushing it back into a vector), you change the location of the texture in memory, causing the reference of the rectangle shape to break. Plus the vector dynamically reallocates after a certain size and thus you again change the texture's memory location.

It's a better design to use something like a resource holder and have the texture managed independently from the entity.

Additionally, you may want to use composition over inheritance and not derive from revtangle shape, but have the rectangle shape be a member of your entity class. Usually the entity interface doesn't really align with ALL the functions a rectangle shape exposes.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

rogeriodec

  • Newbie
  • *
  • Posts: 42
    • View Profile
Re: Vector of class not storing separate Textures
« Reply #2 on: June 02, 2018, 02:58:23 pm »
Now I realize that vector push_back does not work for Texture, since push_back does not save the whole image of the Texture object, but only the object pointer.
So I can not reuse the same Texture object twice, because the second image will overlap the first and as two push_backs point to the same memory address:

        sf::Texture tex;
        vector<sf::Sprite> vecImg;
        sf::Sprite img;

        tex.loadFromFile("car-red.png");
        img.setTexture(tex);
        vecImg.push_back(img);
        tex.loadFromFile("car-black.png");
        img.setPosition(200, 200);
        vecImg.push_back(img);

        debug(vecImg[0].getTexture());
        debug(vecImg[1].getTexture());

Code: [Select]
vecImg[0].getTexture()=00000066C8D4F428
vecImg[1].getTexture()=00000066C8D4F428