05. Palettes
Last updated
Last updated
A little more about the NES palette.
There are 64 choices (0-$3f), but many of those are black. The neslib forces you to use $0f for black and $30 for white. Don’t use the xD colors, especially $0D (it glitches some TVs, see YouTube videos of “Immortal” glitched title screen). Well, you can’t anyway, since the neslib converts it to $0f.
Background uses the PPU addresses $3f00-3f0f for palettes. Color index #0 (position $3f00 in the PPU) is the universal BG color. All 4 of the bg palettes will reuse that same color as their 0th color.
There are 4 BG palettes (and 4 Sprite palettes), with 4 sub-palettes. U = universal color U123 U123 U123 U123 That makes 13 unique BG colors on screen.
Sprites can only use 3 colors per tile. The 0th color index is transparent. Sprites use the $3f10-3f1f area of the PPU for palettes. You can use 12 unique sprite colors.
So far, we have been working with only 1 palette (4 colors), so let’s make something using all the bg palettes.
You can change an entire palette (32 bytes) with pal_all(), or change the 16 byte bg palette with pal_bg() and the 16 byte sprite palette with pal_spr(). Just pass it an array of 16 bytes. And you can change just 1 color with pal_col(index, color), where index is 0-$1f. There will be an example of pal_col in the next page (sprite collisions).
On a side note, the palette is in the PPU, and it can’t be written while the PPU is rendering, but all the neslib palette functions write to a buffer, which is copied to the PPU only during v-blank (in the nmi code). So, feel free to use these functions anytime, with the screen on or off.
Background Attribute Table
In the PPU, at the end of each nametable (tilemap), is the attribute table. For map#0, thats $23c0-$23ff. The only “attribute” they can have is palette selection, so, you can think of it as the palette table.
A nametable only has 64 bytes to work with for palette choices, so that makes an 8×8 grid. Each byte represents a 32×32 chunk of the BG. Each byte is further divided into 2 bit segments, and each 2 bits represents a 16×16 chunk of the background.
So, each tile doesn’t get its own palette choice. You can only define a palette choice for a block of 4 (2×2) tiles.
Try NES screen tool and try changing palettes, and you can see this right away.
Most games just design their games in blocks of 16×16. I do this too.
Notice how the floor blocks and the window blocks are exactly 16×16 pixels. The columns are exactly 32 pixels wide. The curtain area is exactly 32 pixels wide.
Having multiple palettes to choose from extends our tileset, since we can reuse the same tiles for different objects by changing its palette. Look at the clouds and the bushes. They are using the same tiles at the top.
Again, 1 attribute byte affects 16×16 blocks. 2 bits per block. So, the layout of an attribute byte go like this, bitwise…
44332211 bits in attribute byte
11 22 11 22 33 44 33 44
So if bits 44 goes 00, that block will use the 0th palette. If 22 goes 01, it will use the next palette, etc.
So, I made a background in NES screen tool. The entire picture was gray, using palette #0, but the code is writing to the Attribute table with fills, changing the palette choices. Notice I used get_at_addr(0,0,0) to calculate an address in the attribute table. Then using vram_fill() to set the attribute bytes.
The attribute table is fairly hard to modify mid game…involving bit shifting and masking. Many games just avoid changing it, except as part of the scrolling engine. You could design the game as 32×32 blocks, and you would just change a full byte, rather than worry about bit shifting.
I wrote 1 vram_put() statement to change 1 lower attribute byte, so you can see it’s size and abilities.
vram_put(0xe4); // push 1 byte 11 10 01 00
For now, if make the background in NES screen tool, just save the nametable with the attribute bytes as a compressed rle, and it will copy those when your game loads them.
https://github.com/nesdoug/06_Color/blob/master/color.c
https://github.com/nesdoug/06_Color
.
Part of my library is a metatile system, which can handle attribute bytes for you. For another time.