How does SNES (mode 7) rotate tile pixels internally?
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
-
- Posts: 24
- Joined: Sun Dec 18, 2016 1:11 pm
How does SNES (mode 7) rotate tile pixels internally?
I'm writing a software renderer to work veeeery similar (nearly the same) to the SNES ppu but slightly(?) simpler. Indexed color graphics, 8x8 tile-based, multiple modes etc. But I am wondering for the purposes of writing this SNES like renderer, how does it actually rotate tiles? Mine draws to the screen by basically looping through pixels and "copy-pasting" tiles onto the screen in a way, giving them their real pixel color from the palette as they are pasted.
It all happens in a little 8x8 area, per-tile. Which makes it really, really hard for me to figure out how the heck I am supposed rotate pixels, on a low level, with this sort of system?? I would have to increase area/size, which is kind of hard when I just loop through the pixels/bytes. I just have no idea where to start with it! Hopefully this info can also help when I add sprite rotation in a similar way, but the SNES doesn't have that...
Can I get a low-ish level overview of how it calculates/manipulates the rotated pixels of the tiles and then draws them? Not low level like "does this with that address, this register, check this bit..." but more like "does this with each of these pixels in this way and converts them to this format [etc...]"
It all happens in a little 8x8 area, per-tile. Which makes it really, really hard for me to figure out how the heck I am supposed rotate pixels, on a low level, with this sort of system?? I would have to increase area/size, which is kind of hard when I just loop through the pixels/bytes. I just have no idea where to start with it! Hopefully this info can also help when I add sprite rotation in a similar way, but the SNES doesn't have that...
Can I get a low-ish level overview of how it calculates/manipulates the rotated pixels of the tiles and then draws them? Not low level like "does this with that address, this register, check this bit..." but more like "does this with each of these pixels in this way and converts them to this format [etc...]"
-
- Posts: 3140
- Joined: Wed May 19, 2010 6:12 pm
Re: How does SNES (mode 7) rotate tile pixels internally?
It draws pixels from left to right, top to bottom.
Re: How does SNES (mode 7) rotate tile pixels internally?
Mode 7:
Has a library of 256 tiles
Which are used to make a 1024x1024 pixel master tilemap.
At the beginning of each scanline,
it calculates a starting location and a rate to walk through the 1024x1024 pixel map per output pixel (in a calculus sense, dX/dx and dY/dx)
So, e.g.
for scanline 0
it says "ok, we're starting at (currentX, currentY), and our rate of walking through the table is (deltaX, deltaY)"
Fetch the first pixel from currentX, currentY
Add deltaX and deltaY to currentX and currentY respectively (deltaX and deltaY can be smaller than 1.)
Repeat these two instructions 256 times
For scanline 1, it calculates a different currentX and currentY. If nothing has changed things, deltaX and deltaY are the same. (The SNES provides hardware that can change them. That's how 3D-ish modes work)
Has a library of 256 tiles
Which are used to make a 1024x1024 pixel master tilemap.
At the beginning of each scanline,
it calculates a starting location and a rate to walk through the 1024x1024 pixel map per output pixel (in a calculus sense, dX/dx and dY/dx)
So, e.g.
for scanline 0
it says "ok, we're starting at (currentX, currentY), and our rate of walking through the table is (deltaX, deltaY)"
Fetch the first pixel from currentX, currentY
Add deltaX and deltaY to currentX and currentY respectively (deltaX and deltaY can be smaller than 1.)
Repeat these two instructions 256 times
For scanline 1, it calculates a different currentX and currentY. If nothing has changed things, deltaX and deltaY are the same. (The SNES provides hardware that can change them. That's how 3D-ish modes work)
Re: How does SNES (mode 7) rotate tile pixels internally?
It does more or less the same thing as all 3D rendering systems: it has a transformation matrix.
The typical way to think of a transformation matrix is you have a vector which holds your X,Y position of a pixel. You multiply that vector by a matrix to get a new vector, which is the new position after transformation. Depending on the contents in the matrix, this can do rotation, flipping, moving, zooming, stretching, etc, etc. Any arbitrary transformation.
Mode 7 actually does that in reverse. Instead of taking a pixel position and translating it to find it's on-screen position, it takes an on-screen position and translates it to find what pixel should be drawn there.
The formula for this is in Anomie's wonderful "regs.txt" SNES reference doc:
X, Y = The pixel from the 1024x1024 BG to draw
SX, SY = Screen position to draw it
everything else: values that are configurable by the game.
@lidnariq: The delta X/Y thing is pretty interesting. I had always just assumed it did all the math for each pixel in the scanline. Would the delta approach have rounding errors?
The typical way to think of a transformation matrix is you have a vector which holds your X,Y position of a pixel. You multiply that vector by a matrix to get a new vector, which is the new position after transformation. Depending on the contents in the matrix, this can do rotation, flipping, moving, zooming, stretching, etc, etc. Any arbitrary transformation.
Mode 7 actually does that in reverse. Instead of taking a pixel position and translating it to find it's on-screen position, it takes an on-screen position and translates it to find what pixel should be drawn there.
The formula for this is in Anomie's wonderful "regs.txt" SNES reference doc:
Code: Select all
The matrix transformation formula is:
[ X ] [ A B ] [ SX + M7HOFS - CX ] [ CX ]
[ ] = [ ] * [ ] + [ ]
[ Y ] [ C D ] [ SY + M7VOFS - CY ] [ CY ]
Note: SX/SY are screen coordinates. X/Y are coordinates in the playing
field from which the pixel is taken. If $211a bit 7 is clear, the
result is then restricted to 0<=X<=1023 and 0<=Y<=1023. If $211a bits 6
and 7 are both set and X or Y is less than 0 or greater than 1023, use
the low 3 bits of each to choose the pixel from character 0.
The bit-accurate formula seems to be something along the lines of:
#define CLIP(a) (((a)&0x2000)?((a)|~0x3ff):((a)&0x3ff))
X[0,y] = ((A*CLIP(HOFS-CX))&~63)
+ ((B*y)&~63) + ((B*CLIP(VOFS-CY))&~63)
+ (CX<<8)
Y[0,y] = ((C*CLIP(HOFS-CX))&~63)
+ ((D*y)&~63) + ((D*CLIP(VOFS-CY))&~63)
+ (CY<<8)
X[x,y] = X[x-1,y] + A
Y[x,y] = Y[x-1,y] + C
(In all cases, X[] and Y[] are fixed point with 8 bits of fraction)
SX, SY = Screen position to draw it
everything else: values that are configurable by the game.
@lidnariq: The delta X/Y thing is pretty interesting. I had always just assumed it did all the math for each pixel in the scanline. Would the delta approach have rounding errors?
Re: How does SNES (mode 7) rotate tile pixels internally?
dX/dx and dY/dx (and the change per scanline, dX/dy and dY/dy) are, I think, literally just the entries in the affine transformation matrix. So the rounding error should happen at programming time, not at blit time.Disch wrote:@lidnariq: The delta X/Y thing is pretty interesting. I had always just assumed it did all the math for each pixel in the scanline. Would the delta approach have rounding errors?
i.e.
Code: Select all
⎡A B⎤ = ⎡∂X/∂x ∂X/∂y⎤
⎣C D⎦ ⎣∂Y/∂x ∂Y/∂y⎦
Re: How does SNES (mode 7) rotate tile pixels internally?
And I see those rounding errors all the time in Super Mario Kart. If you want, I can take a screenshot of its blatant rounding errors, but be careful because you won't be able to unsee them later.lidnariq wrote:dX/dx and dY/dx (and the change per scanline, dX/dy and dY/dy) are, I think, literally just the entries in the affine transformation matrix. So the rounding error should happen at programming time, not at blit time.Disch wrote:Would the delta approach have rounding errors?
Re: How does SNES (mode 7) rotate tile pixels internally?
Do you mean something other than aliasing?
Re: How does SNES (mode 7) rotate tile pixels internally?
I mean that not only are the textures aliased, but the starting position for each scanline appears to be aliased as well.
-
- Posts: 611
- Joined: Mon Jan 23, 2006 7:47 am
- Location: Germany
- Contact:
Re: How does SNES (mode 7) rotate tile pixels internally?
You mean stuff like this?
My current setup:
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
-
- Posts: 3140
- Joined: Wed May 19, 2010 6:12 pm
Re: How does SNES (mode 7) rotate tile pixels internally?
Is this something that was fixed in later console revisions? It looks like something wasn't working the way it was supposed to.
Re: How does SNES (mode 7) rotate tile pixels internally?
Unfortunately, this is the nature of working with fixed point precision. If you work with very small values, things get stair-steppy because you aren't able to express differences smaller than 1/256. Seems like you can avoid those artifacts if you keep A and D at or above 0x40 (i.e. no closer than a 4x zoom).
SNES NTSC 2/1/3 1CHIP | serial number UN318588627
Re: How does SNES (mode 7) rotate tile pixels internally?
I've found that the transforms can be a bit jumpy even at around 2x zoom. I had a slowly rotating background, and it was distracting to the player because it jiggled visibly. I fixed it by using tiles as pixel pairs and the tilemap as a packed-pixel bitmap, which allowed me to zoom out a fair bit; the result is way smoother.
I'm also squishing it horizontally at 7:8, so it's got a square aspect ratio on the TV regardless of rotation angle. Maybe that had something to do with the jiggling...
I'm also squishing it horizontally at 7:8, so it's got a square aspect ratio on the TV regardless of rotation angle. Maybe that had something to do with the jiggling...
-
- Posts: 3140
- Joined: Wed May 19, 2010 6:12 pm
Re: How does SNES (mode 7) rotate tile pixels internally?
I think I found the reason why. Was this done just to save a couple pennies?X[0,y] = ((A*CLIP(HOFS-CX))&~63)
+ ((B*y)&~63) + ((B*CLIP(VOFS-CY))&~63)
+ (CX<<8)
Y[0,y] = ((C*CLIP(HOFS-CX))&~63)
+ ((D*y)&~63) + ((D*CLIP(VOFS-CY))&~63)
+ (CY<<8)
Re: How does SNES (mode 7) rotate tile pixels internally?
Wow... I must be blind. The portion of Anomie's doc that I copy/pasted clearly shows the delta approach:
Code: Select all
X[x,y] = X[x-1,y] + A
Y[x,y] = Y[x-1,y] + C