code of the Ninja();

// in search of swift, efficient, and invisible code

2012-12-31

Creating Old-School Palette Effects Using Pixel (Fragment) Shaders

Please note that the following only applies to Game Maker 8.0 using this shader extension. However, the principle can be applied to anything else that uses shaders.

Okay, time to get started. Let's say you have an image. It's made of pixels - obviously - and each pixel is a colour. Where things get interesting is how you choose to describe that colour, i.e what bits or bytes you use to signify it.

The simplest way is to use 1 bit per pixel - on or off. But that only gives you a monochrome image. What about colour? A very common way is to use 24 bits per pixel - one byte each for the red, green, and blue channels. This gives you 256 levels of intensity for each channel, allowing over 16 million vibrant colours, and indeed 24-bit colour is sometimes referred to as "true" colour.

The drawback to methods such as 24-bit true colour is that they use a large amount of memory. So, a common practice in old-school games was to use indexed colour: a palette contains the actual colours, while the pixels in an image are only described by a single value - the index (i.e. the address in the palette) of the colour to be used for that pixel. (Read more at Wikipedia.)

The indexing method, in addition to saving memory, has another big advantage. If you change a colour in the palette, any and all pixels that reference the index of that colour will change along with it. An otherwise static image can come to life in this way - lights can flash, water can flow, stars can twinkle - all without true animation of any kind. (See a beautiful example of this in action.)

As memory and CPU power improved, these little tricks largely fell by the wayside. Software such as Game Maker doesn't provide any functionality for palettes by default, which is bad news for anyone who wants to emulate the effects of old-school games.

Fortunately, LSnK has come to the rescue with his shader extension for Game Maker. (Sadly it is only compatible with version 8.0 of GM, but 8.0 is still a sufficient tool for making great games.) It allows one to use shaders in Game Maker with little more effort than setting the fog colour.

Shaders are quite a complicated subject, but for the purposes of palette effects (and this article) we will only be considering pixel shaders (also referred to as fragment shaders). You can think of a pixel shader as a tiny program that runs for each pixel that is drawn. If you activate a pixel shader and then use a drawing function, each pixel to be drawn is input to the shader, the shader runs, manipulating the pixel in some way, and finally the pixel is output to the screen.

There are a great many effects pixel shaders can achieve. A common example is drawing an image in greyscale: the red, green, and blue channels are used to determine the perceived brightness of the colour, and then that brightness value is output to all three channels, making the corresponding shade of grey.

Now, I'm not going to explain every little thing about how to use the shader extension or make a shader - there's plenty of instruction on how to do these things on its own page. Here I'm only concerned with explaining the idea behind emulating palette effects with a pixel shader. I'll also provide an example GMK at the bottom of the article to get you started.

So let's move on. First, we need a palette (any image that's one pixel in height with colours in horizontal sequence will do). Let's use Sonic's palette from Sonic 1 as an example.

We'll also need an image of Sonic.

The above image clearly won't do. It's already in colour; what we need is an image of Sonic where each pixel is an index in a palette. I've made a tool called Palettiser that lets you do exactly that. It'll analyse an image and replace all the pixels with shades of red - shades of red whose intensity corresponds to an index in a palette, for a max of 256 colours. Having completed that process one ends up with an image of Sonic that looks like this (since there are only about 16 colours in the palette, the shades of red are all very dark, almost black):

Now, both the palette image and the funky-looking converted image can be imported into Game Maker as a sprite or background resources.

The next step is to create a custom pixel shader. A shader that, when active, will perform the following operation on every pixel that is drawn:

  1. Get the amount of red in the pixel.
  2. Use that value as a horizontal coordinate, finding the colour at that position in the palette image.
  3. Draw a pixel of that colour instead.

By drawing the converted image with the shader active, the original Sonic image can then be recreated correctly. But this time it will palettised - any change to the palette image colours will be reflected in the Sonic image immediately.

But how to change the palette image colours? It's a background or sprite, right? Well, what's cool is that a shader can also use surfaces. If you make your palette a surface, you can draw anything to it, and in so doing animate the palette.

But talk is cheap. It's much cooler to see this happen and play around with it in real time. To that end, here is an example GMK. (Be sure and install the shader extension first, of course!)

Have fun!