Hblank - Palette swap mid frame, etc....

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

Hblank - Palette swap mid frame, etc....

Post by JoeGtake2 »

So...why not? May or may not implement this, but now I want to play with it. Generally, I've been preserving a subpalette for the menu area. I got the thought about possibly trying to swap the palette after the menu draw, since that area is always static, to maximize colors in gameplay area. Game has no scrolling. Started searching around the forums a bit and found some tips and tricks (and nightmares). I figured I'd toss it out there to see if anyone could help walk me through it.

I saw Tokumaru's responses about preloading A,X,Y with the values, that way you could set $2006 to $3fxx, bit the first write to %2007, then fire AXY as successive writes to $2007 to minimize time this would take. So...conceptually, I would...

1) Load palette with menubar subpal

2) Wait for sprite zero hit (which I'd put at the end of the menu bar), which would look something like:

Code: Select all

checkSpriteZnotHit:
  bit PPUSTATUS
  bvs checkSpriteZnotHit

checkSpriteZhit:
  bit PPUSTATUS
  bvc checkSpriteZhit/code]
Then wait for hblank (how?)

3) Turn rendering off, then push the three new values to the subpal

Then wait for next hblank (how?)


4) Turn rendering on and reset scroll.


That seems...too easy. Granted, I'm not trying to do any sort of scrolling or anything. Is it really that easy? I'm reading about waiting for hBlank, but haven't ever had to do that. How does one know when the hBlank fires (understand the concept of an hBlank, but don't know how to know when it fires like vBlank, or if it's even necessary). Or is it that sprite0 hit *forces* an hblank or something?

Thoughts?

Thanks!
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: Hblank - Palette swap mid frame, etc....

Post by thefox »

JoeGtake2 wrote:Then wait for hblank (how?)
There's no signal in NES which tells you that hblank has started. You're going to have to use a timed delay loop (well, it doesn't have to be a loop specifically) after the sprite 0 hit. How long a delay depends on your sprite's X position. (E.g., if your sprite is at X=200, you're going to have to wait approximately 256-200=56 pixels to reach the right side of the screen, i.e., the start of hblank. That comes down to 56/3 ≈ 18.67 CPU cycles on NTSC machines, so about 9-10 NOP instructions would do the job in this case.)

The debugger in Mesen has a pretty cool feature that lets you see the screen as its drawing (Options -> Draw Partial Frame in the debugger window). That could come in useful when debugging things like this. You can also see the PPU cycle count (0-341 -- anything over 256 means you're in hblank).
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

Re: Hblank - Palette swap mid frame, etc....

Post by JoeGtake2 »

Thanks - yeah, that's getting into stuff I haven't really pushed into yet. Hm....

Alright, i could draw this sprite at, say, 240...then i'd have 16 pixels...5.3 cpu cycles...2-3 NOP instructions...

And then at that point, do the steps mentioned...but no need to wait until the next hblank in step 3, as it should all fit in that tiny hblank, correct?



Again...that kinda feels too easy...
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Hblank - Palette swap mid frame, etc....

Post by tepples »

Sprite 0 hit happens at a certain horizontal position on the scanline, and hblank begins at x=256. Each CPU cycle is worth three pixels. So if you have sprite 0 hit at (say) x=76, that means 256 - 76 = 180 pixels or 60 cycles from that point to the start of hblank. The end of your waiting loop will probably use 5 to 11 of those cycles.

Code: Select all

  lda #$C0  ; $80 is vblank; $40 is sprite 0
  s0wait:
    ; The read and branch total 7 cycles, with the actual PPU port
    ; read on the fourth cycle of 7.
    bit PPUSTATUS
    beq s0wait

  ; At this point, one of two things has happened: either sprite 0 hit,
  ; or sprite 0 missed and vblank began instead.  Occasionally
  ; sprite 0 may miss in lag frames or in the first frame before the
  ; OAM DRAM controller becomes stable.  Distinguish these and skip
  ; mid-frame effects if it missed.
  bmi sprite0_missed

  ; Now we're 5 to 11.67 cycles (15 to 35 pixels) after sprite 0.
  ; Do sprite 0 stuff.
So there are two ways to buy enough cycles to set up the PPU port write sequence to happen during horizontal blanking: sprite 0 on the left side of the same scanline or on the right side of the previous scanline.
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

Re: Hblank - Palette swap mid frame, etc....

Post by JoeGtake2 »

Awesome guys...good info!

Yeah, tepples, my thought was last pixel of former scanline.

Any suggestion as to generally *where* to place this in relation to other code in order to minimize potential for gremlin chaos? haha
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Hblank - Palette swap mid frame, etc....

Post by tepples »

There's a quirk of the PPU's pixel pipeline such that a hit on x=255 (and only x=255) won't register. If you're looking to use a whole line to prepare, put the overlap at x=252-254 or the like.
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

Re: Hblank - Palette swap mid frame, etc....

Post by JoeGtake2 »

So, I'm getting hung up right out of the gate.

In my NMI, rendering is off. This code just causes the game to hang indefinitely:

Code: Select all


WaitNotSprite0:
    LDA $2002
    AND #%01000000
    BNE WaitNotSprite0

WaitSprite0:
    LDA $2002
    #%01000000
    BEQ WaitSprite0

    LDX #$10 ;; arbitrary - variable
WaitScanline:
    DEX
    BNE WaitScanLine

I'd delved deeper but kept freezing, so i figured I'd just start whittling away. It's the WaitSprite0 that causes it to hang. I also made absolute sure, in case it made a difference, that Sprite0 was being drawn on the screen (by literally drawing it just prior to this code). It still froze, gray screen. This is without any sprite0 effect...just the above code inserted in the NMI just prior to palette loads in otherwise working code.

Any thoughts? Thanks!
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Hblank - Palette swap mid frame, etc....

Post by tokumaru »

This has nothing to do with the hanging, but here's a quick tip: to reduce the latency when detecting sprite 0 hits, use BIT instead of AND to test the flag:

Code: Select all

WaitSprite0:
  BIT $2002
  BVC WaitSprite0
BIT copies bits 7 and 6 of the read value to flags N and V, respectively, so you can test those bits more quickly. But even when you need to test bits other than 6 and 7, BIT still results in a shorter loop since you can preload the bit mask, reducing the latency anyway:

Code: Select all

  LDA #%00100000
WaitSpriteOverflow:
  BIT $2002
  BEQ WaitSpriteOverflow
This helps keeping your raster effects timed from sprite hits or overflows more stable.

As for the hanging, you do know that a sprite 0 hit only happens if an opaque sprite pixel overlaps an opaque background pixel, right? Transparent pixels (color 0) don't count.
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

Re: Hblank - Palette swap mid frame, etc....

Post by JoeGtake2 »

Actually, I did know that, but I was absently not thinking about the fact that only my MainGame state was drawing sprite 0...forgot to check the game state before doing this call. Oops! Thanks for the tip. Now let's see if I can get it working :-)
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Hblank - Palette swap mid frame, etc....

Post by rainwarrior »

I would actually recommend testing both vblank and sprite 0 hit together in the second wait loop:

Code: Select all

	lda #%11000000
	:
	bit $2002
	beq :-
If done correctly it should only ever exit the loop due to sprite 0 hit, but vblank is an appropriate fall-back in case some disaster causes that sprite 0 to miss. The fallback result wouldn't be pretty, probably it will drop to 50% framerate and be scrolled completely wrong, etc. but the game won't lock up, and if the player can manage to get themselves where it gets restored, they can get back on track without having to abandon and reset.

Just in case, might also be worth saying that you can have "opaque" pixels hit that are the same colour as the background, they just can't be colour index 0. Also the sprite background priority bit doesn't affect the hit test so you can put it "under" the background to hide it as well.
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

Re: Hblank - Palette swap mid frame, etc....

Post by JoeGtake2 »

I'm making a bit of progress...right now, in just trying to successfully read a hit without glitching or locking up.

I can visibly see where I'm getting a split (right now, ugly horizontal line that flickers...i'm sure that's a timing issue) but unfortunately, the bigger problem is that:

a) I get a push (like the scroll is getting messed up...can mess with that a bit later)
b) it seems like everything *above* the line is drawing from the wrong table, even though there haven't been any writes to 2000 (and even hard-writing something just before the sprite zero check doesn't help this).

