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

Author Topic: White square issue after accesing resource from std::map  (Read 2984 times)

0 Members and 1 Guest are viewing this topic.

Grenthal

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
White square issue after accesing resource from std::map
« on: October 05, 2016, 04:55:59 pm »
Hello Community,

I’m facing "strange" (in my opinion) issue – infamous white square problem, in which I can’t find its source.
I’ m well aware of official tutorial (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem) – used it couple of times, but this time I just don’t see what might be causing an error.
Also, I’ve searched forum for similar issue but as it seems each case is different and uique in its own way…

Describing my issue in couple words: I’m trying to create title manager – class that’s storing titles inside std::map container, so I could access them when necessary. The issue is, when I’m creating “plain” Title object – it’s drawn without problem. Once I store it inside container and try to access it, all I’m receiving is white square.

I’m a little bit stuck at this moment, so any suggestion would be very appreciated.

Minimal code provided below:

#include <SFML/Graphics.hpp>

enum class LocalTitleType {
    Grass
};

class LocalTitle {
    public:
        static const int WIDTH = 64;
        static const int HEIGHT = 64;

        void setTexture( sf::Texture &texture ) {
            title.setTexture( &texture );
        }

        sf::RectangleShape getTitle( void ) {
            return title;
        }

        void create( void ) {
            title.setSize( sf::Vector2f( WIDTH, HEIGHT ) );
        }

    private:
        sf::RectangleShape title;
};

class LocalTitleManager {
    public:
        void create( void ) {
            createGrassTitle();
        }

        LocalTitle& getTitleRef( LocalTitleType titleType ) {
            return titles.at( titleType );
        }

    private:
        std::map< LocalTitleType, LocalTitle > titles;

        void createGrassTitle( void ) {
            sf::Texture texture;
            texture.loadFromFile("media/textures/titles.png"); //one texture for simplicity

            LocalTitle title;
            title.create();
            title.setTexture( texture );

            titles[LocalTitleType::Grass] = title;
        }
};

int main() {
    LocalTitleManager manager;
    manager.create();

    sf::RenderWindow window( sf::VideoMode( 200, 200 ), "Title Manager Test" );
    while ( window.isOpen() ) {
        sf::Event event;
        while ( window.pollEvent( event ) ) {
            if ( event.type == sf::Event::Closed )
                window.close();
        }// while

        window.clear();

        LocalTitle title = manager.getTitleRef( LocalTitleType::Grass );
        window.draw( title.getTitle() ); /** here's the issue */

        /** white square problem is not existent using below:
        sf::Texture texture;
        texture.loadFromFile("media/textures/titles.png"); //one texture for simplicity
        LocalTitle localTitle;
        localTitle.create();
        localTitle.setTexture( texture );
        window.draw( localTitle.getTitle() );
        */


        window.display();
    }// while

    return EXIT_SUCCESS;
}


I know that issue lies inside “LocalTitleManager” Class, in this method precisely:
void createGrassTitle( void ) {
   sf::Texture texture;
   texture.loadFromFile("media/textures/titles.png"); //one texture for simplicity

   LocalTitle title;
   title.create();
   title.setTexture( texture );

   titles[LocalTitleType::Grass] = title;
}

...but according to my knowledge, once I’ve created desired texture, attach it to LocalTitle class and finally store it in Container, it should work.

What am I missing?

Thank You for You’re help in advance

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: White square issue after accesing resource from std::map
« Reply #1 on: October 05, 2016, 06:54:44 pm »
Look at the lifetime of the sf::Texture you create in LocalTitleManager::createGrassTitle(). It only exists within that function, right? (ie: its destructor is called once execution leaves that function)

Grenthal

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Re: White square issue after accesing resource from std::map
« Reply #2 on: October 05, 2016, 08:04:05 pm »
Thank You for Your response Dabbertorres.
I’ve made some research and refactored LocalTitleManager to a working state as presented below:
class LocalTitleManager {
    public:
        void create( void ) {
            loadTextures();
            createGrassTitle();
        }

        void loadTextures( void ) {
            sf::Texture texture;
            texture.loadFromFile("title.bmp");
            textures[LocalTitleType::Grass] = texture;
        }

        LocalTitle& getTitleRef( LocalTitleType titleType ) {
            return titles.at( titleType );
        }

    private:
        std::map< LocalTitleType, LocalTitle > titles;
        std::map< LocalTitleType, sf::Texture > textures;

        void createGrassTitle( void ) {
            LocalTitle title;
            title.create();
            title.setTexture( textures.at(LocalTitleType::Grass) );

            titles[LocalTitleType::Grass] = title;
        }
};

Question now it’s... why does it work?. Its the same logic as before, yet in this example sf::Texture is not going out of scope.

What am I missing?

void loadTextures( void ) {
            sf::Texture texture; // the same logic as before, yet it works
            texture.loadFromFile("title.bmp");
            textures[LocalTitleType::Grass] = texture;
}

AncientGrief

  • Newbie
  • *
  • Posts: 32
    • Yahoo Instant Messenger - what?
    • View Profile
Re: White square issue after accesing resource from std::map
« Reply #3 on: October 05, 2016, 09:19:09 pm »
In your first example

        void createGrassTitle( void ) {
            sf::Texture texture;
            texture.loadFromFile("media/textures/titles.png"); //one texture for simplicity

            LocalTitle title;
            title.create();
            title.setTexture( texture ); //YOU GIVE THE FUNCTION A REFERENCE, but texture will be destroyed when this function returns

            titles[LocalTitleType::Grass] = title;
        } //texture gets destroyed here! Now there is "no more texture in memory"...
 

Your texture is just available inside the function. After leaving the scope, it get's destroyed.

In your 2nd example:
void loadTextures( void ) {
            sf::Texture texture;
            texture.loadFromFile("title.bmp");
            textures[LocalTitleType::Grass] = texture; //YOUR texture will live on beyond the scope.
        }

//......
    private:
        std::map< LocalTitleType, LocalTitle > titles;
        std::map< LocalTitleType, sf::Texture > textures;
 

        void createGrassTitle( void ) {
            LocalTitle title;
            title.create();
            title.setTexture( textures.at(LocalTitleType::Grass) ); //Here you access the stored texture and use it. And as long as your map exists, it will be able to use it.

            titles[LocalTitleType::Grass] = title;
        }
 

You store the texture in your map. The map lives as long as the instance of your LocalTitleManager class. If you destroy your manager before drawing, you will have the same problem again.
I grew up with C++...but then I met C#...got lazy...time to turn back to my one and only love!
My system:
Wintendo 10 with Intel i7 4770k
Palit GeForce GTX 980
16 GB RAM

Grenthal

  • Newbie
  • *
  • Posts: 20
    • View Profile
    • Email
Re: White square issue after accesing resource from std::map
« Reply #4 on: October 05, 2016, 09:55:34 pm »
Finally it’s starting to make sense  :). Thanks for a clear and straight answer.