Backgrounds

From Snesdev wiki
Jump to navigation Jump to search

SOURCE: Anomie's Register Doc

Backgrounds

BG Modes

The SNES has 7 background modes, two of which have major variations. The modes are selected by bits 0-2 of register $2105. The variation of Mode 1 is selected by bit 3 of $2105, and the variation of Mode 7 is selected by bit 6 of $2133.

Mode    # Colors for BG
         1   2   3   4
======---=---=---=---=
0        4   4   4   4
1       16  16   4   -
2       16  16   -   -
3      256  16   -   -
4      256   4   -   -
5       16   4   -   -
6       16   -   -   -
7      256   -   -   -
7EXTBG 256 128   -   -

In all modes and for all BGs, color 0 in any palette is considered transparent.


Tile Maps and Character Maps

Each BG has two regions of VRAM associated with it: one for the tilemap, and one for the character data.

The tilemap address is selected by bits 2-7 of registers $2107-a, and the tilemap size is selected by bits 0-1 of that same register. All tilemaps are 32x32, bits 0-1 simply select the number of 32x32 tilemaps and how they're layed out in memory:

  00  32x32   AA
              AA
  01  64x32   AB
              AB
  10  32x64   AA
              BB
  11  64x64   AB
              CD

Starting at the tilemap address, the first $800 bytes are for tilemap A. Then come the $800 bytes for B, then C then D. Of course, if only A is required something else could be stuck in the empty space.

Each entry in the tilemap is 2 bytes, formatted as (high low):

  vhopppcc cccccccc

  v/h  = Vertical/Horizontal flip this tile.
  o    = Tile priority.
  ppp  = Tile palette. The number of entries in the palette depends on the Mode
      and the BG.
  cccccccccc = Tile number.

To find the tilemap word address for a particular tile (X and Y), you'd use a formula something like this:

 (Addr<<9) + ((Y&0x1f)<<5) + (X&0x1f) + (SY ? ((Y&0x20)<<(SX ? 6 : 5)) : 0) + (SX ? ((X&0x20)<<5) : 0)

The tile character data is stored at the address pointed to by registers $210b-c, starting at byte address:

 (Base<<13) + (TileNumber * 8*NumBitplanes)

Each tile is (normally) 8x8 pixels. The data is stored in bitplanes. Each row of the tile fills 1 byte, with the leftmost pixel being in bit 7. For 4-color tiles, bitplanes 0 and 1 are stored in the low and high bytes of a word, with 8 words making up the tile. For a 16-color tile, bitplanes 0 and 1 are stored as for a 4-color tile, followed by bitplanes 2 and 3 in the same format. A 256-color tile is stored in the same way as 2 4-color tiles.

If the appropriate bit of $2105 is set, each "tile" of the tilemap actually corresponds to a 16x16 pixel block consisting of Tile, Tile+1, Tile+16, and Tile+17. In this case, the 32x32 tile tilemap codes for a 512x512 pixel screen rather than a 256x256 pixel screen as normal. Thus, using both 16x16 tiles and the 64x64 tilemap each BG can be up to 1024x1024 pixels. There is no wrapping like there is for 16x16 sprites: if you specify Tile=$2ff, you'll get $2ff, $300, $30f, and $310 (as opposed to $2ff, $2f0, $20f, and $200 you might otherwise expect). $3ff goes to $000, of course. Flipping in this mode flips th whole 16x16 tile, not just the individual 8x8 tiles.


BG Scrolling

Of course, depending on the BG mode and the interlace setting, Modes 0-6 have an actual display of 256x224 or 256x239 pixels. The BG scroll registers $210d-$2114 control the offset of the displayed area within that possible 256x256 to 1024x1024 pixel BG.

The display can never fall outside the BG: if that would seem to be the case, simply wrap around back to 0 (or 'tile' the BG to fill the full 1024x1024, however you like to think of it).

The registers $210d-$2114 are all write-twice to set the 16-bit value. The way this works, the last write to any of these registers is stored in a buffer. When a new byte is written to any register, the current register value, the previous byte written to any of the 6 registers, and the new byte written are combined as follows:

 For BGnHOFS: (NewByte<<8) | (PrevByte&~7) | ((CurrentValue>>8)&7)
 For BGnVOFS: (NewByte<<8) | PrevByte

For the most part, the details don't really matter as most games always write two bytes to one of these registers. However, some games write only one byte, or they do other odd things.

