Page 1 of 1

Sprite 0 hit, scroll splits, and fineX

Posted: Mon May 01, 2017 8:32 pm
by LightStruk
Games like Super Mario Bros. and Zelda 2 put sprite 0 at the bottom-center of their status bars and then test for sprite 0 hit to know when to set a non-zero xScroll in $2005, right? In my emulator, the right half of that scanline is glitched, messing with the bottom pixels of the count counters and level numbers in SMB1, and the white bottom border of the life and magic bars in Zelda 2. The rest of the picture is fine, since I reload the X scroll values from the temp register at the end of the scanline.

I must be misunderstanding something about either the fineX register, sprite 0 hit, or both. I know that the first write to $2005 immediately overwrites fineX, and writes the new coarse X to the temp register.

1. Does fine X increment every dot, and then wrap from 7 to 0?
2. Wouldn't writing the fineX in the middle of a line make at least that line scroll unpredictably without very stringent timing?
3. If the fineX is 7 at the moment the CPU writes a 0 to the scroll register, does that cause the PPU to draw the current tile a second time, or does the coarse X increment on its own, regardless of what fineX is doing?
4. If I'm seeing a glitched half line in these games, is it because I'm somehow triggering sprite 0 hit an entire line early? If the sprite 0 hit registered one line later, then no visible glitch would occur, because the next line down is just the backdrop color from there to the right.

Thanks!

Re: Sprite 0 hit, scroll splits, and fineX

Posted: Mon May 01, 2017 8:44 pm
by tepples
Fine X does not increment. It specifies the tap off a delay line for pixels coming out of the shift register: 0 maximum delay, 7 minimum delay. If fine X is 7, and $2005 first write is written again with the same coarse X and fine X of 0, then the 7 most recently rendered background pixels will be rendered again.

See also attempts to explain fine X to a non-native speaker roughly a year ago.

Re: Sprite 0 hit, scroll splits, and fineX

Posted: Mon May 01, 2017 8:48 pm
by Drag
At any time, the PPU always has at least 8 pixels of the scanline ready to go to the screen, those 8 pixels are in a buffer, and fineX determines which of those 8 pixels is sent to the screen. However, after a pixel is drawn, instead of fineX increasing by one, the contents of the buffer itself are shifted over by one. By changing fineX in the middle of a scanline, it'll look like you're just skipping forward or skipping back.

Another important thing to keep in mind is that sprites are actually offset by one pixel downwards. That means, if the game places a sprite at (X, Y), it will physically appear at (X, Y+1), and that does indeed affect the sprite 0 test.

Re: Sprite 0 hit, scroll splits, and fineX

Posted: Tue May 02, 2017 11:36 am
by LightStruk
Thank you for helping me work this out!
tepples wrote:If fine X is 7, and $2005 first write is written again with the same coarse X and fine X of 0, then the 7 most recently rendered background pixels will be rendered again.
The scenario in SMB1 is the reverse - the fineX is 0 for the status bar, and then after the sprite 0 hit is detected, usually becomes greater than 0. So, as I scroll, the half of the scanline after the sprite 0 hit slides between 0 and 7 pixels to the left as the player walks to the right.
Drag wrote:Another important thing to keep in mind is that sprites are actually offset by one pixel downwards. That means, if the game places a sprite at (X, Y), it will physically appear at (X, Y+1), and that does indeed affect the sprite 0 test.
Yes, I already take that into account. I assumed that drawing the sprite and testing sprite 0 for an intersection both involve adding 1 to the OAM y coordinate.

Should I conclude from this that my scrolling code is correct? As it stands now in my emulator, if the CPU does write to $2005 and change fine X in the middle of a line, it affects the rest of that line. Is the problem that I'm reporting sprite 0 in the wrong place, causing the CPU to change the scroll too early?

Here's a screenshot showing the glitched line. You can see it's the second-to-last scanline of the status bar, not the last line.
Glitched line after scroll split
Glitched line after scroll split

Re: Sprite 0 hit, scroll splits, and fineX

Posted: Tue May 02, 2017 12:16 pm
by ReaperSMS
That suggests that either your sprite 0 hit flag timing is off, or your CPU timing is off.

It shouldn't get set until the pixel it actually hits on (in reality, a couple of dots later due to various pipeline shenaningans)

For SMB, that should be on the second to last line of the sprite, it then waits about a scanline and a half, then twiddles the scroll regs.

Re: Sprite 0 hit, scroll splits, and fineX

Posted: Tue May 02, 2017 7:38 pm
by LightStruk
Thanks for the help, everyone. It turns out that while I was testing the correct pixels, including the 1 line delay for the sprite position, I forgot to include that 1 line delay when I returned the hit location. Oops.

One more bug squished, countless more to go...