Status Bar + palette swap

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
Broke Studio
Formerly glutock
Posts: 183
Joined: Sat Aug 15, 2015 3:42 pm
Location: France
Contact:

Status Bar + palette swap

Post by Broke Studio »

Hi everyone,

I've got a status bar which is working fine (with sprite 0 hit) here's the code in my NMI routine :

Code: Select all

    LDA #$00
    STA $2006
    STA $2006

    STA $2005
    STA $2005
                        ; switch CHR bank
    LDA #$03
    TAX
    STA bankTable,X
                        ; switch nametable to $2400
    LDA ctrl_var
    EOR #%00000001
    STA $2000

@WaitNotSprite0:
        LDA $2002
        AND #%01000000
        BNE @WaitNotSprite0   ; wait until sprite 0 not hit

@WaitSprite0:
        LDA $2002
        AND #%01000000
        BEQ @WaitSprite0      ; wait until sprite 0 is hit

        LDX #$10
@WaitScanline:
        DEX
        BNE @WaitScanline

                        ; switch CHR bank
    LDA #$00
    TAX
    STA bankTable,X

                        ; switch nametable back $2000
    LDA ctrl_var
    STA $2000
Everything's fine for now.

What I'd like to do is to swap some colors in the palette for the status bar, and put the original colors back for the rest of the screen.

I manage to do this BUT instead of having the $2000 nametable starting "below" the status bar, it begins "under" the status bar. Am I clear ? (not sure ...)

Here's the code I used :

Code: Select all

    LDA #$00
    STA $2006
    STA $2006

    STA $2005
    STA $2005
; PALETTE SWAP
        LDA #$3f
        STA $2006
        LDA #$01
        STA $2006
        LDA #$30
        STA $2007

        LDA #$00
        STA $2006
        STA $2006

                        ; switch CHR bank
    LDA #$03
    TAX
    STA bankTable,X
                        ; switch nametable to $2400
    LDA ctrl_var
    EOR #%00000001
    STA $2000

@WaitNotSprite0:
        LDA $2002
        AND #%01000000
        BNE @WaitNotSprite0   ; wait until sprite 0 not hit

@WaitSprite0:
        LDA $2002
        AND #%01000000
        BEQ @WaitSprite0      ; wait until sprite 0 is hit

        LDX #$10
@WaitScanline:
        DEX
        BNE @WaitScanline

    LDA #%00000001  ; rendering disabled + grayscale
    STA $2001

; PALETTE SWAP
    LDA #$3F
    STA $2006
    LDA #$01
    STA $2006
    LDA #$1A
    STA $2007

    LDA #$00
    STA $2006
    STA $2006

                        ; switch CHR bank
    LDA #$00
    TAX
    STA bankTable,X

                        ; switch nametable back $2000
    LDA ctrl_var
    STA $2000
I guess I'm doing something wrong, writing to a wrong register, or forgetting to write to a register ...
Any advice ?
My first game : Twin Dragons available at Broke Studio.
User avatar
Broke Studio
Formerly glutock
Posts: 183
Joined: Sat Aug 15, 2015 3:42 pm
Location: France
Contact:

Re: Status Bar + palette swap

Post by Broke Studio »

This is my starting point :
Screen 1
Screen 1
There's an action when I press B in front of the foutain, and the text box appear. I want to change 3 colors for the text box and then write back the original colors after the sprite 0 hit.

If I add the first palette swap, I've got this :
Screen 2
Screen 2
Which is ok.

But if I write back the original colors :
Screen 3
Screen 3
The colors are ok, but the "image" is misplaced.

Any thoughts ?


Sorry for the english ...
My first game : Twin Dragons available at Broke Studio.
tepples
Posts: 22915
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Status Bar + palette swap

Post by tepples »

After you write back the original colors, how are you setting the scroll position? You need to use the $2006-$2005-$2005-$2006 sequence.
User avatar
tokumaru
Posts: 12645
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Status Bar + palette swap

Post by tokumaru »

Mid-screen palette swaps are particularly tricky, and you should definitely not be relying on FCEU alphabet soup alone to do your testing, because it's notoriously inaccurate when it comes to raster effects.

