SFML community forums

Help => General => Topic started by: N_K on September 12, 2012, 05:00:59 pm

Title: Empty texture for vertex array quads
Post by: N_K on September 12, 2012, 05:00:59 pm
Hello all,

Another noob problem here. The vertex array based tile system uses this method to define texture coorinates for each tile:
map[current + 0].texCoords = sf::Vector2f((tx + 0) * size, (ty + 0) * size);
map[current + 1].texCoords = sf::Vector2f((tx + 0) * size, (ty + 1) * size);
map[current + 2].texCoords = sf::Vector2f((tx + 1) * size, (ty + 1) * size);
map[current + 3].texCoords = sf::Vector2f((tx + 1) * size, (ty + 0) * size);

(int tx and int ty are the x and y coordinates of the desired part of the texture, int size is the size of the tile).

The vertex array itself is defined like this:
sf::VertexArray map(sf::Quads, layer_width * layer_height * 4);

Now the problem with this is that I can't define an empty texture. If both tx and ty are 0, the first image of the tileset will be drawn. When I modified the texture coordinate routine to this:
map[current + 0].texCoords = sf::Vector2f(0, 0);
map[current + 1].texCoords = sf::Vector2f(0, 0);
map[current + 2].texCoords = sf::Vector2f(0, 0);
map[current + 3].texCoords = sf::Vector2f(0, 0);
the empty tiles were filled with the first pixel of the tileset image, resulting in a solid color.

How can I set up the texture coordinates to render the tile untextured/completely transparent/invisible?

EDIT: Forgot to mention that when the tile map is loaded from a tile, and the app starts processing the tile IDs, the normal coordinate setup routine is used (the first code snippet) if the tile ID is larger than zero, and if it's zero or less, the empty coordinate routine should be used to texture the current tile.
Title: Re: Empty texture for vertex array quads
Post by: Laurent on September 12, 2012, 05:07:40 pm
Untextured: don't use a texture when you draw the vertex array.
Transparent: don't draw it :P
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 12, 2012, 05:13:41 pm
Iterate through vertex array and if you find first of 4 vertices of a tile that has the '0 ID' copy 4 last vertices into these 4 and then shorten the vertex array.
Quote
Transparent: don't draw it
would sf::Color with alpha 0 do something or does texturing ignore it?
Title: Re: Empty texture for vertex array quads
Post by: N_K on September 12, 2012, 05:42:52 pm
Thanks for your replies.

Untextured: don't use a texture when you draw the vertex array.

The problem with this is that the map processing/array setup takes place during startup, way before rendering.

So basically, the texture is assigned to the vertex array when it's rendered:
window.draw(map, &tileset);
so I can only manipulate the texture coordinates during map procecssing, but not the texture itself.

Transparent: don't draw it :P

Yeah, this would be the most logical thing to do, but if I don't draw the empty tiles, the tile array will be messed up, and everything will be out of place, I'm afraid.

Iterate through vertex array and if you find first of 4 vertices of a tile that has the '0 ID' copy 4 last vertices into these 4 and then shorten the vertex array.

Won't this slow down the map processing with larger maps? Anyway, I'll try to implement this and see how it goes.
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 12, 2012, 05:46:59 pm
Quote
Won't this slow down the map processing with larger maps? Anyway, I'll try to implement this and see how it goes.
Not really? It seems better to remove anything that isn't supposed to be there once rather than render invisible garbage 60 times per second.
Actually, how about starting with empty array and only appending vertices to array if tile number is positive?
Title: Re: Empty texture for vertex array quads
Post by: Laurent on September 12, 2012, 06:09:59 pm
Assigning a color with alpha = 0 to vertices will also hide the tile, yes.

But you can't disable texturing just by changing vertices attributes.

But what are you trying to achieve? Maybe there are other (more global) solutions to your problems.
Title: Re: Empty texture for vertex array quads
Post by: N_K on September 12, 2012, 06:20:03 pm
Actually, how about starting with empty array and only appending vertices to array if tile number is positive?

Do you know any in-depth tutorial about vertex arrays in SFML? It's a good idea, and indeed much cleaner/better than drawing untextured quads, but the code I've posted is the only one I could find in this forum.

But what are you trying to achieve? Maybe there are other (more global) solutions to your problems.

Let's assume we have a map with two layers. The map is an array of integers, each integer representing the N-th tile of the assigned tileset.

Layer one:
1 1 1 1
1 1 1 1
1 1 1 1

This layer is the ground layer, filled with the first texture of the tileset (grass texture in my case).

Layer two:
0 0 0 0
0 2 0 0
0 0 0 2

This is the first layer above the ground layer. Tiles represented with zero are empty, tiles with ID of 2 are the second image from the tileset (flowers scattered around the map, for example).

Whan I'm trying to achieve is to either skip drawing or make invisible the tiles represented with zero, since they are empty spaces.
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 12, 2012, 06:34:09 pm
Quote
Do you know any in-depth tutorial about vertex arrays in SFML? It's a good idea, and indeed much cleaner/better than drawing untextured quads, but the code I've posted is the only one I could find in this forum.
I didn't see a single tutorial about that.
Make a class that holds tile ids mapped to texture coords and have a function FillQuad(int tilex,int tiley,int tileid,sf::VertexArray& garray)?
Title: Re: Empty texture for vertex array quads
Post by: Laurent on September 12, 2012, 06:35:13 pm
And why do you create vertices for these empty tiles? Can the contents of the layers change?
Title: Re: Empty texture for vertex array quads
Post by: N_K on September 12, 2012, 10:11:11 pm
And why do you create vertices for these empty tiles? Can the contents of the layers change?

I create the vertices for the empty tiles because at the moment, I need them to keep the tiles in the correct array.

The coordinates for the quads are being calculated by adding the dimensions of a tile to the previous one. So, assuming the tile size is 32(x32), it goes like 0, 32, 64, 96 ..., and without creating a quad for the empty tiles, I don't know how to position the ones that are not empty.

(Okay, this probably doesn't make any sense, but I can't explain it better...  :-[ )
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 12, 2012, 10:22:53 pm
Make a class that stores info about what id is what texturepos and with a function that takes , x,y, vertex array and tile id.
A bit like that loop but I'm doing with strings as ids and 2d vector of vertex arrays.
        for (int iy=0;iy<map_y;++iy)
        {//1
                for (int ix=0;ix<map_x;++ix)
                {//4
                        std::getline(gstream,tile_name);
                        m_tileset.AddVertices(ix,iy,my_chunks[ix/chunksize][iy/chunksize],tile_name);
                }//4
        }//1
Title: Re: Empty texture for vertex array quads
Post by: Laurent on September 12, 2012, 10:27:53 pm
Quote
The coordinates for the quads are being calculated by adding the dimensions of a tile to the previous one. So, assuming the tile size is 32(x32), it goes like 0, 32, 64, 96 ..., and without creating a quad for the empty tiles, I don't know how to position the ones that are not empty.
Seriously? ???

If a tile is located in the fourth column of the layer, its X position is 4 * 32. You don't need to create the previous tile to calculate that.
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 12, 2012, 10:35:52 pm
Quote
...it goes like 0, 32, 64,96 ...
Seriously? ???

If a tile is located in the fourth column of the layer, its X position is 4 * 32.
I see.  ;D
Title: Re: Empty texture for vertex array quads
Post by: Laurent on September 12, 2012, 10:41:26 pm
Okay, 3 because counting starts at 0... :P
Title: Re: Empty texture for vertex array quads
Post by: N_K on September 13, 2012, 01:59:52 am
Accidentally, I discovered that this works:

sf::VertexArray layer2(sf::Quads, layer_width * layer_height * 4);

for(int x2=0; x2 < layer_width; ++x2)
{
        for(int y2=0; y2 < layer_height; ++y2)
        {
                int current2 = (x2 + y2 * layer_width) * 4;

                if(spriteLayer->GetTileId(x2, y2) != 0)
                {
                        layer2[current2 + 0].position = sf::Vector2f((x2 + 0) * size, (y2 + 0) * size);
                        layer2[current2 + 1].position = sf::Vector2f((x2 + 0) * size, (y2 + 1) * size);
                        layer2[current2 + 2].position = sf::Vector2f((x2 + 1) * size, (y2 + 1) * size);
                        layer2[current2 + 3].position = sf::Vector2f((x2 + 1) * size, (y2 + 0) * size);

                        int currentTile2 = spriteLayer->GetTileId(x2, y2);
                        int tx2 = currentTile2 % horizontalTiles;
                        int ty2 = currentTile2 / horizontalTiles;

                        layer2[current2 + 0].texCoords = sf::Vector2f((tx2 + 0) * size, (ty2 + 0) * size);
                        layer2[current2 + 1].texCoords = sf::Vector2f((tx2 + 0) * size, (ty2 + 1) * size);
                        layer2[current2 + 2].texCoords = sf::Vector2f((tx2 + 1) * size, (ty2 + 1) * size);
                        layer2[current2 + 3].texCoords = sf::Vector2f((tx2 + 1) * size, (ty2 + 0) * size);
                }
        }
}

layer_width and layer_height are the width and height of the tile layer (measured in tile units)

spriteLayer is the map layer that is being processed

GetTileId(int x, int y) is a function of tmx-parser (http://code.google.com/p/tmx-parser/), which returns the ID of the tile at the given XY coordinate

So, this basically does what I wanted to do, if the tile ID is zero, it doesn't create a quad for it. But I can't believe it was so easy, is it safe to use at all?

And is there a built-in way to render the quads as wireframe, or draw some kind of bouding box around them to see how the layer looks like on the polygon level?
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 13, 2012, 02:07:31 am
Quote
Accidentally, I discovered that this works:
[sarcasm]Nooo waaay...using if statements in programming? Srsly?[/sarcasm]
Quote
But I can't believe it was so easy, is it safe to use at all?
Why wouldn't it be? But don't declare your array as
sf::VertexArray layer2(sf::Quads, layer_width * layer_height * 4);
you're having too much quads if something gets skipped, start with 0 size and use append in the if block.
Quote
And is there a built-in way to render the quads as wireframe, or draw some kind of bouding box around them to see how the layer looks like on the polygon level?
Not really. You can take pointer to first vertex and use overloaded draw with lines or line strip but one will skip every second line and other will connect quads together.
Title: Re: Empty texture for vertex array quads
Post by: N_K on September 13, 2012, 02:14:09 am
[sarcasm]Nooo waaay...using if statements in programming? Srsly?[/sarcasm]

Well I had no idea where to start and what to do, so I did this, and if I remember correctly, this is the first time that something worked on the first try. And I'm surprised nobody mentioned this (well, Laurent suggested to not to draw the empty quads at all, but I had no idea this could be done this easily).  :P

Why wouldn't it be? But don't declare your array as
sf::VertexArray layer2(sf::Quads, layer_width * layer_height * 4);
you're having too much quads if something gets skipped, start with 0 size and use append in the if block

See? You just basically told me it's not entirely safe. :)
And thanks for the suggestion, but what do you mean by "having too much quads if something gets skipped"?
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 13, 2012, 02:32:52 am
Quote
And thanks for the suggestion, but what do you mean by "having too much quads if something gets skipped"?
Seriously? ???
You're leaving the vertices of tiles that have 0 id in the array but untouched. If you replaced your operators [] with appends then it'd be ok.
Title: Re: Empty texture for vertex array quads
Post by: N_K on September 13, 2012, 02:39:28 am
You're leaving the vertices of tiles that have 0 id in the array but untouched. If you replaced your operators [] with appends then it'd be ok.

So I have to do something with these parts:
layer2[current2 + 0].position = sf::Vector2f((x2 + 0) * size, (y2 + 0) * size);

If I understand correctly, instead of setting the position/texture coordinates controlled by the
int current2 = (x2 + y2 * layer_width) * 4;
array, I need to "append" them (to something).

I still don't get it, but it could be just me (being sleepy at 2:30 AM), I'll take a look at it again later.
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 13, 2012, 02:45:09 am
sf::VertexArray layer2(sf::Quads);

for(int x2=0; x2 < layer_width; ++x2)
{
        for(int y2=0; y2 < layer_height; ++y2)
        {
             

                if(spriteLayer->GetTileId(x2, y2) != 0)
                {
                                                int currentTile2 = spriteLayer->GetTileId(x2, y2);
                        int tx2 = currentTile2 % horizontalTiles;
                        int ty2 = currentTile2 / horizontalTiles;
                                               
                                                layer2.append(sf::Vertex(sf::Vector2f((x2 + 0) * size, (y2 + 0) * size)
                                                ,sf::Vector2f((tx2 + 0) * size, (ty2 + 0) * size)));
                                               
                                                layer2.append(sf::Vertex(sf::Vector2f((x2 + 0) * size, (y2 + 1) * size)
                                                ,sf::Vector2f((tx2 + 0) * size, (ty2 + 1) * size)));
                                               
                                                layer2.append(sf::Vertex(sf::Vector2f((x2 + 1) * size, (y2 + 1) * size)
                                                ,sf::Vector2f((tx2 + 1) * size, (ty2 + 1) * size)));
                                               
                                                layer2.append(sf::Vertex(sf::Vector2f((x2 + 1) * size, (y2 + 0) * size)
                                                ,sf::Vector2f((tx2 + 1) * size, (ty2 + 0) * size)));
                }
        }
}
Title: Re: Empty texture for vertex array quads
Post by: N_K on September 13, 2012, 02:51:17 am
Oh well, somehow I missed this part of the documentation... Thank you.

EDIT:
Works when the array is still defined as:
sf::VertexArray layer2(sf::Quads, layer_width * layer_height * 4);
but without any change in memory/CPU usage.

When the array is defined as:
sf::VertexArray layer2(sf::Quads);
it crashes with heap corruption.
Title: Re: Empty texture for vertex array quads
Post by: FRex on September 13, 2012, 03:11:31 am
Step thru with debugger to see when it crashes? How do you know it's heap corruption.
Append ads to end so the first definition is leaving a lot of garbage vertices in. Vertex array is glorified vector so all that is happening are stl vector push_backs, almost no way they'd corrupt the heap.
Title: Re: Empty texture for vertex array quads
Post by: N_K on September 13, 2012, 03:56:05 am
EDIT: It works, I was just completely stupid, and not realizing that the texture coordinates has been already set up in:

layer2.append(sf::Vertex(sf::Vector2f((x2 + 0) * size, (y2 + 0) * size), sf::Vector2f((tx2 + 0) * size, (ty2 + 0) * size)));

So basically the first sf::Vector2f defines the position of the vertex, and the second defines the texture coordinates.

And what it does now is to create an empty vertex array at startup, and append a quad if the tile ID is larger than zero, if I understand correctly. And what got me confused was that I used to believe that all the vertices in the array needs to be connected, not realizing that just because they are in the same array, they can be positioned individually (similar to the way like the polygons are stored in a 3D mesh file, they can be scattered around without being connected, while still belonging to the same model (array)).