Any ideas?


**** Actually, not sure what magic just happened but just going back through seemed to fix things. Huh. Ok. I think I'm right there.

********** Nope, nevermind. Here's what's happening.

(rendering is off)

Code: Select all



;; checks game state...if not a screen where sprite 0 is drawn, skip this code

 WaitSpriteNot0:
     BIT $2002
     BVS WaitSpriteNot0

    LDA #%11000000
checkSprite0:
    bit $2002
    BEQ checkSprite0

;;;;;; some arbitrary numbers in a dummy loop here to try to get to the end of the scanline
 ;;;;; should change a color in the last sub palette.
;;;;;; this works with no issue if I don't do the sprite zero check
;;;;; so something with the sprite zero check is the problem?
DoSingColorSwap:
    LDA $2002
    LDA #$3f
    STA $2006
    LDA #$0c
    STA $2006
    LDA #$30
    STA $2007




If I skip the sprite 0 loop and just do the single color swap, no problem. Work's just fine, for the entire screen. But with the sprite 0 hit and trying to separate the screen, the color does not change, I get *animated junk* at the top, scroll value was pshed off, and it seems that in some spots it is drawing the right value (f5, which should be a blank tile) but from the wrong pattern table. I tried different versions of the sprite zero check discussed here. All with the same result.

Currently, i am drawing sprite zero at #$d0 if it helps (and it is definitely colliding with background).
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Hblank - Palette swap mid frame, etc....

Post by tokumaru »

JoeGtake2 wrote:(rendering is off)
I find this statement a bit confusing, because rendering must be on for the sprite hit to happen, and off for the palette update to happen, so rendering must be turned off after the hit and before the palette update. Is this what you're doing? Also, after the update, the scroll has to be restored (since you trashed it when updating the palette), and rendering turned back on.

Can you show the complete code for the split, even if it contains temporary junk?
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

Re: Hblank - Palette swap mid frame, etc....

Post by JoeGtake2 »

Sorry - that was a misplaced note to myself. Yes, rendering is on for the eval.

Essentially, I load the palettes (all) then turn back on rendering, do the checks for sprite 0 hit, turn rendering back off, and then load the *other* palette* once the hit fires. I have tried zeroing out $2005 afterwards to no avail.

Right now, it looks like I'm getting closer, but my scroll is still off. Hm.
User avatar
Broke Studio
Formerly glutock
Posts: 181
Joined: Sat Aug 15, 2015 3:42 pm
Location: France
Contact:

Re: Hblank - Palette swap mid frame, etc....

Post by Broke Studio »

You seem to be on the right path but this post may help you : viewtopic.php?f=2&t=13188
My first game : Twin Dragons available at Broke Studio.
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

Re: Hblank - Palette swap mid frame, etc....

Post by JoeGtake2 »

Yeah, I looked at that for a lot of reference. Everything seems fine, except for the sprite 0 hit. If I take the sprite zero hit out, i can change the palettes no problem. But as soon as i do the sprite 0 hit stuff, I crash and get all sorts of funky things happening with scroll. Hm.
Post Reply