In order to successfully modify the palette mid-screen, you have to turn off rendering. There's a very short amount of time during Hblank when the PPU is not touching $2006 or its memory, but this time is not enough to set the PPU address and update colors, so unless you turn off rendering, there will be a conflict between you trying to write colors and the PPU trying to render tiles.

Also, when rendering is off and the VRAM address is pointing to the palette area, the color being pointed gets displayed on the screen. This means that you get "rainbow" glitches if you don't time the writes to happen during hblank.

In order to keep things glitch-free, you're gonna need some blank scanlines, because you can only really do stuff during hblank. First you wait for the hblank to turn rendering off, and then you can point to the palette you want to change. Then you wait for the next hblank and blast the new colors (pre-loaded in A, X and Y), and then reset the scroll (using the $2005/6 trick) and enable rendering on the next hblank.
User avatar
tokumaru
Posts: 12645
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Status Bar + palette swap

Post by tokumaru »

The idea behind blasting the new colors from pre-loaded registers is that you can safely point to color 0 of any palette beforehand and as long as they were all initialized to the same value it will be like the PPU was rendering the background color. Then you can pre-load the 3 colors that will be changed in A, X and Y, and do this during hblank:

Code: Select all

bit $2007 ;skip color 0
sta $2007 ;write color 1
stx $2007 ;write color 2
sty $2007 ;write color 3
After the last write, the VRAM address register will conveniently be pointing to color 0 of the next palette, so there will be no glitches on screen.

Then you can do the same with another palette (each palette will cost another blank scanline) or take your time with the $2005/6 trick to set the scroll and enable rendering during the next hblank.
User avatar
rainwarrior
Posts: 8763
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Status Bar + palette swap

Post by rainwarrior »

