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

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 »

Stupid question : are you using a fully transparent sprite ?
My first game : Twin Dragons available at Broke Studio.
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 »

glutock wrote:Stupid question : are you using a fully transparent sprite ?
I mentioned the transparency thing and he said he was aware of it, so I guess this isn't the problem.

Here's another idea: are you enabling rendering on the first frame when the hit is supposed to happen during vblank? If you're not waiting for vblank to turn rendering on, that may cause the background to shift down for a frame, and that may prevent the hit from happening.
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 »

JoeGtake2 wrote:I have tried zeroing out $2005 afterwards to no avail.
Setting scroll mid-frame requires the full $2006-2005-2005-2006 cycle. $2005 alone only updates the X scroll; the Y stored in the temporary scroll register until the end of vblank where it finally gets copied in. (You might get away with just two writes to $2006 though, if you're just trying to use 0,0.)
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

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

Post by JoeGtake2 »

So...I've gone back to a much earlier (read: simple) version of the code. After a lot of trial and error, I found that putting in some flags to make sure that the nametable AND zero sprite are drawn prior to checking for the hit got me past the *freezing* in that version. It's possible that a sprite-clear function in my current version of the code at time of screen load is causing the main issue...though I thought I disabled that. Anyhow...it looks like it's not necessarily the method implementation that's the problem, but something that is countering it somewhere in code (my guess, just a single frame where sprite zero is being *cleared* in my object drawing loop, and drawn off screen).

However, things still got weird when I tried to fix the scroll. Any writes to $2006 seem to botch my CHR-Ram graphics load. And zeroing $2006 / $2005 / $2005/ $2006 (in any combination of order, via experimenting) still did not correct the scroll properly (changed it, but still was not in the right place, and like I said, it seemed to stop my chr-Ram graphics from loading / loaded in null values). If I had to venture a guess, I would think maybe the first NMI was being fired in the middle of the graphics load and that I should similarly flag whether or not all graphics were loaded before checking sprite zero hit? Maybe the vblank was striking between 2006 reads elsewhere causing chaos?

**** Update - never mind...found this issue. It had to do with soft 2001 update conditional...just had to move this inside the conditional.
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

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

Post by JoeGtake2 »

Ok - now I'm not *that far* away from implementing this. I'm circling the drain and generally am able to substitute values for the bottom half to get different palettes from the menu bar. I'm having trouble (presumably) with getting the hblank timing right, and still having slight issues getting the scrolling right. Perhaps filling in these gaps in my understanding will help me get this fully functional. Mind you, a lot of this is from your collective posts, searching the forums, and trial and error, so there may be some ugliness or redundancy here...this is more the blunt instrument approach, and now I need someone with a shaper set of proverbial tools.

First I want to get things lining up right, and then I'll worry about protections against sprite zero misses.

In the vBlank, I take care of the initial run through the palettes. After which, the code looks something like this:

Code: Select all


    LDA readyToCheckSpr0 ;; making sure nametable is loaded and sprties are drawn before checking for a sprite 0 hit
                                         ;; early vBlanks were happening before nametable / sprites were being loaded / drawn
                                          ;; causing hit to fail and the game freezing.
    BEQ skipWaitingForSpriteZeroHit
;; turn on rendering to check for sprite 0 hit
    LDA #%000111110
    STA $2001
    LDA #%10010000
    STA #2000
    
;; check for sprite 0 hit
WaitNotSprite0:     ;; I know there is a better way to do this as described...again, this is blunt-instrumenting
    LDA $2002
    AND #%01000000
    BNE WaitNotSprite0

WaitSprite0:        ;; I know there is a better way to do this as described...again this is blunt-instrumenting
    LDA $2002
    AND #%01000000
    BEQ WaitSprite0

;;;;; sprite 0 is now detected (it is at #$b0 - i think the first pixel hit is a few pixels later), so now wait until end of scanline for beginning of hblank
    LDX #$08 ;; arbitrary number here as to how long it takes to get to end of scanline
WaitScanline:
    DEX
    BNE WaitScanline:

;;;;;;;; presumably, now we are in hBlank, if the above wait was timed right.
;;;;;;; my guess is I should put the writes to 2006 and turning off rendering *before* waiting for the scanline so less is done
;;;;;; during the hblank, and this can substitute for some of the loop time...is that sound?

    bit $2002
    LDA #$3F
    STA $2006
    LDA #$00
    STA $2006

    LDA #$00
    STA $2001
    STA $2000

;;;;;;;; change the palette
    bit $2007
    bit $2007    
    bit $2007
    LDA #$18 ;; brown
    STA $2007  ;;; now the last value in the first subpalette should be *brown*

;;;; now we have to set 2006/2005/2005/2006 to match the scroll position...
;;;; this part has been really tricky.  I'm not sure exactly where or what to adjust.
;;; for now, I'm doing two writes to $2006, i've tried sandwiching two writes to $2005 between, I've tried many
;;;; arbitrary values but am not ever really getting results I expect. 
;;; this gets me close to lined up:

    LDA #$00
    STA $2006
    LDA #$c8
    STA $2006

;;; now that scroll is lined up, wait for the hblank again to continue on?
   LDX #$08 ;; i know this value will have to be played with to get it right
WaitScanLine2:
    DEX
    BNE WaitScanLine2

skipWaitingForSpriteZeroHit: ;; if the nametable / sprite 0 were not loaded/drawn yet, from above.

Again, this gets me super close. You can see in the image the brown - it is replacing the *peach* color spot (in the topmost part of the screen, peach is subpal0, color 3...below brown is subpal0 color3...Eureka, it works!
but...not quite there...)
close.png
close.png (3.42 KiB) Viewed 4292 times
So...the immediate questions become, how do I better finely adjust the y-scroll (played around with writes to $2005...this didn't seem to work, so I suppose I'm doing something wrong), and also, how to adjust my scan-line waits correctly to properly get to start of hblank?

Additionally - I liked the idea of loading A,X,andY with the color values and firing them off, but in this context I don't see how that would be possible since I'm using two of those values in the scanline wait for hblank loop. Would love thoughts on that.
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 »

One thing that's important to note is that hblank is really, really short, and there's no time to do everything in one go without glitches either in the scanline before or the one after. You may need 2 or 3 scanlines to accomplish what you want cleanly.

From the screenshot it looks like you're enabling rendering way too long after hblank, well into the visible picture, which is why the graphics for that scanline are shifted.

The simplest solution would be to use 1 hblank to turn rendering off, the next to write the colors, and a third one to enable rendering (after setting the scroll during the scanline).

The challenge of changing the palette mid-screen is precisely the fact that it can only be done during hblank (or there'll be "rainbows"), and that 1 hblank is way too short to do anything useful, so you absolutely do need a "break" in the graphics so you can spread the work across several scanlines. This makes the effect unfeasible in the middle of busy images.
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

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

Post by JoeGtake2 »

Yeah, I figured I'm was cramming too much in there. I had a feeling that was one of the problems...

So then the solution would (or could) be something like...

Code: Select all

;;;;;; HBLANK WAIT 1
   LDX #$08 ;; i know this value will have to be played with to get it right
WaitScanLine:
    DEX
    BNE WaitScanLine

;;;;;;TURN RENDER OFF

;;;;; HBLANK WAIT 2
   LDX #$08 ;; i know this value will have to be played with to get it right
WaitScanLine2:
    DEX
    BNE WaitScanLine2

;;;;;;;; update colors

HBLANK WAIT 3
   LDX #$08 ;; i know this value will have to be played with to get it right
WaitScanLine3:
    DEX
    BNE WaitScanLine3

;;;;; Turn on rendering / fix scroll

Which would give me two *black scanlines*, correct? I mean, theoretically this would be acceptable - the bottom most row in the HUD, the topmost row in the playfield...would be a solid black line that would be fairly negligible.

Still two questions:

1) Is there a better way to do the hblank waiting?

2) How to correctly adjust the scroll, if I'm indeed doing something wrong (keeping in mind that the game has no scrolling).


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 »

That's about right.
JoeGtake2 wrote:;;;;; Turn on rendering / fix scroll
Fix the scroll first (preferably *before* the hblank), turn on rendering second.
1) Is there a better way to do the hblank waiting?
Your loops on X are indeed too freaking coarse if that's all you're using. At 5 cycles per loop iteration you're working in increments of 15 pixels, not great. You can do the bulk of the waiting like this, but add some "padding" afterwards with single cycle precision (increments of 3 pixels). Also, these timed loops are incompatible with PAL consoles, where scanlines are ~7 cycles shorter, so you have to account for that if you plan on making a multi-region program.
2) How to correctly adjust the scroll, if I'm indeed doing something wrong (keeping in mind that the game has no scrolling).
If you want to set the scroll to a tile boundary (which should be enough for status bars), simply writing the NT address of that tile (minus $2000) to $2006 will do the trick. If you need pixel-perfect precision, however, then you'll need to master the dreaded $2006/5/5/6 trick (it's quite simple once you do get it).
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

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