Thus, the tilemap entry for a particular X and Y position on the screen may be calculated as follows:

 Size = 8 or 16 depending on the appropriate bit of $2105
 TileX = (X + BGnHOFS)/Size
 TileY = (Y + BGnVOFS)/Size
 Look up the tile at TileX and TileY as described above.

Note that many games will set their vertical scroll values to -1 rather than 0. This is bacause the SNES loads OBJ data for each scanline during the previous scanline. The very first line, though, wouldn't have any OBJ data loaded! So the SNES doesn't actually output scanline 0, although it does everything to render it. These games want the first line of their tilemap to be the first line output, so they set their VOFS registers in this manner. Note that an interlace screen needs -2 rather than -1 to properly correct for the missing line 0 (and an emulator would need to add 2 instead of 1 to account for this).


Direct Color Mode

For the 256-color BGs of Modes 3, 4, and 7, $2130 bit 0 when set enables direct color mode. In this mode, instead of ignoring ppp and using the character data as the palette index, you treat the character data as expressing a color BBGGGRRR, and use the 3 bits of ppp as bgr to make the color

 Red=RRRr0, Green=GGGg0, Blue=BBb00

In direct color mode you cannot have a black pixel, since any pixel with character data = 0 is still considered transparent. Use one of the almost-black colors instead (01, 08 or 09 are good choices).


Mode 0

