It is currently Sun Oct 21, 2018 5:55 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Fri Dec 08, 2017 10:48 am 
Offline
Formerly AlienX
User avatar

Joined: Fri Apr 18, 2014 7:41 am
Posts: 137
Location: Bulgaria
After successfully setting up the MMC3 and figured out how to use the IRQs, I decided to try something very few NES games attempt and change the palette mid-screen. One of the characteristics of the MMC3 scanline counter is that if the Sprites are loaded from Pattern Table 1 and the backgrounds are loaded from Pattern Table 0, the counter will trigger an IRQ at around pixel 260 of the current scanline. This means that we should be able to change at least one color without any visible graphical glitches.

So I started with a program that displays the following image:

Image

I added an IRQ, which triggers at scanline 120, containing the following code:
Code:
COW:
  LDA #$00
  STA $2001  ;Disable rendering

  LDA $2002 
  LDA #$3F
  STA $2006
  LDA #$00
  STA $2006
 
  LDA #$16
  STA $2007  ;Change Main Background color
 
  LDA #%00011110  ;Enable sprites, Enable backgrounds
  STA $2001
 
  LDA #$01
  STA $E000 ;Disable IRQ

  RTI

I also added the following code in the NMI section to change back to the original color before the next frame starts:
Code:
  LDA $2002
  LDA #$3F
  STA $2006
  LDA #$00
  STA $2006
  LDA #$21
  STA $2007

When I ran the program, I ended up with this:

Image

Now, I knew there were going to be problems. And it turns out that writing to $2006 messes with the scroll register. So I changed the IRQ code a bit and wrote to $2005, hoping to move the screen to where it should be:
Code:
COW:
  LDA #$00
  STA $2001  ;Disable rendering

  LDA $2002 
  LDA #$3F
  STA $2006
  LDA #$00
  STA $2006
 
  LDA #$16
  STA $2007  ;Change Main Background color
 
  LDA #%00011110  ;Enable sprites, Enable backgrounds
  STA $2001
 
  LDA #$00       
  STA $2005
  LDA #$78            ;Set Y Scroll position to 120
  STA $2005
 
  LDA #$01
  STA $E000 ;Disable IRQ
 
  RTI

Unfortunately, this didn't change anything at all. In an online MMC3 guide, I saw that instead of writing to $2005, they wrote to $2006, like so:
Code:
  LDA #%00011110  ;Enable sprites, Enable backgrounds
  STA $2001
  LDA #$00
  STA $2006
  STA $2006

This brings the screen down a bit:

Image

I decided to see what would happen if I put in a higher value on the second write to $2006
Code:
  LDA #%00011110  ;Enable sprites, Enable backgrounds
  STA $2001
  LDA #$00       
  STA $2006
  LDA #$78
  STA $2006

This brings the screen down more, but not by much:

Image

So, can somebody tell me what is the right way to go about this? How do I fix these problems?

Thanks!

_________________
Greetings! I'm That Bio Mechanical Dude and I like creating various stuff like movies, games and of course chiptunes!
You can check out my YouTube Channel.
You can also follow me on Twitter.


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 11:02 am 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 388
Maybe this is helpful? https://wiki.nesdev.com/w/index.php/PPU ... 2FY_scroll


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 11:27 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7677
Location: Seattle
BioMechanical Dude wrote:
One of the characteristics of the MMC3 scanline counter is that if the Sprites are loaded from Pattern Table 1 and the backgrounds are loaded from Pattern Table 0, the counter will trigger an IRQ at around pixel 260 of the current scanline. This means that we should be able to change at least one color without any visible graphical glitches.
No, it does not mean that.

It is not possible to change one color without any visible glitches. At all. Ever.

At the very best, the scanline following the palette change will have no sprites.

But even this requires absolutely zero variation in the CPU timing. And IRQs on the 6502 always have some jitter.

The window in which you can disable rendering and write to the PPU is 64 pixels long. That's 21 CPU cycles.

In order to write a new palette entry, you need to write to PPU registers a total of 7 times. That's 28 CPU cycles, of which the first seven cycles can happen early:

