Skip to content

Palette Overrides

grunt-lucas edited this page Apr 29, 2025 · 32 revisions

Table Of Contents

Motivation

You may have noticed that palette primers do not give you control over the ordering of the output palettes, nor the ordering of colors within each palette. For direct control over palette and color orderings, palette overrides are the right choice. This feature may be especially useful for:

  1. DNS systems which expect window lights to be in specific, fixed palette slots
  2. Forcing tile sharing, i.e. saving tile space by storing one tile that can index into multiple palettes, e.g. the vanilla Pokémart and Pokécenter roof tile
  3. Cases where you want to manually construct palettes, or re-use palettes you already created manually
  4. Fixing the palette slots for your door anim colors, so they don't keep breaking as you update your tileset

Palette overrides and palette primers are complementary features. Both will work together, and (in most cases) play nicely with Porytiles's automatic palette assigment algorithm.

How To Use The Feature

First step: create a palette-overrides directory in your source folder, right along side your layer PNGs and attributes CSV. Within the palette-overrides directory, you can place a JASC .pal file for each output palette you want to override. E.g. if you want to override some slots in output palette one, then place a JASC .pal file called 01.pal in your palette-overrides directory.

A palette override JASC .pal file is like any other JASC .pal file, except it allows for a special wildcard - symbol which denotes any color. You can use this symbol to tell Porytiles that you don't care what it puts at this particular slot. That slot is "open" for Porytiles's automatic palette assignment algorithm to freely use.

A palette override JASC .pal file must have a declared size of 16, and must use the wildcard - symbol in the 0th pal slot. This is because pal slot 0 is always transparent. So we need to leave that slot open so Porytiles can place the transparent color there. You'll get an error if either your declared pal size isn't 16 or if your 0th pal slot isn't set to -. You'll also get an error if your actual pal size does not match the declared size.

Note

Porytiles accepts JASC .pal files with either CRLF or LF line-ending format. No need to worry about platform-specific line endings.

Here's a simple example. Suppose you want output pal 1 in your primary tileset to contain a particular red tone in pal slot 2, and a particular green tone in pal slot 3. You don't care about the contents of any other palette slots. Create a 01.pal file with the following contents, and place it in your palette-overrides folder:

JASC-PAL
0100
16
-
-
240 20 40
50 200 40
-
-
-
-
-
-
-
-
-
-
-
-

After compilation, you should see that your 01.pal in the output palettes directory contains the colors you specified at the appropriate slots!

Case Study: Tile Sharing

Let's now look at a more complex example which showcases how you can use palette overrides to pull off a tile sharing optimization.

Compiling Without Overrides

In the Resources directory, you can find a small primary set example that demonstrates how palette overrides alter the tileset compilation process. The example is a bit contrived, but it should serve to illustrate how the feature works.

Let's walk through compilation and see what happens. The tileset bottom, middle, and top layers look like this:

First, we'll compile without the overrides. Note that we have explicitly overriden the primary palette count to 3. This is crucial for understanding the example.

porytiles compile-primary -Wall -tiles-output-pal=true-color -pals-primary-override=3 -o without-compiled ./Resources/Examples/palette-overrides-tutorial/primary-without ./Resources/Examples/metatile_behaviors.h

The result of this compilation:

As you can see, a lot of the building roof tiles are essentially duplicated with a red and blue version of each. The palettes are also quite scrambled and aren't grouping the colors logically. We can do a lot better. If we can make the corresponding reds and blues line up in two different palettes, then we can force Porytiles to generate one tile that correctly indexes into multiple palettes, saving quite a bit of tile space.

So what exactly do we mean by "make the corresponding reds and blues line up in two different palettes?" Consider the pairs tiles marked by the matching arrows in the picture below:

If you look closely, you'll notice that each tile "pair" denoted by equivalent-colored arrows looks like the same tile, just with shifted colors.

Tile Sharing: Mathematical Definition

Warning

This section is under construction and I am not entirely sure this is correct. Feel free to skip or suggest edits.

You can skip to the next section if you don't care about precise definitions or if you find this section confusing.

That is, for each tile pair [T1, T2], where both T1 and T2 contain N unique colors, each unique color u in T1 "corresponds" to one and only one color v in T2. Inversely, each unique v in T2 "corresponds" to one and only one color u in T1. In some cases, u and v are the same color. Other times, they're not. The point is, u and v always "correspond" in a given tile pair.

What do we mean by "corresponds?" For a u in T1, mark down each pixel which contains color u. Then, look at these same pixels in T2. Create a set of all the colors contained at those pixels in T2. If that set has cardinality one, then we can say that u in T1 "corresponds" to one and only one color v in T2.

If there is correspondence for all u in T1

In other words, two tiles T1 and T2 are "sharable" when:

  1. The set U of unique colors in T1 has cardinality N
  2. The set V of unique colors in T2 has cardinality N
  3. The pixel-mapping function f that yields the V_n in T2 for any U_n in T1 is an involution