In Mode 0, you have 4 BGs of 4 colors each. To calculate the starting palette entry for a particular tile, you calculate:

 ppp*4 + (BG#-1)*32

The background priority is (from 'front' to 'back'):

 Sprites with priority 3
 BG1 tiles with priority 1
 BG2 tiles with priority 1
 Sprites with priority 2
 BG1 tiles with priority 0
 BG2 tiles with priority 0
 Sprites with priority 1
 BG3 tiles with priority 1
 BG4 tiles with priority 1
 Sprites with priority 0
 BG3 tiles with priority 0
 BG4 tiles with priority 0


Mode 1

In Mode 1, you have 2 BGs of 16 colors and 1 BG of 4 colors. To calculate the starting palette entry, calculate:

 ppp*ncolors

The background priority varies depending on the setting of bit 3 of $2105. The priority is (from 'front' to 'back'):

 BG3 tiles with priority 1 if bit 3 of $2105 is set
 Sprites with priority 3
 BG1 tiles with priority 1
 BG2 tiles with priority 1
 Sprites with priority 2
 BG1 tiles with priority 0
 BG2 tiles with priority 0
 Sprites with priority 1
 BG3 tiles with priority 1 if bit 3 of $2105 is clear
 Sprites with priority 0
 BG3 tiles with priority 0


Mode 2

In Mode 2, you have 2 BGs of 16 colors each. To calculate the starting palette index, calculate:

 ppp*16

The priority is (from 'front' to 'back'):

 Sprites with priority 3
 BG1 tiles with priority 1
 Sprites with priority 2
 BG2 tiles with priority 1
 Sprites with priority 1
 BG1 tiles with priority 0
 Sprites with priority 0
 BG2 tiles with priority 0

Note the change from Modes 0 and 1.

Mode 2 is the first of the Offset-Per-Tile Modes. In this mode, the 'tile data' for BG3 actually encodes a (possible) replacement HOffset and/or VOffset value for each tile of BG1 and/or BG2.

Consider a visible scanline. Normally, you'd get the pixels something like this:

 HOFS = X + BGnHOFS
 VOFS = Y + BGnVOFS
 Pixel[X,Y] = GetPixel(GetTile(BGn, HOFS, VOFS), HOFS, VOFS)

With offset-per-tile, the formula is a little more complicated:

 HOFS = X + BGnHOFS
 VOFS = Y + BGnVOFS
 ValidBit = 0x2000 for BG1, or 0x4000 for BG2
 if (!IsFirst8x8Tile(BGn, HOFS)) {
   /* Hopefully these calculations are right... */
   Hval = GetTile(BG3, (HOFS&7)|(((X-8)&~7)+(BG3HOFS&~7)), BG3VOFS)
   Vval = GetTile(BG3, (HOFS&7)|(((X-8)&~7)+(BG3HOFS&~7)), BG3VOFS + 8)
   if (Hval&ValidBit) HOFS = (HOFS&7) | ((X&~7) + (Hval&~7))
   if (Vval&ValidBit) VOFS = Y + Vval
 }
 Pixel[X,Y] = GetPixel(Get8x8Tile(BGn, HOFS, VOFS), HOFS, VOFS)

In other words, number the visible tiles in BGn from 0-32, and the 'visible' tiles in BG3 the same way. BGn tile 0 is offset as normal, then for 1<=T<33 BGn tile T gets the offset data from BG3 tile T-1. It doesn't matter whether or not the tiles actually align in any way.

Note that the leftmost visible tile is done as normal in all cases (although as little as 1 pixel may be visible, and if that still bothers you then use a clip window to hide it), and the next tile uses the tilemap entry for what would be BG3's leftmost tile. Note also that the 'new' offset completely overrides the BGnVOFS register, but the lower 3 bits of the BGnHOFS offset are still used. And note that the current Y position on the screen does not affect which row of the BG3 tilemap to reference, it's as if Y were always 0.

On the other hand, note that even if BGn is 16x16 tiles, BG3 can specify the offset for each 8x8 subtile. And if BG3 is 16x16, the offsets will apply to all the corresponding 8x8 subtiles on BGn. Also note that if BG3 is 16x16, we may end up using the same tile for Hval and Vval.


Mode 3

In Mode 3, you have one 256-color BG and one 16-color BG. To calculate the starting palette index, calculate:

 BG1: 0
 BG2: ppp*16

The priority is (from 'front' to 'back'):

 Sprites with priority 3
 BG1 tiles with priority 1
 Sprites with priority 2
 BG2 tiles with priority 1
 Sprites with priority 1
 BG1 tiles with priority 0
 Sprites with priority 0
 BG2 tiles with priority 0

Note that register $2130 may enable Direct Color Mode on BG1.


Mode 4

In Mode 4, you have one 256-color BG and one 4-color BG. To calculate the starting palette index, calculate:

 BG1: 0
 BG2: ppp*4

The priority is (from 'front' to 'back'):

 Sprites with priority 3
 BG1 tiles with priority 1
 Sprites with priority 2
 BG2 tiles with priority 1
 Sprites with priority 1
 BG1 tiles with priority 0
 Sprites with priority 0
 BG2 tiles with priority 0

Note that register $2130 may enable Direct Color Mode on BG1.

Mode 4 is the second of the Offset-Per-Tile Modes. It operates much like Mode 2, however the SNES doesn't have time to load two offset values. Instead, it does this:

   Val = GetTile(BG3, ...)
   if (Val&0x8000) {
     Hval = 0
     Vval = Val
   } else {
     Hval = Val
     Vval = 0
   }


Mode 5

In Mode 5, you have one 16-color BG and one 4-color BG. To calculate the starting palette index, calculate:

 ppp*ncolors

The priority is (from 'front' to 'back'):

 Sprites with priority 3
 BG1 tiles with priority 1
 Sprites with priority 2
 BG2 tiles with priority 1
 Sprites with priority 1
 BG1 tiles with priority 0
 Sprites with priority 0
 BG2 tiles with priority 0

Mode 5 is rather different from the previous modes. Instead of using an 8/16 pixel wide tile as normal, it always takes a 16 pixel wide tile (the height may still be 8 or 16) and only uses half the pixels (zero-based, the even pixels for subscreen tiles and the odd pixels for mainscreen tiles). Then it forces pseudo-hires on to render a 512-pixel wide scanline. Also, if Interlace mode is on (see bit 0 of $2133), the screen is 448 or 478 half-lines high instead of 224 or 239. Either the odd half-lines or the even half-lines are drawn each frame, as indicated by bit 7 of $213f.

Note that this means you must set $212c and $212d to the same value to get the 'expected' display.


Mode 6

In Mode 6, you have only one 16-color BG. To calculate the starting palette index, calculate:

 ppp*ncolors

The priority is (from 'front' to 'back'):

 Sprites with priority 3
 BG1 tiles with priority 1
 Sprites with priority 2
 Sprites with priority 1
 BG1 tiles with priority 0
 Sprites with priority 0

Mode 6 has the same oddities as Mode 5. In addition, it is an offset per tile mode! That part works just like as Mode 2. However, remember that Mode 6 always uses 8 pixel (16 half-pixel) wide tiles, this applies to BG3 as well as BG1. You can't apply the offset to an 8-half-pixel tile nor to a 16-pixel wide area (except by using two offset values for the two 8-pixel areas).


Mode 7

Mode 7 is extremely different from all the modes before. You have one BG of 256 colors. However, the tilemap and character map are laid out completely differently.

The tilemap and charactermap are interleaved, with the character data being in the high byte of each word and the tilemap data being in the low byte (note that in hardware, VRAM is set up such that odd bytes are in one RAM chip and even in another, and each RAM chip has a separate address bus. The Mode 7 renderer probably accesses the two chips independantly). The tilemap is 128x128 entries of one byte each, with that one byte being simply a character map index. The character data is stored packed pixel rather than bitplaned, with one pixel per byte. Thus, to calculate the tilemap entry byte address for an X and Y position in the playing field, you'd calculate: (((Y&~7)<<4) + (X>>3))<<1

To find the byte address of the pixel, you'd calculate:

 (((TileData<<6) + ((Y&7)<<3) + (X&7))<<1) + 1

Note that bits 4-7 of $2105 are ignored, as are $2107-$210c. They can be considered to be always 0.

The next odd thing about Mode 7 is that you have full matrix transformation abilities. With creative use of HDMA, you can even change the matrix per scanline. See registers $211b-$2120 for details on the matrix transformation formula. The entire screen can be flipped with bits 0-1 of $211a.

And finally, the playing field can actually be made larger than the tilemap. If bit 7 of $211a is set, bit 6 of $211a controls what is seen filling the space surrounding the map.

The background priorities are:

 Sprites with priority 3
 Sprites with priority 2
 Sprites with priority 1
 BG1
 Sprites with priority 0

When bit 6 of $2133 is set, you get a related mode known as Mode 7 EXTBG. In this mode, you get a BG2 with 128 colors, which uses the same tilemap and character data as BG1 but interprets the high bit of the pixel as a priority bit. The priority map is:

 Sprites with priority 3
 Sprites with priority 2
 BG2 pixels with priority 1
 Sprites with priority 1
 BG1
 Sprites with priority 0
 BG2 pixels with priority 0

Note that the BG1 pixels (if BG1 is enabled) will usually completely obscure the low-priority BG2 pixels.

BG2 uses the Mode 7 scrolling registers ($210d-e) rather than the 'normal' BG2 ones ($210f-10). Subscreen, pseudo-hires, math, and clip windows work as normal; keep in mind OBJ and that you can do things like enable BG1 on main and BG2 on sub if you so desire. Mosaic is somewhat weird, see the section on Mosaic below.

Note that BG1, being a 256-color BG, can do Direct Color mode (in this case, of course, there is no palette value so you're limited to 256 colors instead of 2048). BG2 does not do direct color mode, since it is only 7-bit.


Rendering the BGs

Rendering a BG is simple.

1) Get your H and V offsets (either by reading the appropriate registers or by doing the offset-per-tile calculation).

2) Use those to translate the screen X and Y into playing field X and Y - Note this is rather complicated for Mode 7