STa $2006 - can be significantly early - always contains $3F
STb $2001 - timed such that the final write happens on pixel 255/6/7 - disable rendering, probably contains 0 but other values are possible
STc $2006 - the palette index to update
STd $2007 - the new palette value
STe $2006 - restore correct scroll - note that the fine "y" 4s bit is always cleared when you update the scroll register using just $2006
STf $2006 - finish correcting scroll
STg $2001 - re-enable rendering

Note: There is no time here to load your three registers with new values! (other than after "a") There are a very few don't care bits in the above sequence ("b" & $E1, "c" & $E0, "d" & $C0, "e" & $C0) that help a little, but probably not enough.

So you basically have to move this entire sequence early in order to have enough time to load the registers with the values you want to write. There will be a visible glitch and you can't cover it with a sprite (because rendering will be disabled). Furthermore, there are very strict timings on when you can disable rendering without breaking sprites for the entire remaining redraw.

If there are sprites that intersect the place where you want the palette update, you only can move the entire sequence early by 16 pixels, enough time to LDx immediate twice, or LDx zeropage once. (If there are no sprites near the split, you can move the entire sequence early by 64 pixels) But the earlier you move it, the more visible the glitch.


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 1:25 pm 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7548
Location: Chexbres, VD, Switzerland
Blagg has discovered a way to get rid of jitter by abusing the $4014 sprite DMA, I don't remember the details. I don't think it's applicable to MMC3 IRQs, but rather NMI, but I might be wrong.

C64 demoes usally uses crazy hardware abuse to remove jitter entirely, and they are able to write to hardware video registers at a fully stable timing.

As for the original topic, if your goal is just to change the background colour (or even a significant part of the palette) once in the middle of the frame, for example in order to change the palette for the status bas, it's probably best to rely on a single glitchy scanline. If you want to change the background colour each line, it's possible and I did a demo about it 9 years ago, which was itself inspired by a demo by Memblers I think.


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 1:27 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 4093
Fantastic Adventures of Dizzy is one of the few games to do midscreen palette changes well.

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 2:59 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6898
Location: Canada
Since this question comes up a lot, I decided to start a wiki article on it:
Wiki: Palette change mid frame

Please feel free to edit/contribute to it.

(lidnariq: how would you feel about the Indiana Jones diagram being uploaded to the wiki?)


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 3:17 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7677
Location: Seattle
rainwarrior wrote:
(lidnariq: how would you feel about the Indiana Jones diagram being uploaded to the wiki?)
By all means!


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 3:57 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10906
Location: Rio de Janeiro - Brazil
BioMechanical Dude wrote:
I decided to try something very few NES games attempt and change the palette mid-screen.

There's a reason for that, you know. There are several limitations that apply to mid-screen palette changes, so most programmers come to the conclusion it's not worth the trouble.

It's just not possible to change even a single color without disrupting the background and/or the sprites for at least 1 scanline, so outside of status bars or title screens, cutscenes and the like, this is of little use. And I wouldn't trust emulators when testing this either, a lot of them aren't accurate enough to show the correct results for mid-screen PPU manipulations.


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 4:56 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2308
Location: DIGDUG
BioMechanical Dude, this is one of the things I have tried and failed to do.

My understanding of the PPU, is that during rendering, the PPU is auto-incrementing the PPU address, using the same bits as 2005/2006, to fetch the correct pixels to put on the screen.

If you change 2006, midscreen, it starts fetching tiles/bytes from that new address.

Also, you can't change Y scroll, midscreen, by doing 2 writes to 2005.

You can with the 2006/2005/2005/2006 trick, however.



One easy thing you CAN do, is have the top portion of the first nametable reserved for a HUD. Set the Y scroll to avoid showing this for most of the screen. Then, near the bottom of the screen, 2 quick writes of zero to 2006 (I think) should then show the HUD at the bottom.

Or something like that.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Fri Dec 08, 2017 6:16 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10906
Location: Rio de Janeiro - Brazil
dougeff wrote:
One easy thing you CAN do, is have the top portion of the first nametable reserved for a HUD. Set the Y scroll to avoid showing this for most of the screen. Then, near the bottom of the screen, 2 quick writes of zero to 2006 (I think) should then show the HUD at the bottom.

You also have to clear the fine X scroll using $2005, since $2006 doesn't affect that, otherwise the status bar will jitter left and right by up to 7 pixels as the game scrolls.


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

All times are UTC - 7 hours


Who is online

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