How does SNES (mode 7) rotate tile pixels internally?

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
ittyBittyByte
Posts: 24
Joined: Sun Dec 18, 2016 1:11 pm

How does SNES (mode 7) rotate tile pixels internally?

Post by ittyBittyByte » Sat Dec 30, 2017 11:21 pm

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...]"

psycopathicteen
Posts: 2934
Joined: Wed May 19, 2010 6:12 pm

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by psycopathicteen » Sat Dec 30, 2017 11:37 pm

It draws pixels from left to right, top to bottom.

lidnariq
Posts: 9384
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by lidnariq » Sat Dec 30, 2017 11:37 pm

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)

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by Disch » Sun Dec 31, 2017 12:31 am

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:

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)
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?

lidnariq
Posts: 9384
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by lidnariq » Sun Dec 31, 2017 1:42 am

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?
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.

i.e.

Code: Select all

⎡A B⎤ = ⎡∂X/∂x ∂X/∂y⎤
⎣C D⎦   ⎣∂Y/∂x ∂Y/∂y⎦
Assuming I'm not making a mistake. Not confident.

tepples
Posts: 21973
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by tepples » Sun Dec 31, 2017 8:40 am

lidnariq wrote:
Disch wrote:Would the delta approach have rounding errors?
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.
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
Posts: 9384
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by lidnariq » Sun Dec 31, 2017 12:36 pm

Do you mean something other than aliasing?

tepples
Posts: 21973
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by tepples » Sun Dec 31, 2017 1:13 pm

I mean that not only are the textures aliased, but the starting position for each scanline appears to be aliased as well.

creaothceann
Posts: 224
Joined: Mon Jan 23, 2006 7:47 am
Location: Germany
Contact:

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by creaothceann » Sun Dec 31, 2017 4:04 pm

You mean stuff like this?

Image
My current setup:
Super Famicom ("2/1/3" SNS-CPU-GPM-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10

psycopathicteen
Posts: 2934
Joined: Wed May 19, 2010 6:12 pm

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by psycopathicteen » Sun Dec 31, 2017 10:09 pm

Is this something that was fixed in later console revisions? It looks like something wasn't working the way it was supposed to.

User avatar
HihiDanni
Posts: 186
Joined: Tue Apr 05, 2016 5:25 pm

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by HihiDanni » Sun Dec 31, 2017 11:01 pm

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

93143
Posts: 1146
Joined: Fri Jul 04, 2014 9:31 pm

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by 93143 » Mon Jan 01, 2018 2:54 am

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...

psycopathicteen
Posts: 2934
Joined: Wed May 19, 2010 6:12 pm

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by psycopathicteen » Mon Jan 01, 2018 10:29 am

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)
I think I found the reason why. Was this done just to save a couple pennies?

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Re: How does SNES (mode 7) rotate tile pixels internally?

Post by Disch » Tue Jan 02, 2018 9:23 pm

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

Post Reply