3) Look up the tilemap for those coordinates

4) Use that to find the character data

5) If necessary, de-bitplane it and stick it in a buffer.


See the section "RENDERING THE SCREEN" below for more details.

Unresolved Issues

1) What happens to the very first pixel on the scanline in Hires Math?

2) Various registers still need to know when writing to them is effective.


Windows

The masking windows are pretty simple. The windows can be used to mask off a portion of any BG on the scanline. With HDMA, they can be adjusted per scanline. They can be combined in various ways, per BG. Each can be used to select either the region of the BG to keep, or the region of the BG to hide, per BG. All that's left is to see the registers above and the section "RENDERING THE SCREEN" below for details.

The Color Window

The color window is rather different. The color window itself can be set to clip the colors of pixels to black (before math, so it's almost the same effect you'd get by setting all entries in the palette to black, then fixing them before you do subscreen addition--the only difference is that half math will not occur), and to prevent all color math effects from occurring. These can be applied never, always, inside the "clip" windows specified for the color window, or outside the "clip" window.

Bits 6-7 of register $2130 controls whether the pixel colors (and half-math) will be clipped inside the window, outside the window, never, or always. Bits 4-5 do the same for preventing color math.

Consider the main screen set up so BGs 1 and 2 are visible in an 8x8 checkerboard pattern, with all the BG1 pixels red and all the BG2 pixels blue. The subscreen is filled with a green BG, and color math is enabled on BG 1 only. You'll end up with a yellow and blue checkerboard. Turn on the color window to clip colors, and you'll get a green and black checkerboard since the subscreen is only added (to a black pixel) where BG1 would be visible. If you clip math instead, you'll get the same display you'd get with color math disabled on all BGs.

In hires modes, we use the previous main-screen pixel to determine whether the color window effect should be applied to a subscreen pixel. See "Color Math" below for details.


Rendering the screen

Mosaic