tokumaru wrote:you should definitely not be relying on FCEU alphabet soup alone to do your testing
The usual recommendation is to test this kind of stuff against nintendulator, but test it on hardware if you can, too. (If you don't have a flash cart / NES yourself, post a ROM that already works in nintendulator and ask someone here to test it for you.)
User avatar
Broke Studio
Formerly glutock
Posts: 183
Joined: Sat Aug 15, 2015 3:42 pm
Location: France
Contact:

Re: Status Bar + palette swap

Post by Broke Studio »

OK let's see if I understand everything right here.

Before updateing any color, I'd like to turn off an on rendering without glitch (screen 3)

Actually I'm doing this :

00 : load new palette
01 : switch CHR bank
02 : set BG "page" to 1
03 : write %xxxxxx01 to $2000 to switch nametable
04 : wait for not sprite 0 hit
05 : wait for sprite 0 hit
06 : wait for hblank (end of scanline?)
07 : write $00 to $2001 to turn rendering off
08 : switch CHR bank
09 : set BG "page" to 0
10 : write %xxxxxx00 to $2000 to switch nametable
11 : write %xxx11xxx to $2001 to turn rendering on

It's ok so far, everything's working.

So now I have to update palette between points 07 and 08 right ?

07.1 : write $3FC0 to $2006
07.2 : wait for hblank
07.3 : write color to $2007
07.4 : wait for hblank (???)
07.5 : write $00 to $2006-$2005-$2005-$2006

Should be ok ?

I'll test with Nintendulator and I've got an Everdrive N8 to test on real hardware.
My first game : Twin Dragons available at Broke Studio.
User avatar
rainwarrior
Posts: 8763
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Status Bar + palette swap

Post by rainwarrior »

glutock wrote:09 : set BG "page" to 0
10 : write %xxxxxx00 to $2000 to switch nametable
This is already taken care of by the $2006-$2005-$2005-$2006 sequence.
User avatar
Broke Studio
Formerly glutock
Posts: 183
Joined: Sat Aug 15, 2015 3:42 pm
Location: France
Contact:

Re: Status Bar + palette swap

Post by Broke Studio »

Oh ok, thanks

Otherwise, it is correct ?
My first game : Twin Dragons available at Broke Studio.
User avatar
rainwarrior
Posts: 8763
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Status Bar + palette swap

Post by rainwarrior »

glutock wrote:07.4 : wait for hblank (???)
07.5 : write $00 to $2006-$2005-$2005-$2006
You don't need to wait for hblank specifically, but it does matter where in the line you turn rendering back on. If you do it before the Y increment at dot 256, I believe you'll get a partially rendered line, and then the first full line will begin rendering at Y+1. If you do it in hblank the next line will begin rendering at Y+0. (There's some notes on this in the article I linked in the previous post.)
lidnariq
Site Admin
Posts: 11716
Joined: Sun Apr 13, 2008 11:12 am

Re: Status Bar + palette swap

Post by lidnariq »

One of the previous times this came up, I marked up what the title screen for Indiana Jones and the Last Crusade was doing for its mis-screen palette changes.

Specifically on this screen, because there's no change in X fine scroll, and the positions of the gradients correspond to specific fine Y scroll values, they're able to skip the writes to $2005.
User avatar
tokumaru
Posts: 12645
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Status Bar + palette swap

Post by tokumaru »

glutock wrote:07.1 : write $3FC0 to $2006
07.2 : wait for hblank
07.3 : write color to $2007
If you write only one color to $2007, the VRAM address register will be pointing to a color other than 0, and this color will be rendered on the next scanline until you modify the address with the $2006/5/5/6 writes, which will look like a glitch. This is why I recommended you wrote 3 colors in succession, so that the address register would be pointing at color 0 of the next palette after all the writes.

If you want to update only 1 or 2 colors, replace the writes you're not doing with BIT or LD* instructions, to advance the VRAM address without modifying the colors. For example, to update only color 2:

Code: Select all

bit $2007
bit $2007
sta $2007
bit $2007
This will always ensure that when the next scanline starts, the VRAM address is pointing to a color 0.
User avatar
Broke Studio
Formerly glutock
Posts: 183
Joined: Sat Aug 15, 2015 3:42 pm
Location: France
Contact:

Re: Status Bar + palette swap

Post by Broke Studio »

I'm sorry to insist but I really want to understand.

I've attached a rom and source as an example.
If you press A, it updates a color an show a status bar using sprite 0 hit.

If I uncomment lines 350 to 353 and lines 368 to 372, it's not working anymore.

Why ?
Attachments
sprite_0_hit+palette_swap.rar
(6.9 KiB) Downloaded 558 times
My first game : Twin Dragons available at Broke Studio.
lidnariq
Site Admin
Posts: 11716
Joined: Sun Apr 13, 2008 11:12 am

Re: Status Bar + palette swap

Post by lidnariq »

When you write 0 to 2006, 2005, 2005, 2006, you're resetting the full scroll to (0,0), which is why it appears to re-scroll to the top of the screen. (Is this the problem you're referring to? If so, for now, you can just use a shorter version that writes specific non-zero values to 2006 twice, since you seem to be not changing X or Y fine scroll.)

In the future, once the bottom part is scrolling independently, you'll need to keep track of the specific values that will appear in all four registers and write them instead. (see also: nesdevwiki:PPU scrolling#Split X/Y scroll)
User avatar
tokumaru
Posts: 12645
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Status Bar + palette swap

Post by tokumaru »

lidnariq wrote:When you write 0 to 2006, 2005, 2005, 2006, you're resetting the full scroll to (0,0), which is why it appears to re-scroll to the top of the screen. (Is this the problem you're referring to? If so, for now, you can just use a shorter version that writes specific non-zero values to 2006 twice, since you seem to be not changing X or Y fine scroll.)
Just wanted to clarify this: The reason you need the set the scroll is that changing the palette modifies the VRAM address register, so you have to reconfigure the whole address again. Ideally, just writing the new address to $2006 would work fine, but unfortunately the PPU automatically clears one bit related to the vertical scroll on the first write to $2006, so you need the $2006/5/5/6 trick to fully set all the scroll bits.

I don't see anything obviously wrong with your code, but I don't have the setup to uncomment those lines and build a new ROM for further testing. When you say "it's not working anymore", what's the expected behavior and what is actually happening? Where have you tested this behavior?
Post Reply