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

Author Topic: sf::Image deprecated? sf::Texture? a problem with rendering  (Read 2851 times)

0 Members and 1 Guest are viewing this topic.

excrulon

  • Newbie
  • *
  • Posts: 12
    • View Profile
sf::Image deprecated? sf::Texture? a problem with rendering
« on: January 01, 2012, 12:19:19 am »
Haven't used sfml in a while, came back to start a new project and am trying to figure stuff out. I used to load something in a sf::Image, and then assign it to a sf::Sprite. Now it seems that sf::Texture has taken its place? Just making sure they're the same thing cause I'm having a problem with getting stuff to draw properly. Looks like corrupted memory somewhere when I render.


And am I doing this right? Loading tiles from a tileset (larger image with all my tiles). I want to make sure the sprite only has that subrect of the image stored in it, or a lot of memory would be taken up.

sprite->SetTexture(*texture);
sprite->SetTextureRect(sf::IntRect(sourceX, sourceY, tileset->GetTileWidth(), tileset->GetTileHeight()));



Might anyone know why this doesn't render properly? If I take out the sprite->SetTextureRect line, the whole tileset renders properly just fine.

Code: [Select]

bool Map::LoadMap(std::string filename)
{
Tmx::Map *map = new Tmx::Map();
map->ParseFile(filename);

if (map->HasError()) {
printf("error code: %d\n", map->GetErrorCode());
printf("error text: %s\n", map->GetErrorText().c_str());

return map->GetErrorCode();
}

for(int i = 0; i < map->GetNumTilesets(); i++)
{
const Tmx::Tileset* tileset = map->GetTileset(i);

sf::Texture* texture = new sf::Texture();


if(!texture->LoadFromFile(tileset->GetImage()->GetSource().c_str()))
{
return false;
}

for(int y = 0; y < (tileset->GetImage()->GetWidth() / tileset->GetTileWidth()); y++)
{
for(int x = 0; x < (tileset->GetImage()->GetHeight() / tileset->GetTileHeight()); x++)
{
int margin = tileset->GetMargin();
int spacing = tileset->GetSpacing();
int sourceX = (margin + (x * tileset->GetTileWidth()) + (inRange(x, 1, (tileset->GetTileWidth() * (tileset->GetImage()->GetWidth() - tileset->GetTileWidth()))) ? (x * spacing) : 0));
int sourceY = (margin + (y * tileset->GetTileHeight()) + (inRange(y, 1, (tileset->GetTileHeight() * (tileset->GetImage()->GetHeight() - tileset->GetTileHeight()))) ? (y * spacing) : 0));
int sourceWidth = sourceX + tileset->GetTileWidth();
int sourceHeight = sourceY + tileset->GetTileHeight();

sf::Sprite* sprite = new sf::Sprite();

sprite->SetTexture(*texture);
sprite->SetTextureRect(sf::IntRect(sourceX, sourceY, tileset->GetTileWidth(), tileset->GetTileHeight()));

sf::Texture t;

unsigned int gid = tileset->GetFirstGid() + x * y;
_tileSprites[gid] = sprite;

std::cout << gid << " ";

}
}
}

for (int i = 0; i < map->GetNumLayers(); ++i)
{
const Tmx::Layer* layer = map->GetLayer(i);

for (int y = 0; y < layer->GetHeight(); y++)
{
for (int x = 0; x < layer->GetWidth(); x++)
{
// Find a tileset for that id.
unsigned int tileGID = layer->GetTileGid(y,x);

if(tileGID != 0)
{
_tiles.push_back(new Tile(tileGID, sf::Vector2f(x * 32, y * 32)));

//printf("Tile position on layer: x=%d, y=%d\n", x * map->GetTileWidth(), y * map->GetTileHeight());
//printf("Tile rect on tileset: x=%d, y=%d, w=%d, h=%d\n", sourceX, sourceY, sourceWidth, sourceHeight);
//printf("Tile Size: w=%d, h=%d\n", tileset->GetTileWidth(), tileset->GetTileHeight());
//printf("Tile Source: %s\n", tileset->GetImage()->GetSource().c_str());
//printf("\n");

}
else
{
// no tileset found. blank tile.
}
}
}
}

delete map;
}


Code: [Select]

while(_renderer->GetRenderWindow()->IsOpened())
{
sf::Event Event;
        while (_renderer->GetRenderWindow()->PollEvent(Event))
        {
            // Close window : exit
            if (Event.Type == sf::Event::Closed)
                _renderer->GetRenderWindow()->Close();
        }

        // Clear screen
        _renderer->GetRenderWindow()->Clear();

for(int i = 0; i < m->_tiles.size(); i++)
{
Tile* t = m->_tiles.at(i);
sf::Sprite* s = m->_tileSprites[t->GetGID()];
if(s)
{
std::cout << s << ": " << t->GetPosition().x << "," << t->GetPosition().y << std::endl;
s->SetPosition(t->GetPosition());
_renderer->GetRenderWindow()->Draw(*s);
}
}

        // Finally, display the rendered frame on screen
        _renderer->GetRenderWindow()->Display();
}