The mosaic filter is applied after the BG is rendered and scrolled but before it is clipped, combined with other BGs, pseudo-hiresed, or mathed. Each XxX block of pixels is replaced with the upper-leftmost pixel of the block. The 'blocks' are such that the upper-leftmost block is at the left edge of the screen at the scanline where $2106 was written (or the first visible scanline if it was not written this frame).

Modes 5/6 Hires work slightly differently: they use a 2XxX block of half-pixels. Similarly, Modes 5/6 interlaced use a 2Xx2X block of half-pixels. So if you set $2106 to $0F ("1x1" blocks), the even half-pixels will be expanded to cover the odd half-pixels. $1F would cover the next even-and-odd pixel over as well. An example: put a single red pixel at line #1 pixel #0 of Mode 5 BG1, and a single blue pixel in the same place on BG2. Enable BG1 on main and BG2 on sub, you'll see the blue pixel only. Set $2106=$03, and you'll suddenly see both the blue and red pixels. Set $2106=$13, and you'll see "BRBR" on two lines.

Mode 7's matrix transformations do not affect the mosaic block positions, so BG1 can be mosaiced about as normal. BG2 in EXTBG mode is weird, though: it uses bit 0 of $2106 to control "vertical mosaic" and bit 1 to control "horizontal mosaic". So if $2106 is $F1, BG2 will expand with 1x16 blocks. $F2 will give 16x1 blocks, and only $F3 will give the expected 16x16 blocks. Note that BG1 still uses bit 0 as usual, so you can have BG1 expanded with 16x16 blocks and the high-priority BG2 pixels expanded with 1x16 blocks on top of it. Or you could have BG1 rendered as normal, but with the high-priority pixels from BG2 expanded 16x1 on top of it.


Color Math

Each main-screen BG (and the color-0 backdrop, and the sprites (although sprites with palettes 0-3 never participate)) may be marked in register $2131 to participate in color math. If the visible pixel is from a layer/OBJ participating in color math, we perform one of 8 operations on the pixel, depending on $2130 bit 1 and $2131 bits 6-7.

 0 00: Add the fixed color. R, G, and B are added separately, and clipped to
       the max.
 0 01: Add the fixed color, and divide the result by 2 before clipping (unless
       the Color Window is clipping colors here).
 0 10: Subtract the fixed color from the pixel. For example, if the pixel is
       (31,31,0) and the fixed color is (0,16,16), the result is (31,15,0).
 0 11: Subtract the fixed color, and divide the result by 2 (unless CW etc).
 1 00: Add the corresopnding subscreen pixel, or the fixed color if it's the
       subscreen backdrop.
 1 01: Add the subscreen pixel and divide by 2 (unless CW etc), or add the
       fixed color with no division.
 1 10: Subtract the subscreen pixel/fixed color.
 1 11: Subtract the subscreen pixel and divide by 2 (unless CW etc), or sub
       the fixed color with no division.

In hires modes, color math is applied to the visible subscreen pixels as well. Choosing the math operation is simple: look at the previous main-screen pixel (i.e. if we're at pixel #6 on the 512-pixel screen (which is taken from pixel

  1. 4 on the subscreen), we look at pixel #5 (#3 on the main screen)). If no math

was applied to that pixel, don't math this subscreen pixel either. If the fixed color was added/subtracted, add/subtract the fixed color. And if a pixel from the subscreen was added/subtracted, add/subtract that main-screen pixel (the original value before math). What happens to the subscreen pixel at the left edge of the screen is unknown.

This is really important with color subtraction: normally, if you have a block of cyan (#00ffff) on main and a block of magenta (#ff00ff) on sub, subtraction would give a block of green. Hires math will give you a block of alternating green and red, which will probably appear yellow on your TV. If you've set $2131 bit 6 and this block is sitting alone in the middle of the backdrop, you'll have a bright line at the left edge where the fixed color was subtracted from the subscreen pixel and no 1/2 was applied (because the previous main pixel had the fixed color subtracted and no 1/2 applied).


Rendering the Screen

Note that this may be inaccurate.

1) Go down the priority list to find the first BG/OBJ layer that is enabled on
   main, not clipped, and has a non-transparent pixel here. You'll always
   bottom out on the backdrop (color 0) if not before.
2) If the color window clips colors here, set the color of that pixel to 0.
3) If color math is applicable and the color window doesn't clip math here, do
   math.

Hires modes (BG modes 5 and 6 or any mode 0-4 with bit 3 of $2133 set) should process the visible subscreen pixels as described above.