It is currently Sun May 26, 2019 2:53 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 24 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Fri Jan 04, 2019 7:07 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11357
Location: Rio de Janeiro - Brazil
pwnskar wrote:
If I opt for not having any scrolling at all, perhaps this could be a feature I would be able to pull off?

Your case is not so bad because you can have a "break" between the status bar and the gameplay area where to do the dirty work, you just need to time things really well if you want to prevent visual glitches. There's a correct time to turn sprites off, a correct time to modify the VRAM address, a correct time to turn rendering back on... It has to be very well planned and executed in order to look right.

Quote:
I've managed to set the coarse Y scroll right by using the sprite-0 Y value divided by 8, though I seem to have to adjust it a bit by subtracting #2 before dividing.

Well, sprites are delayed by one scanline (an OAM Y coordinate of 45 will cause the sprite to show on scanline 46), and the new scroll value should only be set for the scanline after the one where the hit happens, so 2 scanlines of difference sounds about right.

Quote:
I also tried applying some fine Y scroll and it worked just as you explained. How would one go about solving the issue of that missing bit? Is it impossible on a standard UNROM mapper?

You do 4 register writes, like this:

Code:
$2006: ****NN** (name table)
$2005: YYYYYyyy (coarse and fine Y scroll)
$2005: XXXXXxxx (coarse and fine X scroll)
$2006: YYYXXXXX (mix of coarse X and Y)

The idea is to get the troublesome write out of the way first, using it to set only the name table. The other bits function as I told you before, but it's a waste of time to use them because later writes will affect all those bits, so I asterisked the bits that don't matter.

Then you set the Y and X scroll via $2005, almost as you'd do during vblank except that Y goes first, then X. This is because $2006 and $2005 share the toggle that selects between the first and the second write, and the $2006 write we did before changed that toggle, so the PPU thinks we're writing to $2005 the second time, so Y goes first. The toggle changes, and then the PPU expects the X scroll.

Finally, the second $2006 write works as I explained before. Even though X and Y have already been set, the scroll is still in a temporary PPU internal register, and the second $2006 write has the important task of copying that to the actual address register, otherwise the new scroll won't take effect until the next frame. So you need to combine the coarse X and Y scroll correctly for that last write to work.

As for timing, this can be done at any time when rendering is off, but when rendering is on (e.g. scroll splits for parallax effects) the first 2 writes can happen during the scanline, and the last 2 as close to the beginning of hblank as possible, so you may want to buffer those last 2 values in advance so you can store them in quick succession when hblank starts.

Quote:
Oh, and how do I know when I'm in h-blank, so that I can make sure to only do my palette updates at that time?

You count cycles starting from an event that happens at a known time. In this case, the reference event is the sprite zero hit, because you know when that happens. You have to count the cycles of each instruction from that point on to predict when things will happen as the PPU runs in parallel.

Each pixel is 1 PPU cycle, the PPU is 3 times faster than the CPU in NTSC, 3.2 times in PAL. This means that in the time it takes for the lda #$20 instruction to run (2 CPU cycles), the PPU will draw 6 pixels. An scanline has 256 visible pixels, plus 85 "pixels" of hblank (about 28.3 CPU cycles in NTSC). The PPU is still doing work during hblank when rendering is on though, so only some of that time is available for specific tasks when that's the case.


Top
 Profile  
 
PostPosted: Sat Jan 05, 2019 1:25 am 
Offline

Joined: Tue Oct 16, 2018 5:46 am
Posts: 93
Location: Gothenburg, Sweden
tokumaru wrote:
Finally, the second $2006 write works as I explained before. Even though X and Y have already been set, the scroll is still in a temporary PPU internal register, and the second $2006 write has the important task of copying that to the actual address register, otherwise the new scroll won't take effect until the next frame. So you need to combine the coarse X and Y scroll correctly for that last write to work.

So for that last $2006 write, do I understand it correctly that it should be formatted the same way as the 2nd write to $2006 in the previous example?
tokumaru wrote:
As for setting the scroll mid-frame, it can mostly be done with 2 PPUADDR ($2006) writes, in the following format:
Code:
Code:
1st:     2nd:
0yyyNNYY YYYXXXXX

XXXXX: coarse X scroll (0 to 31);
YYYYY: coarse Y scroll (0 to 30);
NN: name table (0 to 3);
yyy: fine Y scroll (0 to 7);

I'll try implementing all this in my test rom to see if I can get the scroll right and minimize the visual glitches.


Top
 Profile  
 
PostPosted: Sat Jan 05, 2019 1:42 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11357
Location: Rio de Janeiro - Brazil
pwnskar wrote:
So for that last $2006 write, do I understand it correctly that it should be formatted the same way as the 2nd write to $2006 in the previous example?

Yup. And the first $2006 write really only needs the name table bits to be in the correct position, because everything else gets overwritten.

Quote:
I'll try implementing all this in my test rom to see if I can get the scroll right and minimize the visual glitches.

I have written code for the scroll change itself several years ago: viewtopic.php?p=64111#64111

Feel free to use that as reference if you'd like.


Top
 Profile  
 
PostPosted: Sat Jan 05, 2019 2:32 am 
Offline
User avatar