Here's without the subrect line: http://imgbin.org/index.php?page=image&id=6140

Here's with the subrect line: http://imgbin.org/index.php?page=image&id=6141

Thanks.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: sf::Image deprecated? sf::Texture? a problem with render
« Reply #1 on: January 01, 2012, 01:25:16 pm »
Quote from: "excrulon"
Now it seems that sf::Texture has taken its place?
sf::Image has been split into sf::Texture (OpenGL texture) and sf::Image (pixel container unrelated to graphics). See here.

Quote from: "excrulon"
I want to make sure the sprite only has that subrect of the image stored in it, or a lot of memory would be taken up.
You have a wrong understanding of sprites. They only reference the sf::Texture subrect (that is, 4 rect coordinates and a pointer) and don't copy the pixels.

Quote from: "excrulon"
Might anyone know why this doesn't render properly?
Check with the debugger if the arguments passed to the sf::IntRect constructor are correct. Simplify code if necessary.

And why do you use new everywhere? It's unnecessary in your case, it only results in memory leaks. Just use automatic variables (or smart pointers, if you need dynamic allocations).
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

excrulon

  • Newbie
  • *
  • Posts: 12
    • View Profile
sf::Image deprecated? sf::Texture? a problem with rendering
« Reply #2 on: January 01, 2012, 11:05:23 pm »
I solved my map loading problems... finally got it to work. Was an issue with using the wrong gid.

Could you help me understand how else to do it if not using new? I thought that for textures/sprites, I *had* to allocate memory on the heap for it because if I try to pass it to a different method/container, it'd end up being white squares when I draw it unless I do that or make a copy constructor for it or something.

I'm still fuzzy on how all that works.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
sf::Image deprecated? sf::Texture? a problem with rendering
« Reply #3 on: January 01, 2012, 11:13:35 pm »
You first have to decide how wide the scope of a variable is. If it is used during the lifetime of an object, make it a member. If you need it only in a single function (and functions invoked by it), make it a function-local variable. In your case, I think you could use many member variables: Tmx::Map, Tmx::Tileset, sf::Texture, the container of sf::Sprites. Declare the objects (not pointers) in the Map class definition, then you can use them in all member functions.

And if you really need new, for example because you transfer ownership, consider std::unique_ptr. This is a smart pointer that automatically invokes delete if the object goes out of scope. This technique is also called RAII, you find a lot about it on the internet. It is a very important idiom in C++, because it simplifies code while making it more robust and safer.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

excrulon

  • Newbie
  • *
  • Posts: 12
    • View Profile
sf::Image deprecated? sf::Texture? a problem with rendering
« Reply #4 on: January 01, 2012, 11:30:23 pm »
Quote from: "Nexus"
You first have to decide how wide the scope of a variable is. If it is used during the lifetime of an object, make it a member. If you need it only in a single function (and functions invoked by it), make it a function-local variable. In your case, I think you could use many member variables: Tmx::Map, Tmx::Tileset, sf::Texture, the container of sf::Sprites. Declare the objects (not pointers) in the Map class definition, then you can use them in all member functions.

And if you really need new, for example because you transfer ownership, consider std::unique_ptr. This is a smart pointer that automatically invokes delete if the object goes out of scope. This technique is also called RAII, you find a lot about it on the internet. It is a very important idiom in C++, because it simplifies code while making it more robust and safer.


Alright, this actually clears up quite a bit. I think I'm actually going to have some sort of ResourceManager (actually think I'm going to give your thor library a try, and that has a resource manager :D), so in that case, ownership is transferred from the map class to that resource class, right? Thus I'd need new/unique_ptr.

I don't think Map will hold my sf::Sprites... I was thinking the resource manager should hold the sf::Sprites/textures so they're all in one place, and the container of Tiles in the map class will have some reference to the sprite it uses. Sound right?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
sf::Image deprecated? sf::Texture? a problem with rendering
« Reply #5 on: January 01, 2012, 11:42:30 pm »
Quote from: "excrulon"
so in that case, ownership is transferred from the map class to that resource class, right? Thus I'd need new/unique_ptr.
thor::ResourceManager returns thor::ResourcePtr objects which contain the actual resource like sf::Texture. They are smart pointers with shared-ownership semantics, so you don't have to care about memory management. You don't need new, delete or std::unique_ptr. I recommend to read the tutorial ;)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything