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

Author Topic: Textures going out of scope?  (Read 3023 times)

0 Members and 1 Guest are viewing this topic.

intrinsic

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Textures going out of scope?
« on: September 04, 2016, 03:35:57 am »
So I have 2 classes. One is called MapGrid and the other is called MapTile. My MapGrid class' job is to create and store MapTiles in a vector that is part of the MapGrid class. MapGrid class also control the Position of the MapTile sprite. In the MapTile class I have an sf::sprite and an sf::texture. Everytime MapGrid constructs a MapTile, it assigns a .png file to a texture and then that texture is assigned to a sprite and is pushed back onto the vector in MapGrid.

I then try to render the MapGrid with code that looks something like this. (going off memory)
for(auto iter : mapGrid.mapTiles)
window.draw(iter.sprite);

Can someone tell me if this is a scope issue and the texture reference is being destroyed before it can be rendered? Is there any way to work around this other than not storing each sf::texture in the MapTile object?

Thanks!

Mr_Blame

  • Full Member
  • ***
  • Posts: 192
    • View Profile
    • Email
Re: Textures going out of scope?
« Reply #1 on: September 04, 2016, 11:31:03 am »
That code doesn't show any problem, show more!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: Textures going out of scope?
« Reply #2 on: September 04, 2016, 01:35:18 pm »
My guess would be that when pushing into a vector you either do acopy of the class, thus invalidating the sprite's reference. Or that when you insert a new element, all elements will be copied else where.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

intrinsic

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: Textures going out of scope?
« Reply #3 on: September 04, 2016, 08:19:53 pm »
Here's some code.

MapGrid.h
class MapGrid
{
public:
        MapGrid();

        void createTile();
        void adjustTilePosition();
        void populateGrid(MapTile &mapTile);
       
        int tileCount;

        float x_offset;
        float y_offset;

        std::vector<MapTile> mapTiles;
};

MapGrid.cpp
MapGrid::MapGrid()
{
        x_offset = 0.0f;
        y_offset = 0.0f;
        tileCount = 0;
}

void MapGrid::createTile()
{
        MapTile newMapTile(x_offset, y_offset);
        tileCount++;
        adjustTilePosition();
        populateGrid(newMapTile);
}

void MapGrid::adjustTilePosition()
{
        if (tileCount % 10 == 0)
        {
                x_offset = 0;
                y_offset += 50;
        }
        else
        {
                x_offset += 50;
        }
}

void MapGrid::populateGrid(MapTile &mapTile)
{
        mapTiles.push_back(mapTile);
}
 

MapTile.h
class MapTile
{
public:
        MapTile() = default;
        MapTile(float x, float y);

        int id;
        float x;
        float y;

        sf::FloatRect rectangle;
        sf::Texture texture;
        sf::Sprite sprite;
 

MapTile.cpp
MapTile::MapTile(float _x, float _y)
{
        texture.loadFromFile("Zelda Sprites/Blank.png");
        sprite.setTexture(texture);
        sprite.setPosition(_x, _y);
}
 

Perhaps it's going out of scope when createTile() ends?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Textures going out of scope?
« Reply #4 on: September 04, 2016, 08:33:21 pm »
It doesn't go out of scope it's just that when you call push_back it will do a copy of the MapTile, thus moving the instance in memory, thus making the reference of the sprite to the texture invalid, which will then lead to having a white sprite instead of the texture.

Additionally even if the reference was set after the push_back, push_back will at some point reallocate all its members to somewhere else in memory, again making the reference invalid.

It's adviced to use some sort of resource manager (like the one Thor provides) or use a different container than std::vector for textures.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

intrinsic

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: Textures going out of scope?
« Reply #5 on: September 05, 2016, 12:23:34 am »
So I learned something new while writing some test code and googling a few things.
From what I read, you can't have a vector of references, but you can have a vector of pointers.

So i'll just create the MapTile Object and push_back it's address onto the vector.
I'm at work now, so I can't test it, but I can only hope that it will work.

Here's the test code:
int main()
{
   std::vector<int*> vect;
   int x = 1;
   
   vect.push_back(&x);
   
   std::cout << vect[0] << std::endl;
   std::cout << &x << std::endl;
   
   return 0;
}

Also, would a map container's insert be different than a vector's push_back?
I suppose not because you can use an iterator on it...
Thanks!
« Last Edit: September 05, 2016, 12:38:53 am by intrinsic »

intrinsic

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: Textures going out of scope?
« Reply #6 on: September 05, 2016, 05:20:18 am »
Solved the problem, thank you for your help! I would still like to know more about a memory management system, it would be a good way for me to push my knowledge.

Here's the revised version:
MapGrid.h
class MapGrid
{
public:
        MapGrid();

        void createTile();
        void adjustTilePosition();
        void populateGrid(MapTile* mapTile);
       
        int tileCount;

        float x_offset;
        float y_offset;

        std::vector<MapTile*> mapTiles;
}

MapGrid.cpp
MapGrid::MapGrid()
{
        x_offset = 0.0f;
        y_offset = 0.0f;
        tileCount = 0;
}

void MapGrid::createTile()
{
        MapTile* newMapTile = new MapTile(x_offset, y_offset);
        tileCount++;
        adjustTilePosition();
        populateGrid(newMapTile);
}

void MapGrid::adjustTilePosition()
{
        if (tileCount % 10 == 0)
        {
                x_offset = 0;
                y_offset += 50;
        }
        else
        {
                x_offset += 50;
        }
}

void MapGrid::populateGrid(MapTile* mapTile)
{
        mapTiles.push_back(mapTile);
}

I know raw pointers are frowned upon, so I'll use a unique_ptr.
Thanks again.

Edit: unique_ptr was giving me some problems, so I switched to shared_ptr.
« Last Edit: September 05, 2016, 05:52:29 am by intrinsic »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Textures going out of scope?
« Reply #7 on: September 05, 2016, 07:22:44 am »
Quote
Edit: unique_ptr was giving me some problems, so I switched to shared_ptr.
Wrong ;) Use std::move to move unique_ptrs around (you can't copy them).

void MapGrid::createTile()
{
    std::unique_ptr<MapTile> newMapTile(new MapTile(x_offset, y_offset));
    ...
    populateGrid(std::move(newMapTile));
}

void MapGrid::populateGrid(std::unique_ptr<MapTile> mapTile)
{
    mapTiles.push_back(std::move(mapTile));
}
Laurent Gomila - SFML developer

intrinsic

  • Newbie
  • *
  • Posts: 26
    • View Profile
    • Email
Re: Textures going out of scope?
« Reply #8 on: September 05, 2016, 07:43:51 pm »
Passing the unique_ptr to a function was where I was getting errors. something about a deleted function.

I didn't know you had to use std::move.

Very good, thank you!

 

anything