SFML community forums

Help => General => Topic started by: Mr_Bunkers on May 07, 2013, 03:28:33 pm

Title: When creating a tile map, sprites do not always texture properly
Post by: Mr_Bunkers on May 07, 2013, 03:28:33 pm
So, as the title says, I'm making a tile map loader (using the Tiled format).

(http://i.imgur.com/LMASeZnh.png)

(http://i.imgur.com/rXWqgWqh.png)

The images show 2 instances of the program loading the map. One, the tiles are fine. Another, the tiles are blacked out, but only on one layer. I first thought that this was a problem with the vector in which I store my tiles, but its not. The hex values are pointers to the sf::Textures that I have loaded in my texture manager. You're wondering, well if it works in one instance, then why are you here? The images are the same program. I was stress testing my program; loading the map over and over and noticed this problem. Sometimes it works, sometimes it doesn't. I'm baffled. The textures are fine, cuz the memory is the same. The vector should be reserved correctly, but I'm not sure. The tile id's are the same every single time I load. I'm trusting that SFML is fine, unless I discovered some issue.

Here is my map parsing code. I use RapidXML to parse the .tmx file.

Quote
      bool MapManager::parseData(const std::string& src)
      {
         try
         {
            rapidxml::xml_node<> *node_root = m_document->first_node("map"), *node_layer = node_root->first_node("layer"),
               *node_data = 0;

            std::string encoding = "", compression = "";

            for(; node_layer; node_layer = node_layer->next_sibling("layer"))
            {
               std::deque<unsigned> split;
               node_data = node_layer->first_node("data");

               if(node_data->first_attribute("encoding"))
               {
                  encoding = node_data->first_attribute("encoding")->value();
                  if(encoding == "csv")
                  {
                     split = m_parse_csv(node_data->value());
                  }
                  else if(encoding == "base64")
                  {
                     if(node_data->first_attribute("compression"))
                     {
                        if((compression = node_data->first_attribute("compression")->value()) == "zlib")
                        {
                           split = m_parse_zb64(node_data->value());
                        }
                        else
                        {
                           split = m_parse_b64(node_data->value());
                        }
                     }
                  }
                  else
                  {
                     return false;
                  }

                  for(int y = 0; y < m_height; y++)
                  {
                     for(int x = 0; x < m_width; x++)
                     {
                        int id = split.front();
                        be::Object::TileSet* t = m_decide_tileset(id);

                        if(id != 0 && t && !split.empty())
                        {
                           sf::Vector2i pos(x, y), size(t->width, t->height);
                           sf::IntRect text_split = m_decide_texture_split(id, t);

                           m_tile_map.push_back(new be::Object::Tile(id, pos, size, text_split, t->texture));
                        }

                        split.pop_front();
                     }
                  }
               }
            }
         }
         catch(const rapidxml::parse_error &e)
         {
            return false;
         }

         return true;
      }

Here is what I use to load textures.

Quote
      sf::Texture* TextureManager::getTexture(const std::string& src)
      {
         for(auto i = m_textures.begin(); i != m_textures.end(); i++)
         {
            if(i->first == src)
            {
               std::cout << i->second << std::endl;
               return i->second;
            }
         }

         sf::Texture* t = new sf::Texture;

         if(t->loadFromFile(src))
         {
            std::cout << "Loading a new texture: " << src << std::endl;
            m_textures[src] = t;
            return t;
         }
         else
         {
            delete t;
            return 0;
         }
      }

I won't post more code unless needed to save everyone a headache. I got an itch that this is where the issue lies.

Tiled documentation: https://github.com/bjorn/tiled/wiki/TMX-Map-Format (https://github.com/bjorn/tiled/wiki/TMX-Map-Format)
Title: AW: When creating a tile map, sprites do not always texture properly
Post by: eXpl0it3r on May 07, 2013, 05:47:53 pm
We won't dig in your code and debug it for you, so at best you should do it on your own. ;)
If manage it to narrow down to a minimal and complete example, we might look into it. ;)
Title: Re: AW: When creating a tile map, sprites do not always texture properly
Post by: Mr_Bunkers on May 07, 2013, 07:36:35 pm
We won't dig in your code and debug it for you, so at best you should do it on your own. ;)
If manage it to narrow down to a minimal and complete example, we might look into it. ;)

