Hblank - Palette swap mid frame, etc....
Moderator: Moderators
- Broke Studio
- Formerly glutock
- Posts: 181
- Joined: Sat Aug 15, 2015 3:42 pm
- Location: France
- Contact:
Re: Hblank - Palette swap mid frame, etc....
Stupid question : are you using a fully transparent sprite ?
My first game : Twin Dragons available at Broke Studio.
Re: Hblank - Palette swap mid frame, etc....
I mentioned the transparency thing and he said he was aware of it, so I guess this isn't the problem.glutock wrote:Stupid question : are you using a fully transparent sprite ?
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.
- rainwarrior
- Posts: 8734
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Hblank - Palette swap mid frame, etc....
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 wrote:I have tried zeroing out $2005 afterwards to no avail.
Re: Hblank - Palette swap mid frame, etc....
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.
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.
Re: Hblank - Palette swap mid frame, etc....
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:
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...)
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.
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.
but...not quite there...)
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.
Re: Hblank - Palette swap mid frame, etc....
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.
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.
Re: Hblank - Palette swap mid frame, etc....
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...
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!
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
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!
Re: Hblank - Palette swap mid frame, etc....
That's about right.
Fix the scroll first (preferably *before* the hblank), turn on rendering second.JoeGtake2 wrote:;;;;; Turn on rendering / fix scroll
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.1) Is there a better way to do the hblank waiting?
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).2) How to correctly adjust the scroll, if I'm indeed doing something wrong (keeping in mind that the game has no scrolling).
Re: Hblank - Palette swap mid frame, etc....
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?
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?
Re: Hblank - Palette swap mid frame, etc....
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.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
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
Re: Hblank - Palette swap mid frame, etc....
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?
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?
Re: Hblank - Palette swap mid frame, etc....
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
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
- rainwarrior
- Posts: 8734
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Hblank - Palette swap mid frame, etc....
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.JoeGtake2 wrote:1) Is there a better way to do the hblank waiting?
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.
- rainwarrior
- Posts: 8734
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Hblank - Palette swap mid frame, etc....
If all you had was 2 and 3 cycle instructions:JoeGtake2 wrote:The smallest seems to be two, so how would I do this?
2 = 2
3 = 3
4 = 2 + 2
5 = 2 + 3
6 = 2 + 2 + 2 = 3 + 3
7 = 2 + 2 + 3
etc...