Pattern tables

Last updated:

The majority of NES game graphics are stored in Tiles within structures called Pattern Tables (sometimes called the tile tables).

These tiles are similar to the spritesheets you'd find in a modern 2D game: a sheet of small images for game graphics.

These pattern tables are stored in the CHR-ROM memory of the cart, location of which is explained in the last part of previous chapter.

Next are displayed the pattern tables of the Thwaite game. Since:

... there's two pattern tables in Thwaite:

Pattern table0 ($4010-$500F):

Thwaite pattern table 0, 256 tiles in a 16×16 grid: a full font and a row of little houses

Pattern table1 ($5010-$600F):

Thwaite pattern table 1, 256 tiles in a 16×16 grid: explosions, missiles, and detailed houses

Keep in mind, each pattern table is displayed in a 16×16 tiles layout, left to right, top to bottom. But this is just to fit in the webpage width.
The tiles are actually stored as a "single strip", one after the other

Why is it in black and white?

Colors are not stored in pattern tables (why is explored at a later chapter).
Because of that, we rendered these in grayscale.

But even without the palette, we can discern the shapes: the font, the houses you defend, the missiles and explosion bursts, and the chunky title-screen letters spelling thwaite.

How is every tile represented in the data?

To teach how tiles are stored, I'll use the 1-tile little house below the o and right to the ~ tiles from pattern table 0.

This is the house scaled up:

The decoded tile rendered in grayscale: a small house

Notice how there's only 4 different grayscale tones, this will be important later.

We're gonna first obtain the 16 bytes of this tile and then we're going to convert them, somehow, into this image.

Getting the tile bytes address

To obtain those 16 bytes, we first need their address.

This tile is the tile 127 (0-based) counting left to right (row 7, column 15 so 7*16 + 15 = 127).

And each tile takes 16 bytes, so 126*16=2032, in hex 0x7f0

Since the pattern table starts at 0x4010 + 0x7F0 = 0x4800

We can get the 16 bytes at 0x4800 with xxd:

> xxd -s 0x4800 -l 16 thwaite.nes
20 00 00 0a 7a fb ff 00 ┊ 24 2e ff f1 04 a5 a5 00

Rendering the image

The first 8 bytes of the tile are bitplane 0, and the latter 8 are bitplane 1. And we're going to show every byte in binary.

        bitplane 0 (low bit)         bitplane 1 (high bit)
row 0   $20  0 0 1 0 0 0 0 0      $24  0 0 1 0 0 1 0 0
row 1   $00  0 0 0 0 0 0 0 0      $2E  0 0 1 0 1 1 1 0
row 2   $00  0 0 0 0 0 0 0 0      $FF  1 1 1 1 1 1 1 1
row 3   $0A  0 0 0 0 1 0 1 0      $F1  1 1 1 1 0 0 0 1
row 4   $7A  0 1 1 1 1 0 1 0      $04  0 0 0 0 0 1 0 0
row 5   $FB  1 1 1 1 1 0 1 1      $A5  1 0 1 0 0 1 0 1
row 6   $FF  1 1 1 1 1 1 1 1      $A5  1 0 1 0 0 1 0 1
row 7   $00  0 0 0 0 0 0 0 0      $00  0 0 0 0 0 0 0 0

Now, merge both planes into a new grid. For each pixel, stack its high bit (plane 1) over its low bit (plane 0) to get a 2-bit number:

merged (high bit, low bit)
row 0   00 00 11 00 00 10 00 00
row 1   00 00 10 00 10 10 10 00
row 2   10 10 10 10 10 10 10 10
row 3   10 10 10 10 01 00 01 10
row 4   00 01 01 01 01 10 01 00
row 5   11 01 11 01 01 10 01 11
row 6   11 01 11 01 01 11 01 11
row 7   00 00 00 00 00 00 00 00

Now read each 2-bit number as a value 03:

. . 3 . . 2 . .
. . 2 . 2 2 2 .
2 2 2 2 2 2 2 2
2 2 2 2 1 . 1 2
. 1 1 1 1 2 1 .
3 1 3 1 1 2 1 3
3 1 3 1 1 3 1 3
. . . . . . . .
The decoded tile, a small house

Hopefully, via intuition, you'll see how every number matches the tile. And that's how the tiles are rendered from data.

But where's the color?

Color is determined from a selected palette, which is determined at runtime. We're gonna see that way later.