Understood. I'm looking into it.
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Mr_Bunkers on May 08, 2013, 12:59:58 am
Found the problem. It is of no importance to SFML, and I would request that this thread be removed. :)
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Roose Bolton of the Dreadfort on May 08, 2013, 11:00:47 am
What was the problem in the end?
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Mr_Bunkers on May 09, 2013, 12:12:07 am
What was the problem in the end?

Loading TMX requires that you provide information for the tiles, provided in the tilesets in the .tmx file. I was loading the tileset information into a priority queue, which held a custom Object::TileSet class, and had overrode the < operator to compare gid's. However, I put pointers of the Object::TileSet into priority queue, so it was comparing the memory of the pointers, not the gid.

To solve the problem, I just stored references to the Object::TileSet's in the queue and continued on my merry way.

Like I said, not a SFML problem, and probably not helpful to anybody in the future, so this thread can be deleted.

This is what the TileSet looks like now, I changed the operator override from

bool operator<(const TileSet &b)

to

bool operator<(const TileSet &b) const

        namespace Object
        {
                struct TileSet
                {
                        // ctor, dtor...

                        virtual ~TileSet(){}

                        bool operator<(const TileSet &b) const
                        {
                                return this->gid > b.gid;
                        }

                        sf::Texture* texture;
                        int gid, spacing, height, width;
                };
        }
 

Then I changed the priority queue from

std::priority_queue<Object::TileSet*> tileset_queue;

to

std::priority_queue<Object::TileSet> tileset_queue;
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Nexus on May 09, 2013, 11:08:05 am
In general, declare binary operators as non-member functions. This treats the two operands symmetrically and allows implicit conversions of both.
bool operator< (const TileSet& lhs, const TileSet& rhs)
{
    return lhs.gid < rhs.gid;
}

If the operator< is not meaningful in other contexts, you can also define a predicate functor:
struct CompareTileSet
{
    bool operator() (const TileSet& lhs, const TileSet& rhs)
    {
        return lhs.gid < rhs.gid;
    }
};

std::priority_queue<TileSet, std::vector<TileSet>, CompareTileSet> queue;
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Mr_Bunkers on May 09, 2013, 07:57:08 pm
In general, declare binary operators as non-member functions. This treats the two operands symmetrically and allows implicit conversions of both.
bool operator< (const TileSet& lhs, const TileSet& rhs)
{
    return lhs.gid < rhs.gid;
}

If the operator< is not meaningful in other contexts, you can also define a predicate functor:
struct CompareTileSet
{
    bool operator() (const TileSet& lhs, const TileSet& rhs)
    {
        return lhs.gid < rhs.gid;
    }
};

std::priority_queue<TileSet, std::vector<TileSet>, CompareTileSet> queue;

Why does overriding the () operator work?
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Nexus on May 09, 2013, 08:01:05 pm
Why does overriding the () operator work?
Because the C++ standard allows it ;)

Overriding the function call operator is the basic idea of functors (function objects). This allows very powerful constructs like std::function in C++11.
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Mr_Bunkers on May 09, 2013, 08:02:54 pm
Why does overriding the () operator work?
Because the C++ standard allows it ;)

Overriding the function call operator is the basic idea of functors (function objects). This allows very powerful constructs like std::function in C++11.

No, I mean, what does the () operator do in the std::priority_queue? I'm learning something new here.
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Nexus on May 09, 2013, 08:13:13 pm
The same as operator<, it is used to compare different values. The priority queue must reorder the elements according to their priority values. See here (http://www.cplusplus.com/reference/queue/priority_queue) for example.

By the way, there is no need for a full quote if the text is just above :)
Title: Re: When creating a tile map, sprites do not always texture properly
Post by: Mr_Bunkers on May 09, 2013, 08:32:27 pm
The same as operator<, it is used to compare different values. The priority queue must reorder the elements according to their priority values. See here (http://www.cplusplus.com/reference/queue/priority_queue) for example.

By the way, there is no need for a full quote if the text is just above :)

Understood. Thanks. ::)