SNES programming tutorial. Example 4.
https://github.com/nesdoug/SNES_04
Last time we created a background (tiles and map) and got it to show up on screen. This time we are going to add more layers.
In Mode 1, we get 3 background layers. Layer 1 and 2 are 4bpp (16 color) and Layer 3 is 2bpp (4 color). If you make the 2bpp tiles in YY-CHR, select the 2bpp GB setting. I made the graphics in GIMP and converted to 4 color indexed mode, saved to PNG (with no compression), and converted to SNES tiles with superfamiconv (with the BPP set to 2).
https://github.com/Optiroc/SuperFamiconv
Now I loaded all the maps and tiles to M1TE and quickly drew a line across layer 2, just to test it. Here’s each layer…
layer 1
layer 2
layer 3
Now let’s talk about how the layers work. Normally, layer 1 is on top, then layer 2 is next, and layer 3 on the bottom. Like this.
But each tile on the map has a PRIORITY setting. Normally, this is to determine if the tile will go behind a sprite on the same layer, or in front of it. In mode 1, the layers go like this…
(top)
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
Sprites with priority 0
BG3 tiles with priority 0
Unless bit 3 of $2105 is set. BG3 will be in front of everything (if the priority bit is set on the map). In M1TE, you can set all the priority bits for the whole map by checking a box. I did that for BG3. The only difference between the picture above and below is the bit 3 of $2105 is set.
https://wiki.superfamicom.org/backgrounds
This can be very useful for text boxes that appear in front of everything, or a HUD / Scoreboard that you can always see. Because BG3 is only 2bpp, it won’t be very colorful, so it will be ideal for text messages.
The code for putting all this together is very similar to the previous page. The 2bpp tiles were loaded to $3000 in the VRAM with a DMA.
ldx #$3000 stx vram_addr ; set an address in the vram of $3000 lda #1 sta $4300 ; transfer mode, 2 registers 1 write lda #$18 ; $2118 sta $4301 ; destination, vram data ldx #.loword(Tiles2) stx $4302 ; source lda #^Tiles2 sta $4304 ; bank ldx #(End_Tiles2-Tiles2) stx $4305 ; length lda #1 sta $420b ; start dma, channel 0
and the maps were loaded similarly with DMAs. BG2 map to $6800 and BG3 map to $7000. This points those layers to those VRAM addresses.
lda #$03
sta bg34_tiles ; $210c bg3 at VRAM address $3000
lda #$60 ; bg1 map at VRAM address $6000
sta tilemap1 ; $2107
lda #$68 ; bg1 map at VRAM address $6800
sta tilemap2 ; $2108
lda #$70 ; bg3 map at VRAM address $7000
sta tilemap3 ; $2109
We need to make sure that all 3 layers are active on the main screen.
lda #BG_ALL_ON
sta main_screen ; $212c
and that will give us this picture (same as above)
with BG3 behind everything.
When we flip bit 3… 00001000 on, BG3 will show up on top (if their priority bits are set). Note BG3_TOP is defined as 8.
lda #1|BG3_TOP ; mode 1, tilesize 8×8 all, layer 3 on top
sta bg_size_mode ; $2105
Like this.
Each of these layers scroll independently of each other. You would adjust them with these registers. They are write twice (low then high).
$210d – BG1 Horizontal
$210e – BG1 Vertical
$210f – BG2 Horizontal
$2110 – BG2 Vertical
$2111 – BG3 Horizontal
$2112 – BG3 Vertical
Maps, In Depth
All of our examples are with maps set to 32×32 tiles. (the screen is set to 224 pixels high, so you can’t see all the tiles at once). Each tile in the map takes 2 bytes, but since the VRAM is set up for 16 bits per address, it can be very confusing to look at in a Hex Editor (VRAM memory viewer). So each map uses $800 bytes, but only $400 addresses (32×32 = 1024 = $400). They would be arranged like…
0,1,2,3,4… 31
32,33,34,35… 63
64,65, etc.
So, if you go down 1 on the map, you add 32 to the address.
But what if we made the map 64 wide (for BG1 $2107, bit 0 = 1). If the first screen is at $6000, the second screen (to the right) would be at $6400.
Or, we could have made the map 32 wide and 64 tall (for BG1 $2107, bit 1 = 1). If the first screen is at $6000, the second screen (below the first) would be at $6400.
Lastly, if we made the map 64×64 (for BG1, both bits 0 and 1 set). If the first sceen is at $6000, the screens would be like
$6000 – $6400
$6800 – $6c00
If tiles were set to 8×8 size ($2105, called “character size”), a 64×64 map would be 512×512 pixels.
If tiles were set to 16×16, the same map would be 1024×1024 pixels. This should explain why we need 16 bit scrolling registers. If you scroll past the edge of the map, you wrap back around to the beginning again.
Tiles in the Map
So, I said that each entry in the map is 16 bits. Those bits are arranged like this…
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.
Each tileset is theoretically as big as 1024 tiles (for BG).
and one more bit on palettes.
Palettes in Mode 1
4bpp tiles use an entire row (left to right). If you set it’s palette to 0, the top row (indexes 0-15). Palette 1, the next row (indexes 15-31), and so forth down to the 8th row (palette 7). That’s indexes 0 – 127. Sprites would use the indexes 128 – 255. Sprites also use 4bpp tiles and 16 colors per tile.
2bpp tiles (BG3) shares the top 2 rows. Each palette only uses 4 colors, so palette 0 uses indexes 0-3, palette 1 uses index 4-7, palette 2 uses index 8-11, and palette 3 uses index 12-15… all in the top row. I usually reserve the top row for BG3. Palettes 4-7 similarly would use the next row. Every 0th color in each palette would be transparent.
Behind all the layers, the universal background color shows (index 0 of the palette), wherever there are transparent pixels. The black that fills most of these pictures is the background color showing through.