It took me about 3 hours to get the first version of my shader up and running starting from the "Pixelate" sample that came with SFML: I was very happy!

When I tried it on my girlfriend's machine (an ATI™ 5850) it did not work at all :(

It took me about 2 days of work, and the usage of some tools like the AMD Gpu Shader Analyser1before I finally managed to get my shader working at all on ATI.

The lesson I learnt there is that the NVidia drivers and cards are extremely tolerant, accept non valid shaders, non matching parenthesis, invalid type conversions, etc... whatever crap you write will probably work.The ATI drivers on the other hand seems to be a lot more strict, and will refuse to compile your shaders if they are wrong.2The bottom line is: The current shader runs perfectly on all the tested NVidia and Intel cards, has some small accuracy problems on ATI, and does not work at all on S3 Chrome.

The files are available for download in a compressed archive at the end of the article, including a pre-built binary for Windows® system4.

Most of the work is done in tilemap.frag, the setup is done in main.cpp and some minor work is performed by tilemap.vert.

The vertex shader was not absolutely necessary, but more recent versions of OpenGL don't propagate some of the shader parameters automatically anymore, so you need to have a vertex shader just to do that. Go figure.

I commented the two most important files as much as I could, but let's detail a bit.

Of course, there's a little bit of set-up done up-front which makes all that possible:

// This is where the magic happens://// We tell the sf::Sprite engine it will be using the tilemap texture which is// 256 by 256 pixels, but then we will tell it to use texture coordinates that// would a 4096 by 4096 pixel texture use.//// The trick is that we want our pixel shader to draw the actual final texture// as if it had always be present in memory. This makes it possible to use the// tilemap very easy, no need to do complex tricks to clip it or rescale it:// Just pretend it has the size you wanted it to be in first place :)sf::Sprite tileMapSprite;tileMapSprite.setTexture(tileMapTexture);tileMapSprite.setTextureRect(sf::IntRect(0,0,256*16,256*16));tileMapSprite.setOrigin(128*16,128*16);

I guess the comment says it all.

The tileMapSprite.setOrigin is only there to make the tilemap rotate around its center, which is less stomach turning inducing that having it turn around a corner :)

If you download the archive you will get the fully commented code, so I will just briefly explain what it does.

When the graphic card renders the sprite, it will for each visible pixel on the screen call the shader and asks it to compute this one particular pixel value.

The only input we get are:

tilemap - the texture that contains our 256x256 pixels tilemap

tileGraphics - the 32x32 texture atlas containing four textures

gl_TexCoord[0] - the texture coordinates of the pixel being drawn

The only thing we return is:

gl_FragColor - the color of the pixel as computed by the shader

So basically the trick is to do what I explained in the previous article: From the given texture coordinates deduce both the index of the texture to use and the texture coordinates of the pixel to return

The only difficulty really is that you need to clearly layout the size of all your textures and primitives to be able to convert from one system to another.

gl_TexCoord contains a value in the 0 to 1.0 range which maps to our 4096x40966 pixel 'virtual' tilemap texture

And since tileGraphics is a 32 by 32 pixel texture containing 16 by 16 pixels images, we have to use fractional coordinates to access the various images in the atlas.

Hopefully the comments in the code will be enough for you to understand the details, in case of problem just use the comment box!

Here is the complete archive, containing the executable, source code and textures:

Tilemap.zip (105 kilobytes)If you have any comment about this series of tutorial, if you don't like them, if you have suggestions, if you want me to write more of these, if you find the style terrible, or too simple, or too difficult, please tell me :)

This is going to be the last article for the year 2012, I'm now going to take a break and work on my game!

1. The tool works even if you have a non ATI card. You can download it on AMD's website.↩

2. I would not be surprised if that was some dark magic added by NVidia to make crappy games run on their cards, a bit like earlier web browsers that accepted totally broken web pages.↩

3. The original capture ran at 60 frames per second with the framerate limiter enabled. Without limits I had about 1100 frames per seconds reported by FRAPS in 1920x1200 resolution.↩

4. I've not setup sfml on my Linux machine, and I don't have a Mac, sorry for that.↩

5. I admit I've been thinking about doing some bad title pun based on Fifty Shades of Grey, but like Gangnam Style and Nyan Cat it's a bit over-done these days.↩

6. The tilemap contains 256 by 256 tiles, each tile is 16 by 16 pixels, that's a 4096 by 4096 texture.↩