It is currently Tue Jul 17, 2018 6:58 am

All times are UTC - 7 hours



Forum rules


Related:



Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: Sat Dec 30, 2017 11:21 pm 
Offline

Joined: Sun Dec 18, 2016 1:11 pm
Posts: 23
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...]"


Top
 Profile  
 
PostPosted: Sat Dec 30, 2017 11:37 pm 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2712
It draws pixels from left to right, top to bottom.


Top
 Profile  
 
PostPosted: Sat Dec 30, 2017 11:37 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7307
Location: Seattle
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)


Top
 Profile  
 
PostPosted: Sun Dec 31, 2017 12:31 am 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
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?


Top
 Profile  
 
PostPosted: Sun Dec 31, 2017 1:42 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7307
Location: Seattle
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.


Top
 Profile  
 
PostPosted: Sun Dec 31, 2017 8:40 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20257
Location: NE Indiana, USA (NTSC)
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.


Top
 Profile  
 
PostPosted: Sun Dec 31, 2017 12:36 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7307
Location: Seattle
Do you mean something other than aliasing?


Top
 Profile  
 
PostPosted: Sun Dec 31, 2017 1:13 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20257
Location: NE Indiana, USA (NTSC)
I mean that not only are the textures aliased, but the starting position for each scanline appears to be aliased as well.


Top
 Profile  
 
PostPosted: Sun Dec 31, 2017 4:04 pm 
Offline
User avatar

Joined: Mon Jan 23, 2006 7:47 am
Posts: 117
You mean stuff like this?

Image


Top
 Profile  
 
PostPosted: Sun Dec 31, 2017 10:09 pm 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2712
Is this something that was fixed in later console revisions? It looks like something wasn't working the way it was supposed to.


Top
 Profile  
 
PostPosted: Sun Dec 31, 2017 11:01 pm 
Offline
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 186
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


Top
 Profile  
 
PostPosted: Mon Jan 01, 2018 2:54 am 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 929
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...


Top
 Profile  
 
PostPosted: Mon Jan 01, 2018 10:29 am 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2712
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?


Top
 Profile  
 
PostPosted: Tue Jan 02, 2018 9:23 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1849
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


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: LuigiBlood, Revenant and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group