Post by JoeGtake2 »

Cool. For single cycle increments, just load dummy values into the accumulator or something? Never really done cycle counting like this, not sure what opcodes = how many cycles, etc. Best practice? Is there a source with this so I could evaluate how many cycles each part of this is taking? I'd imagine that would take at least a *little* of the arbitrary guess work out of what I'm currently doing...haha.

I imagined some of this would have to be re-figured for PAL version, but would likely be a matter of simply adjusting values to compensate?
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

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

Post by lidnariq »

JoeGtake2 wrote: bit $2002 ; 4
LDA #$3F ; 2
STA $2006 ; 4
LDA #$00 ; 2
STA $2006 ; 4

LDA #$00; 2
STA $2001 ; 4
STA $2000 ; 4

;;;;;;;; change the palette
bit $2007; 4
bit $2007; 4
bit $2007; 4
LDA #$18; 2
STA $2007; 4

;;; this gets me close to lined up:
LDA #$00; 2
STA $2006; 4
LDA #$c8; 2
STA $2006; 4 -> 56cy, 168pixels, twice as long as the actual hblanking period
You don't have the time to do all this extra stuff during a mid-screen palette change if you can't tolerate a blank line.

Here's my annotated visual description of how the title screen for Indiana Jones and the Last Crusade does it.

