Map decoding in President
President's architecture is heavily inspired by that of Super Mario Bros. (SMB1).
President compared to SMB1
- Map is composed of "objects".
- Map is decoded to 8-bit metatile entries in a 2-screen-wide sliding window.
- Layer of "clouds", or a repeating sequence of columns where each column has a 1x3-tile object at a given height.
- Layer of "wall", or a 1x12-tile repeated object drawn on top of "clouds".
- Division of metatile number space into four subspaces $00-$3F, $40-$7F, $80-$BF, $C0-$FF.
- Subspace number, bits 7-6 of the metatile number, directly determines attribute value.
- Four 64-entry metatile tables, one for each subspace.
- The camera can move freely in the sliding window.
- Each map has a 32-entry directory containing the length of each screen's data.
- The decoder can operate on either side of the sliding window.
- When a block is destroyed in one of the 512 columns of a map, it sets a bit in a destruction buffer.
- A lookup table supports translating objects in a destroyed column into destroyed objects.
- A Markov chain supports efficient decoding of objects taller than one block by treating empty metatiles (those with a value of $00) specially.
- Clouds can be drawn in front of a wall, not just behind it. That's useful when using clouds to cut "windows" into a wall.
- It's CHR RAM based; map types can replace tile data.
- President is free software.
To decode column x of screen s
- Clear the column buffer
- If s > 0:
- Seek to screen s - 1
- x += 16
- Seek to screen s
- While x > 0:
- Draw all objects obj where obj.x <= x and obj.x + 16 >= x
- Seek to next screen
- x -= 16
- If this column's destroyed bit is set, apply destruction to column buffer
- Apply Markov chain from the top of the column buffer to the bottom
- Draw clouds into empty metatiles, if clouds in front are enabled
- Draw the wall into empty metatiles, if wall is enabled
- Draw clouds into empty metatiles, if clouds in back are enabled
- Draw column to nametable transfer buffer
- Copy column to sliding window buffer
- Wait for vertical blank
- Copy nametable transfer buffer to VRAM
- CPU RAM 12 bytes: Column decoding buffer
Each screen's map data has a 32-entry table giving the length in bytes of each screen's map data. When the decoder seeks to the previous or next screen, it follows the chain of lengths when modifying curMapPageDataStart.
A cloud pattern has
- Number of screens (1 byte), value = 1 to 4
- Metatiles making up each of 16 1x3 patterns (48 bytes)
- Column entries (16 to 64 bytes, 1 byte for each column)
Format of each column entry:
7654 3210 |||| |||| |||| ++++- Pattern number ++++------ Height at which pattern is drawn
A "wall" is a horizontal strip of identical tiles placed behind empty metatiles. This can represent water, a long castle wall, etc. It is defined as a 1x12, 2x12, 4x12, or 8x12 tile repeating block.
Most scenery in a level that the player can interact with is stored in a list of objects. Each level has a list of the lengths in bytes of each screen's data, consisting of the objects whose leftmost tile lies within that page.
7654 3210 Background object: first byte |||| |||| |||| ++++- Vertical position of object (0 to 11) ++++------ Horizontal position of object (0 to 15) 7654 3210 Background object: first byte |||| |||| |||| ||++- Argument; some uses this as a size argument (1, 2, 4, or 8 tiles) ++++-++--- Index into table of decoder procedures
The decoder for a background object is called with (x - o.x, y, obj), and it is responsible for overwriting metatiles in the column buffer.
A background object can never be wider than 16 tiles, because then it could sit across more than the two screens that the decoder considers.
There are two 192-byte buffers, each holding 16x12 bytes, where each byte controls what metatile is placed there. This is used for redrawing and collision. Columns of even screens go in buffer 0; columns of odd screens go in buffer 1.
- CPU RAM $0600-$06BF: Even screen buffer
- CPU RAM $0700-$07BF: Odd screen buffer
Between the two buffers of the sliding window is a destruction buffer organized as a 512-bit array. When a block is destroyed, the corresponding bit turns on.
The map decoder has a set of four 64-entry tables, one for each subspace, defining which tiles become which when destroyed. For example, if table[$19] = $8B, then all tiles of attribute 0 and value $19 become attribute 2 and value $0B in a destroyed column. This happens before Markov.
- CPU RAM $06C0-$06FF: Destruction buffer
Each subspace has a table of up to 64 entries from each tile to the most common tile below it. For example, if table[$23] = $64, then the most common tile below a tile of attribute 0 and value $23 is attribute 1 and value $24. Empty metatiles are replaced with the most common tile below the tile above them.
Metatile to nametable
The top 2 bits of a metatile number are the subspace number, and each subspace is hardcoded to one of the four color sets. Each subspace has a set of four lookup tables of up to 64 entries, each entry being 4 bytes, from each tile to the top left, bottom left, top right, and bottom right nametable entries making up a metatile. Which table is used depends on the metatile's attribute number.
To be written.
- CHR RAM $0000-$0FFF: Background tiles
- CHR RAM $1000-$1FFF: Sprite tiles