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.
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.
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).
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
sy. They will be worked with in fixed 8.8 format, so they are 16bit variables. For example:
; 16-bit accumulator lda #1<<8 ; or lda #$100 sta sx sta sy
The matrix interprets
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
0-$ff, so 1.1 and 1.10 are different values!
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.
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
centerY at 0. Feel free to change that and experiment with it.
Complete Source Code: mode-7-tutorial-scaling.7z
Tutorial by bazz