Note that that loop is
1- exactly timed, so there's no poll loop for sprite 0
2- uses A, X, and Y
3- reloads as little as possible
4- doesn't use 2006/5/5/6 but just 2006/6
JoeGtake2
Posts: 333
Joined: Tue Jul 01, 2014 4:02 pm

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

Post by JoeGtake2 »

Thanks for posting that - I think, due to the fact that other things will be going on (and I'm perfectly ok with a single black line...even two wouldn't be so horrible, since it bottoms out with a black line for separation as it is) separating the menu from the action, the looser i could be with the already tight timing, the better.

I'm doing some research on opcodes and their cycle count. Tokumaru suggested padding with single-cycle precision (so I could be finely adjusting the hblank wait time to 3 pixels rather than 15 pixel increments a time in my loop...totally understand that). However, after quick researching, I don't see any operations that would take a single cycle. The smallest seems to be two, so how would I do this?
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

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

Post by lidnariq »

STA address,X/Y always takes 5 cycles instead of 4 ... although X or Y has to be a known value so that you can know the resulting address at build-time .
They also cause an extra dummy read, from address+X or address+X-256, so can't be used safely to slow a write to $2007
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 »

JoeGtake2 wrote:1) Is there a better way to do the hblank waiting?
The X counter loop is okay to do the bulk of the cycles but the end of it, and then you can use a couple of finer instructions at the end to finish it off with an exact number of cycles.

There is no 1 cycle wait (but you can do without).

If waiting 2 cycles, NOP is the best choice. No side effects.

For 3 cycles there's a lot of options but they all have side effects. BIT ZP only affects flags, STA ZP only overwrites one byte in memory, etc.

I use this reference constantly: http://www.obelisk.me.uk/6502/reference.html

All branch instructions are problematic (but not impossible) for cycle counting: different cycle count if branch taken, additional different cycle count if branch goes to a new page, etc.. When writing cycle timed code, you should try to protect yourself against accidental page crossings: https://forums.nesdev.com/viewtopic.php?f=2&t=14622

Finally, using breakpoints in a debugger that can count cycles is a good idea. You can use it to check your work, or even do the counting for you.
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 »

JoeGtake2 wrote:The smallest seems to be two, so how would I do this?
If all you had was 2 and 3 cycle instructions:

2 = 2
3 = 3
4 = 2 + 2
5 = 2 + 3
6 = 2 + 2 + 2 = 3 + 3
7 = 2 + 2 + 3
etc...
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

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

Post by lidnariq »

Post Reply