To construct your palette overrides such that T1 and T2 share hardware tiles, you simply need to list all the colors of U in one palette and all the colors of V in another palette. As long as U_n and V_n are placed in the same palette slot, you should be OK.

Setting Up Tile Sharing: In Practice

Usually, the easiest way to get started is to pick some pair of tiles T1 and T2, then figure out the full set U of unique colors in T1 and the full set V of unique colors in T2. Then, choose a palette to use for U and a different palette to use for V. Then line up the colors in each palette such that corresponding colors u and v are in the same palette slot. For this example, we've already constructed some palettes that satisfy all these constraints. See below:

00.pal

JASC-PAL
0100
16
-
248 184 128
200 64 80
232 144 112
216 104 96
96 96 120
64 72 104
216 224 232
248 248 248
128 128 136
152 176 216
184 200 224
-
-
-
-

01.pal

JASC-PAL
0100
16
-
112 184 240
72 112 168
96 160 216
80 136 192
96 96 120
64 72 104
216 224 232
248 248 248
128 128 136
152 176 216
184 200 224
-
-
-
-

We did a bit of work behind the scenes to put these pals together, but if you inspect them closely you'll see how they make sense. The first four colors in each are the corresponding reds and blues. You'll notice the rest of the colors are identical. These are the various greys that are shared between the mart and center tiles. Finally, let's create a 02.pal for the tree greens. You'll see why this is important later:

02.pal

JASC-PAL
0100
16
-
-
-
-
-
-
-
-
-
-
-
-
56 136 48
176 248 128
56 80 0
128 192 96

Take these three palettes and place them in your palette-overrides directory. Now compile again:

porytiles compile-primary -Wall -tiles-output-pal=true-color -pals-primary-override=3 -o with-compiled ./Resources/Examples/palette-overrides-tutorial/primary-with ./Resources/Examples/metatile_behaviors.h

The result of this compilation:

Notice how many fewer tiles we're using now! You can also see the palettes are "lined-up" in such a way that corresponding colors use the same slot. Great!

Tile Sharing Across Tileset Boundaries

You can also use palette overrides to force tile sharing across a primary-secondary tileset boundary. It works the same way as before. The Resources/Examples/palette-overrides-tutorial has a couple example secondaries to try. If you take a look, you'll notice that the secondary contains the same tree as the primary, just with differently shaded greens. Let's first try compiling without overrides and see what happens:

porytiles compile-secondary -Wall -tiles-output-pal=true-color -pals-primary-override=3 -pals-total-override=6 -o without-compiled-2 ./Resources/Examples/palette-overrides-tutorial/secondary-without ./Resources/Examples/palette-overrides-tutorial/primary-with ./Resources/Examples/metatile_behaviors.h

The result of this compilation is below. Circled in red are the secondary tree tiles and colors. You'll notice, circled in blue, the tree colors from the primary set (that we overrode into the last primary palette). Since the primary tree colors aren't properly aligned with the secondary ones, Porytiles is forced to create tiles in the secondary set for the secondary-colored tree:

Let's fix this. Check out the Resources/Examples/palette-overrides-tutorial/secondary-with/palette-overrides folder to see how we laid out the overrides. As a bonus, you'll notice we also set up the flower colors so that Porytiles can combine those red and purple secondary flowers. Now compile again with the updated tileset:

porytiles compile-secondary -Wall -tiles-output-pal=true-color -pals-primary-override=3 -pals-total-override=6 -o with-compiled-2 ./Resources/Examples/palette-overrides-tutorial/secondary-with ./Resources/Examples/palette-overrides-tutorial/primary-with ./Resources/Examples/metatile_behaviors.h

The result:

Notice how the palettes are now better aligned, and Porytiles was able to consolidate quite a few tiles. Very cool!

Manual Palette Allocation With Overrides

Palette overrides provide a way to force Porytiles to use a manual palette allocation. For example, let's assume you want to manually allocate the palettes for a pokeemerald primary tileset. First, create your palette-overrides directory within the Porytiles-format tileset directory. Then, copy your 00.pal through 05.pal into the palette-overrides folder. Finally, open each palette and adjust the declared size to 16 and make sure slot 0 uses the wildcard -. If your tiles are not allocatable with the palettes you've provided, you'll receive the usual error message.

This functionality is very useful in the following scenarios:

  1. You want Porytiles to handle tile flip/dupe optimization and metatile construction, but you'd like to set up palettes manually.
  2. Porytiles is struggling to allocate palettes for your tileset, but you know it's possible and can see where the allocation algorithm is going wrong.
  3. You have an old manually-constructed Porymap-format tileset that you've imported to Porytiles-format via the decompiler, but you want to keep your original, manually-constructed palettes.
Clone this wiki locally