It is currently Thu Sep 21, 2017 9:00 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 48 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
PostPosted: Fri Aug 04, 2017 9:54 pm 
Offline
User avatar

Joined: Sat Aug 15, 2015 3:42 pm
Posts: 100
Location: France
Stupid question : are you using a fully transparent sprite ?


Top
 Profile  
 
PostPosted: Fri Aug 04, 2017 10:15 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10010
Location: Rio de Janeiro - Brazil
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.


Top
 Profile  
 
PostPosted: Fri Aug 04, 2017 10:54 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5623
Location: Canada
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.)


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 5:13 am 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
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.


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 9:49 am 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
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:

    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...)

Attachment:
close.png
close.png [ 3.42 KiB | Viewed 264 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.


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 10:40 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10010
Location: Rio de Janeiro - Brazil
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.


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 11:06 am 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
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:
;;;;;; 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!


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 11:31 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10010
Location: Rio de Janeiro - Brazil
That's about right.

JoeGtake2 wrote:
;;;;; Turn on rendering / fix scroll

Fix the scroll first (preferably *before* the hblank), turn on rendering second.

Quote:
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.

Quote:
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).


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 11:48 am 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
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?


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 11:49 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6162
Location: Seattle
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


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 12:21 pm 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 254
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?


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 12:41 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6162
Location: Seattle
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


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 1:08 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5623
Location: Canada
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.


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 1:11 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5623
Location: Canada
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...


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 1:11 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6162
Location: Seattle
Well, and the unofficial instructions...


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 48 posts ]  Go to page Previous  1, 2, 3, 4  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: Google Adsense [Bot] and 9 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