Fast Tile Map Rendering in Slick

Hi guys, what’s the fastest way to render a large amount of tiles onto the screen using Slick?
In my game I have huge worlds which, when zoomed out, means that there are hundreds of tiles on screen at any given time.

At first, I drew every tile at its location on every frame, and my frame rate dropped to 1 - 2 fps.
So I tried drawing only the tiles that are on the screen, and the game would only drop to 30fps when viewed on the furthest zoom level.

Lastly, I tried drawing all the tiles onto a buffer image, then drawing that buffer image to the screen every frame, however, the world size is too big to incorporate into a single image.
So I tried creating a buffer image for just the tiles on the screen, and I’d get a wait time of about 2 seconds at the beginning, but then everything ran smoothly.
What use will this be though, if I have to update the buffer image every time the player scrolls and more of the world is revealed? I was hoping to create just one big image of the world that I can move on the x/y axis when the player moves.

In the future, I plan to include a line of sight method to only draw the tiles in the player’s line of sight, so that will probably fix my problem, but does anyone have any tips on drawing many things on the screen at once?

Thanks for your help!

A simple way to give you faster culling is to divide the world into sections (maybe 8x8 to 32x32), checking the visibility of the sections and drawing the whole section with a single command as a display list or using glDrawArrays or something. This should give you good enough performance.

If you want to use more advanced OpenGL 3 commands, you can use a 2D texture array for the tiles and a shader to do a dependent texture lookup per fragment to place tiles. This allows you to draw a single gigantic quad over the whole map (or at least a very very large section of the map) and the tiles will be placed automatically. Only 4 vertices to process, cull and clip for the GPU and only a single draw command (or at least very few) for the CPU.

Thanks for the tips. Unfortunately, I am unfamiliar with OpenGL, which is why I am using Slick2D to draw my images. I guess I better learn how to do it the proper way if I want to optimize the performance of my game though.

I have almost no knowledge at all about Slick2D. However, the problem is the same no matter what library you use to render tiles: When zooming out, you will need to draw lots of small tiles, maybe even pixel-sized. This is very tough on both the CPU and GPU, as the CPU has to instruct the GPU to draw all the small tiles, and GPU has to render lots of very small quads. I don’t know exactly how Slick draws tiles under the hood, but maybe you could just wrap the drawing in a display list and call it later, but that might break functionality…

Anyway, if you’re ready to experiment with display lists:

//When starting the game (run once)

int displayList = GL11.glGenLists(1); //Save this int so you can access it later
GL11.glNewList(displayList, GL11.GL_COMPILE);
//Draw the tiles using Slick
GL11.glEndList();


//When rendering, instead of drawing things with SLick

GL11.glCallList(displayList);


Slick renders each single tiny images/sprite/tile as one quad, texture binds it, draw a quad, unbinds it - and stuff
way to slow for tilemaps
so you pretty much have to use something like vertex arrays, vbos, display lists - whatever

I guess there is also a slick.tiled.TiledMap in Slick, which I have never used - but its for use with a map created with the “TilED” map editor

so even rendering spritesheet.renderInUse or something, its still the same deal

you gotta write it yourself in Slick pretty much - this is why I often said Slick is nice, but if you wanna do bigger stuff, it will also frustrate you

fortunately my guys know their OpenGL and after a couple of weeks or trying different methods we are now using the VBO extension which works with GL1.2 I believe

again, you pretty much need to do some OpenGL at least
its really not all that difficult, or much lines of code - since you can still use everything else Slick is offering, and only change your TileMap
and you will get a speed boost by at least a factor of 10.

so looking at the source again, even if you would use Tilemap created by Slick, it still uses SpriteSheet.renderInUse, which uses Image.drawEmbedded

basically its

once:

Color.white.bind();
texture.bind();
GL.glBegin(SGL.GL_QUADS);

then for every tile

GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY);
GL.glVertex3f(x,y, 0.0f);
GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY + newTextureHeight);
GL.glVertex3f(x,(y + myheight), 0.0f);
GL.glTexCoord2f(newTextureOffsetX + newTextureWidth, newTextureOffsetY + newTextureHeight);
GL.glVertex3f((x + mywidth),(y + myheight), 0.0f);
GL.glTexCoord2f(newTextureOffsetX + newTextureWidth, newTextureOffsetY);
GL.glVertex3f((x + mywidth),y, 0.0f);

and then just finally

GL.glEnd();

So I guess its a little bit faster here because it’s not a single new quad and binding every time - but still slow

However, if you wanna do something without writing OpenGL code, which in itself is not that good an idea, to do directly, while using Slick,
try using SpriteSheet for your TileMap
benchmark before and after to see effectiveness

wrong button, dbl post, delete please D=

Depends which renderer you’re using. If you switch to the VertexArrayRenderer it packs them all into a vertex array and spits that. There isn’t a VBO renderer at the moment but doesn’t sound like masses of work.

The benefit being of course that at the renderer level it optimizes for the vertex array across everything you draw not just your tiled map.

Cheers,

Kev

The point is that the data is static. The only thing that varies is which tiles to draw.

And nice triple post, Cero! xD

Wow, thanks for the helpful responses guys.

I found this example of using OpenGL code with Slick. Is that a good idea, or is there a better way?

How many tiles are you rendering, I’m surprised you’re hitting a bottle neck.

Cheers,

Kev

Several hundred, take a look. I do want to implement a lighting system similar to Terraria’s, where only the outer-most tiles are rendered, with fading alpha values as you go deeper underground because there really is no point rendering all those tiles unless the player digs that far down. That will certainly ease the bottleneck of all the tiles needing to be rendered.

Use data representation that can get any field equally fast, independant of size. An array, and the ArrayList does this, for instance. A LinkedList will not be a good choice, because it will take longer to get an object from it, the bigger it gets.

Say you have room for 8 tiles on the screen. On each repaint, you just get those 8 tiles, from your data structure and paint them. You will use the same amount of CPU on getting those 8 tiles, no matter how big your map it, because you’re using arrays.
Now, the only thing that will scale when your map grows bigger, is the time used to initialize it and that won’t even slow you down too much, if you’re initializing your array with the amount of indexes needed.

EDIT: Didn’t read thread carefully. My bad. I will leave this here, since it is relevant if people are searching for it.

especially using lighting with direct OpenGL commands in Slick is a horror - so just a heads up, if you experience wierd color effects and stuff, its all because of Slick internal stuff

As usual everyone ignores my perfect OpenGL 3 solution. It even eliminates bleeding between tiles when using mipmaps… ._.

Anyway, using quad-strips for tiles is pretty much impossible, because the edges between tiles don’t share information. The edges may have the exact same position, but they don’t have coherent texture coordinates. You have to draw them one at a time. It’s a similar problem to batching the sides of a 3D cube together and getting correct normals. The corners of the cube needs to have 3 different normals, and there is no (realistic) way of attaining this when the corner vertices are shared. You have the same problem for your tile grid. The tile corner vertices needs to have 4 texture coordinates, one for each tile they are part of, which again is not possible. You just have to use GL_QUADS, or my epic OpenGL 3.0 idea. It would even be possible to implement a lighting system very easily by reading the tile texture to determine if a tile lets light through or not, which would allow you to have several hundred lights on entry level OpenGL 3 hardware. I have working code right here for such a lighting system.