## Tile Map Geometry

Today I implemented tile map geometry.

Basically the way it works is I have a class TileFloorData that stores a 2D array of Tile’s. For now, each struct Tile contains a height. In the future, Tile will also have (a) texture ID(s). For rendering, TiledFloor is an renderable Entity that generates geometry based on its TileFloorData.

To start with, I just did the geometry (no textures yet). The geometry is designed such that the TileFloorData can be drawn with a single draw call – so it’s a single list of vertex positions, a single list of vertex colors, and a single list of indices. The geometry is also designed to work with a texture atlas. So each tile has 5 faces (we ignore the bottom face) and 4 verts per face (so 20 verts per tile). Vertices are not shared between faces – because we want independent texture coordinates for texture atlas lookup. Each tile face also has 6 indices per face (so 30 indices per tile).

For GLES2 core profile, glDrawElements() can only use GL_UNSIGNED_BYTE or GL_UNSIGNED_SHORT (ie GL_UNSIGNED_INT is not allowed), so that’s a max of 65536 vertices. With 20 verts per tile, that’s a max of 3276 tiles, which is only 57×57 tiles. If we want more tiles than that, then we can break it up into multiple draw calls (such as four draw calls for 114×114 tiles). Or we could use glDrawArrays() in which case we’d need 30 verts per tile (instead of 20).

Just for fun… A single vertex has 3 coordinates per position and 3 values (red, green, blue) for color. Each of these values is a GLfloat. So a single vertex has (sizeof(GLfloat) is 4 bytes) * (3 + 3 is 6) = 24 bytes. Each tile has 20 verts, so that’s 480 bytes per tile. 57×57 tiles * 480 bytes per tile would be 1,559,520 bytes or a little under 1.5 MB. Using GLshort, indices are only 2 bytes each, so 2 bytes * 30 indices per tile = 60 bytes per tile. 57×57 tiles * 60 bytes per tile would be 194,940 bytes. For both vertices + indices, 57*57*(480+60) = 1,754,460 bytes or a little over 1.67 MB.

Here’s some screen shots – 10×10 stair-step (incrementing) heights, 10×10 random heights, 50×50 random heights. For the 50×50 example, I had to increase my zFar plane from 100 to 200. The fourth screen shot shows that with 58×58 we lost some tiles. This is because on GLushort overflow it wraps around, so any index value of 65536 or greater will wrap-around and cause us to redraw tiles we already drew (ie 65536 becomes 0, 65537 becomes 1, etc).

The final screen shot shows Z-fighting. This happens because adjacent tiles share bottom verts and their top verts are on the same plane, so we have overlapping triangles (tile faces) on the same plane. However, we only see this from the bottom side of the tile map. In the final game, these won’t be visible to the player, so they will all be back face culled. The top side doesn’t have this problem, because you only see the tallest part of tile sides (everything else gets drawn over).

mepem37 :: Oct.03.2015 :: cross-platform SDL demos, Graphics & GPU :: No Comments »