Joined: Fri Jan 24, 2014 9:05 am
Posts: 187
Location: Hungary
A slightly less complicated, but also less effective way to "get more colors" is to use the PPU color emphasis bits. It's not nearly as useful as an actually changed palette, but it lets you get a few more tones (or a few washed-out colors by combining them with the grayscale bit) out of your already existing palette without having to do anything other than a write to $2001 (which is also not bound by whether the PPU is rendering or not).


Top
 Profile  
 
PostPosted: Sat Jan 05, 2019 7:25 am 
Offline

Joined: Tue Oct 16, 2018 5:46 am
Posts: 93
Location: Gothenburg, Sweden
za909 wrote:
A slightly less complicated, but also less effective way to "get more colors" is to use the PPU color emphasis bits. It's not nearly as useful as an actually changed palette, but it lets you get a few more tones (or a few washed-out colors by combining them with the grayscale bit) out of your already existing palette without having to do anything other than a write to $2001 (which is also not bound by whether the PPU is rendering or not).

Yeah, that thought crossed my mind too and I'll definitely try it out at some point in the actual game. :)
My use case right now would require totally different colors in some slots though. My ultimate goal would be to have a palette for the status bar totally independent from the background of the level but I realize that would require a lot of scanlines and thus might not be feasible, depending on how I decide to layout the attributes of the status bar.
I'm thinking the sprite-0 and palette writes could be triggered a couple of scanlines before the end of the status bar. If I make sure to either leave some empty space at the bottom of the status bar or just make sure to not write to any colors that happen to be on those scanlines, maybe I could get away with a complete swap...?
Anyways, I'm getting way ahead of myself.


Top
 Profile  
 
PostPosted: Sun Jan 06, 2019 5:33 am 
Offline

Joined: Tue Oct 16, 2018 5:46 am
Posts: 93
Location: Gothenburg, Sweden
So now I have the coarse and fine scroll working thanks to you tokumaru! :beer:

Here's an updated test rom. I get a lot of rainbow colors and even some twitching y scroll in PAL mode. Now I'll try to count cycles so that I can do most writes within a couple of h-blanks.


Attachments:
sprite-0_test_04.nes [24.02 KiB]
Downloaded 71 times
Top
 Profile  
 
PostPosted: Sun Jan 06, 2019 10:48 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11357
Location: Rio de Janeiro - Brazil
If you want the same code to work on both NTSC and PAL, you'll have to compensate for the timing differences between the consoles. The wiki has an article about detecting the TV system used by the console, which you do once during startup to setup variables that you can use to make decisions later.

An NTSC scanline is 341/3 = 113.666 cycles, while a PAL scanline is 341/3.2 = 106.5625 cycles, do you need to wait about 7 cycles more on NTSC per scanline.


Top
 Profile  
 
PostPosted: Mon Jan 07, 2019 3:36 am 
Offline

Joined: Tue Oct 16, 2018 5:46 am
Posts: 93
Location: Gothenburg, Sweden
tokumaru wrote:
If you want the same code to work on both NTSC and PAL, you'll have to compensate for the timing differences between the consoles. The wiki has an article about detecting the TV system used by the console, which you do once during startup to setup variables that you can use to make decisions later.

An NTSC scanline is 341/3 = 113.666 cycles, while a PAL scanline is 341/3.2 = 106.5625 cycles, do you need to wait about 7 cycles more on NTSC per scanline.

I've been using the NTSC/PAL detection from famitone2 for my main project but the one you linked from the wiki seems to be able to detect the dendy famiclone as well, which is interesting.

Working on the test rom, I've gotten 4 colors loaded at the cost of 2 transparent scanlines and some minimal glitching to the far right of those. I've only concerned myself with NTSC so far.

I guess I'll try to see if I can manage to turn off rendering, load 1 color, set scroll and turn rendering back on within 1 h-blank. I think the wiki says it's not really possible and maybe you guys already have too, but it will be fun to try. :)

Here's my latest test rom.


Attachments:
sprite-0_test_05.nes [24.02 KiB]
Downloaded 68 times
Top
 Profile  
 
PostPosted: Mon Jan 07, 2019 6:44 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11357
Location: Rio de Janeiro - Brazil
pwnskar wrote:
I guess I'll try to see if I can manage to turn off rendering, load 1 color, set scroll and turn rendering back on within 1 h-blank.

Do you mean without blanking any scanlines? Definitely not possible. Here are all the writes you'd need to do, in the simplest possible case (no fine Y):

$2001 (disable rendering)
$2006 x2 (set VRAM address)
$2007 (update color)
$2006 x2 (set scroll without fine Y)
$2001 (enable rendering)

That's 7 writes, at 4 cycles each the total is 28 cycles. That alone would already take the entirety of the NTSC hblank, and more than the PAL hblank. And that's just counting the *writes*, you'd still have to *load* the values that would be written.

Also note that even though the PPU is not drawing pixels during hblank, that doesn't mean it's doing nothing. This wiki page explains everything that the PPU does. The first part of hblank (75%) is spent fetching sprite patterns for the next scanline, and the second part (25%) is spent fetching the first 2 tiles for the next scanline. If rendering is turned off during this time, this will definitely affect sprites and the background on the following scanline.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 24 posts ]  Go to page Previous  1, 2

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 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