Tiled Minimap

I’m working on roguelike, and we’re hopefully about 3 weeks from releasing it. The programmer I took over for wrote a minimap implementation that I’ve discovered is horribly inefficient; framerate drops from a smooth 30 to a shaky 17 in the worst case when it’s active.

The algorithm in use now basically does this:

for( map.width ){
for( map.height ){

glLineWidth(LINE_WIDTH);

if(currentTile.explored) glColor4ub(currentTile.minimapR, currentTile.minimapG, currentTile.minimapB, currentTile.minimapA);
else glColor4ub(0, 0, 0, 255);

drawLine( CGPointMake(x, y), CGPointMake(x, y+LINE_WIDTH));

}
}

which gets called every frame. Even when only drawing a 30x30 subset of the tilemap, this is killing the framerate.

It was suggested to me that I create one texture for the entire map in advance, and just draw that static texture, which makes sense. However, that approach might not fully meet the requirements I’ve got to implement and it would take me a day or so learning how to do, so I want to make sure that’s what I should be doing.

The snag is that the map needs to reveal itself as the player explores it, so building one texture upfront for the entire map would require some way to mask parts of it. Can that be done somehow? The current implementation was probably designed with this feature in mind.

The alternative would be remaking the texture each time more of the map has been revealed, which is almost constantly. I have to assume that would be a lot worse than our current algorithm. Is that a reasonable assumption to make?

Doing glTexSubImage2D for a small part of a texture + render a textured frame with it once per frame is almost certainly more efficient than drawing a bunch of tiny lines each frame.

What are typical values for map.width / map.height / LINE_WIDTH ?

width and height are 51, though I have tried 31 with similar performance issues. A LINE_WIDTH of 2 would be good enough.

glTexSubImage2D seems like it would do what I need in terms of making a texture for the entire map once, and then displaying the subset of it, so thank you for showing me that.

I’m still uncertain if I would be able to mask an arbitrary subsection of such a texture, though, or if it is possible to do so using this approach.

the idea was more to do a glTexImage2D with full black (or whatever color is your fog of war).
Then each time a portion of the map becomes explored, glTexSubImage2D the actual map data on this tiny portion.

Instead of masking less and less, you actually reveal more and more.

Ah, I think I understand now, but just to clarify, this would eventually result a composition of several dozen ( or possibly hundreds of ) subImages of the completed map texture?

Edit: I suppose the number of subImages would depend on how big an area I want to reveal at once; revealing the area immediately around the player would result in a smaller number of larger subImages, versus revealing the area immediately around the player, which would result in many more and smaller subImages.

Read the docs :
http://www.opengl.org/sdk/docs/man/xhtml/glTexSubImage2D.xml
“glTexSubImage2D redefines a contiguous subregion of an existing two-dimensional texture image.
The texels referenced by data replace the portion of the existing texture array”

So for the GPU, it is always seen as a single texture.
Only the updates are small and have somewhat costly fixed cost (compared to the little data actually updated), but doing it only once per frame really is not a problem.

What is the width/height you need for the texture ?

I probably won’t need the full texture to be more than 512x512, and even that’s extreme.

My confusion with glTexSubImage2D must have been in that it only specifies a rectangular area of the texture. I’ll need some way of making any conceivable composition of rectangular subsections of the texture be unmasked. For example the player might explore an L-shaped or U-shaped area of the map, which it doesn’t sound like subImage would support. I may still be misunderstanding how the function works, though, it’s been a bit hard for me to visualize from the documentation.

You can probably get away with updating one (or more) 1x1 texel “rectangle” each frame.
At 60Hz, player would need to be able to go trough the whole map width in more than 8 seconds to need more than 1 texel update per frame :slight_smile: