nesdev.com
http://forums.nesdev.com/

How does SNES (mode 7) rotate tile pixels internally?
http://forums.nesdev.com/viewtopic.php?f=12&t=16880
Page 1 of 1

Author:  ittyBittyByte [ Sat Dec 30, 2017 11:21 pm ]
Post subject:  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...]"

Author:  psycopathicteen [ Sat Dec 30, 2017 11:37 pm ]
Post subject:  Re: How does SNES (mode 7) rotate tile pixels internally?

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

Author:  lidnariq [ Sat Dec 30, 2017 11:37 pm ]
Post subject:  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)

Author:  Disch [ Sun Dec 31, 2017 12:31 am ]
Post subject:  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:

Code:
        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?

Author:  lidnariq [ Sun Dec 31, 2017 1:42 am ]
Post subject:  Re: How does SNES (mode 7) rotate tile pixels internally?

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:
⎡A B⎤ = ⎡∂X/∂x ∂X/∂y⎤
⎣C D⎦   ⎣∂Y/∂x ∂Y/∂y⎦


Assuming I'm not making a mistake. Not confident.

Author:  tepples [ Sun Dec 31, 2017 8:40 am ]
Post subject:  Re: How does SNES (mode 7) rotate tile pixels internally?

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.

Author:  lidnariq [ Sun Dec 31, 2017 12:36 pm ]
Post subject:  Re: How does SNES (mode 7) rotate tile pixels internally?

Do you mean something other than aliasing?

Author:  tepples [ Sun Dec 31, 2017 1:13 pm ]
Post subject:  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.

Author:  creaothceann [ Sun Dec 31, 2017 4:04 pm ]
Post subject:  Re: How does SNES (mode 7) rotate tile pixels internally?

You mean stuff like this?

Image

Author:  psycopathicteen [ Sun Dec 31, 2017 10:09 pm ]
Post subject:  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.

Author:  HihiDanni [ Sun Dec 31, 2017 11:01 pm ]
Post subject:  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).

Author:  93143 [ Mon Jan 01, 2018 2:54 am ]
Post subject:  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...

Author:  psycopathicteen [ Mon Jan 01, 2018 10:29 am ]
Post subject:  Re: How does SNES (mode 7) rotate tile pixels internally?

Quote:
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?

Author:  Disch [ Tue Jan 02, 2018 9:23 pm ]
Post subject:  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:
          X[x,y] = X[x-1,y] + A
          Y[x,y] = Y[x-1,y] + C

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/