Palette Shifting


This is part of a series on how this game was implemented technically, as part of the Game Jam it was developed for. It is recommended to read them roughly in-order as later blog entries may refer to earlier ones.

Technical:

  1. State Machine
  2. Pathfinding/Movement
  3. Isometric Rendering
  4. API
  5. Control Sources
  6. AI
  7. Networking
  8. Fog of War
  9. Bit Packing
  10. Palette Shifting

Other:

----

Palette Shifting

Adjusting the colour of images based on the map chosen is used to change the way the theme of the map plays.

The achieve this, when each image is loaded, it's passed through a conversion function. The function reads the source RGB of each pixel and compares it to the pixels in the palette.

To work out which colour the RGB value should become, this formula was used from the related stackoverflow question.

const colourDistance = (r1,g1,b1,rgb)=>{
    const drp2 = Math.pow(r1 - rgb.r, 2);
    const dgp2 = Math.pow(g1 - rgb.g, 2);
    const dbp2 = Math.pow(b1 - rgb.b, 2);
    const t = (r1 + rgb.r) / 2;
    return Math.sqrt(2 * drp2 + 4 * dgp2 + 3 * dbp2 + t * (drp2 - dbp2) / 256);
};     

To speed up this process, each input colour is stored in a lookup table, and it's first read from that to save computing the distance for every single pixel.

Once the image is loaded, each palette is cached in-memory and can be swapped out on the fly. 

 There are a number of bugs in this implementation, firstly, it's disabled on mobile because it can take too much memory to save multiple copies of all the game's images. Secondly, the palette choice is global and isn't always saved. If playing a multiplayer game, the palette on the remote player's game could be different from the local game. There's several other places where the palette might get out of sync.

These are purely visual quirks, so  these were left in.

To make the game colourblind friendly, there should be an option to disable this feature. But given the tight time constraints for development, it wasn't able to be added.

In theory, there is no for this palette shift to be done in real-time. Each version of the image could have been shifted in an image editor offline, and have the player load the 4 different images upfront. Given the large images, it takes a lot of CPU time to do the colouring.


This is a performance profile on a load during development, even with cached lookups it maxes out the CPU for nearly 6 seconds while loading.

Even though the source images are large, once they are palette-reduced they compress very well. It would likely to be only a few hundred extra kilobytes worth of images of extra loading to compute the images offline.

At the end of the day it was decided to leave the CPU-expensive code in, as it allows faster iteration on images (I didn't need to create 4x copies of each image per edit). The slowdown should only happen while the game is loading, and even if players click through the loading screen, they should only see a few seconds of slowdown while the cache is initially populated. 

Leave a comment

Log in with itch.io to leave a comment.