Mode 7 is a BG mode that allows a background to be rotated, scaled, and skewed. There are more possibilities when HDMA gets involved, Mario Kart. Let's get started with the basics.
Prerequisites
You need to understand fixed point complementary math. You might be able to get by this part but it's going to come into play a lot in the other parts.
Initialization
You remember register $2105
to set the Screen Mode. Set the mode bits to 7, none of the other bits are acknowledged.
Register $211A: Mode 7 Initial Settings (W/1b)
ss----vh ss: Screen Out Settings (when outside screen area)
00 = screen repetition
10 = Color 0 backdrop
11 = tile 0 repetition
vh: Screen Flip
00 = no flip
01 = horizontal flip
10 = vertical flip
11 = both
Register $211B-$211E: Matrix Parameters A-D (W/2b)
low byte = represents fraction
high byte = represents whole number
$211B-$211E
take numbers in 8.8 fixed point format, allowing fractional accuracy. Next up, the registers for the center coordinate where the transformations are performed from.
Register $211F-$2120: Center Coordinate X/Y (W/2b)
---ccccc cccccccc c: coordinate
Write 2 bytes to $211F
for the X center coord, and 2 bytes to $2120
for the Y coord.
This is the part where you want to pay attention. I'm not going to throw a lot of theory at you don't worry. To use mode7 you use this matrix:
θ: Rotation angle
α: X scale factor
β: Y scale factor
[ cos(θ)·(1/α) -sin(θ)·(1/α) ] [ A B ]
[ sin(θ)·(1/β) cos(θ)·(1/β) ] [ C D ]
Note: Rotation is counter-clockwise. For clockwise rotation, you need to put a -sin in C +sin in B.
Rotation and scaling is the simplest to get started with. Simply choose values for θ, α, β. For example, if you wanted the background to be the same size and have it rotate you would update the cos and sin values while multiplying by a scale factor of 1 (no change).
Scaling
This is easiest to get started with. For now let's scale the bg with no rotation, θ = 0. This is nice and easy because cos(0) = 1 and sin(0) = 0, so we know right off the bat that B and C are going to be 0.0 and A and D are going to be 1 * our scale factors, or simply the scale factors themselves. Let's make it really easy. Using a scale factor of 1:
[ 1 0 ] Identity
[ 0 1 ] Matrix
This will give you the usual looking background, so yeah, not so interesting yet, but this is helping you understand the concept. Let's spice things up (not so much).
Let's create variables to hold our scale factors, we'll call them sx
and sy
. They will be worked with in fixed 8.8 format, so they are 16-bit variables. For example:
; 16-bit accumulator
LDA #1<<8 ; or LDA #$0100
STA sx
STA sy
The matrix interprets $0100
as 1.00
. What confused me when I was learning is that you cannot think of the fractional part like our normal decimal system. This fraction has a range of $00-$FF
, so 1.1 and 1.10 are different values!
Mode7 Graphics
Normal (not EXTBG) Mode7 graphics are stored in VRAM differently. The map and tile data are interleaved - the map is stored in every low byte and the tile data in every high byte. Remember, VRAM addresses are 2 bytes in size.
Image Conversion
I've been using Neviksti's pcx2snes to convert images to mode7 format. Mode7 backgrounds are 256-color 128x128 tilemaps which is 1024x1024 pixels. To convert a 1024x1024 pcx just do a pcx2snes -screen7 <image>
This will create 3 files: .clr color palette, .pc7 tile data, and .mp7 map data.
Uploading to VRAM
As I was saying earlier, the map is stored in every low byte and the tiles in every high byte. We can use $2115
to change whether the VRAM address is incremented after an upload to the low or high byte in VRAM. What we'll do is setup 2 DMAs to VRAM for the map and the tiles:
;-- Load map data to vram --
STZ $2115 ; increment VRAM address after write to $2118 (low byte)
LDX #$0000 ; VRAM addr $0000
STX $2116
LDX #$1800 ; Write to $2118
STX $4300
LDX #Map
STX $4302
LDA #:Map
STA $4304
LDY #$4000 ; # of bytes
STY $4305
LDA #$01 ; Enable DMA channel 0
STA $420B
;-- Load tile data to VRAM --
LDA #$80 ; increment VRAM address after write to $2119 (high byte)
STA $2115
LDX #$0000 ; VRAM addr $0000
STX $2116
LDX #$1900 ; Write to $2119
STX $4300
LDX #Tiles
STX $4302
LDA #:Tiles
STA $4304
LDY #$1F80 ; # of bytes
STY $4305
LDA #$01
STA $420B
Just for the sake of demonstration I wrote a simple program that lets you scale the width and height of a background as well as scroll through it. It's not much but I thought it would help you learn the basics. Also note that I left the centerX
and centerY
at 0. Feel free to change that and experiment with it.
Complete Source Code: mode-7-tutorial-scaling.7z
Tutorial by bazz