I'm trying to remove the glitching I see at the edges of scanlines I see when setting scroll values
mid hblank in my game. I was wondering if you guys had any suggestions, I included my irq routine and an explanation of how it works.
I included my mmc3 irq routine (multiLineIrq: is the entry point) to see if any of you could provide some pointers as to how I can fix this.
The basic jist is that there is are 4 tables of 2006,2005,2005,2006 for the register writes that store my scroll values for each of the N mmc3 scanline irqs (indexed by the number of irqs hit so far per screen).
IRQ_SCROLL_2006_FIRST
IRQ_SCROLL_2005_Y
IRQ_SCROLL_2005_X
IRQ_SCROLL_2006_SECOND
There is a table of # line deltas between irqs: R_MMC_IRQ_LINE0
Nametable layout:
Foreground layer: page 0
Background layer: page 1
Status bar: last 2 character rows of page 1
Here is what happens per frame:
24 lines (status bar size) after vblank ends:
The first irq set is change part of the palette from gray (for the status bar) to the colors used on the play screen. Also the character set is changed to a blank page to blank the screen and remove some glitching.
2 lines later
The second irq sets the 2006,5,5,6 for the playscreen (can be parallaxing background or foreground), and sets the character set for the playscreen. During the 2006,5,5,6 setting background drawing using the ppumask is disabled to ensure the scroll registers are set properly. This is also where sprite drawing gets enabled for the first time for the screen.
The next (N-3) irqs set 2006,5,5,6 for the different bands of scrolling foreground/background "layers". Also there is an irq for a Crystalis style single screen mirroring.
The final irq depends on the mode.
In play mode about 8 lines above the visible screen bottom, the final irq changes the character set to a blank page to blank the screen and remove some artifacts.
In conversation mode the final irq changes the character set to the alphanumeric font pages, the first 3 colors to grays for the font rendering, and changes the sprite bank to the portrait.
-Sedwave / Hiatus Ward ( http://www.nesworld.com/homebrew/hiatwrd0.zip)
mid hblank in my game. I was wondering if you guys had any suggestions, I included my irq routine and an explanation of how it works.
I included my mmc3 irq routine (multiLineIrq: is the entry point) to see if any of you could provide some pointers as to how I can fix this.
The basic jist is that there is are 4 tables of 2006,2005,2005,2006 for the register writes that store my scroll values for each of the N mmc3 scanline irqs (indexed by the number of irqs hit so far per screen).
IRQ_SCROLL_2006_FIRST
IRQ_SCROLL_2005_Y
IRQ_SCROLL_2005_X
IRQ_SCROLL_2006_SECOND
There is a table of # line deltas between irqs: R_MMC_IRQ_LINE0
Nametable layout:
Foreground layer: page 0
Background layer: page 1
Status bar: last 2 character rows of page 1
Here is what happens per frame:
24 lines (status bar size) after vblank ends:
The first irq set is change part of the palette from gray (for the status bar) to the colors used on the play screen. Also the character set is changed to a blank page to blank the screen and remove some glitching.
2 lines later
The second irq sets the 2006,5,5,6 for the playscreen (can be parallaxing background or foreground), and sets the character set for the playscreen. During the 2006,5,5,6 setting background drawing using the ppumask is disabled to ensure the scroll registers are set properly. This is also where sprite drawing gets enabled for the first time for the screen.
The next (N-3) irqs set 2006,5,5,6 for the different bands of scrolling foreground/background "layers". Also there is an irq for a Crystalis style single screen mirroring.
The final irq depends on the mode.
In play mode about 8 lines above the visible screen bottom, the final irq changes the character set to a blank page to blank the screen and remove some artifacts.
In conversation mode the final irq changes the character set to the alphanumeric font pages, the first 3 colors to grays for the font rendering, and changes the sprite bank to the portrait.
-Sedwave / Hiatus Ward ( http://www.nesworld.com/homebrew/hiatwrd0.zip)
Code:
; ===============================================
endPaletteIrq:
pla
tay ;pull y
pla
tax ;pull X
pla ;pull a
plp ; pull flags
rti
; ===============================================
setBlankingAndFinishIrq:
setMMC3ChrBankLo 0, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 1, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 2, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 3, #K_EMPTY_CHR_PAGE
jmp endIrq
; ===============================================
setPaletteIrq:
lda R_MMC_IRQ_LINE0 +1 ; setup next irq
setMMC3ScanlineIrq;
inc R_MMC_NUM_IRQ_HIT
nop
nop
nop
nop
nop
jsr setPlayScreenPaletteIrq
;blank screen but still allow mmc3 irq counter by setting to empty character page
setMMC3ChrBankLo 0, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 1, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 2, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 3, #K_EMPTY_CHR_PAGE
lda #(PPU_MASK_SPR_VIS | PPU_MASK_BKG_VIS )
sta PPU_MASK
jmp endPaletteIrq
;note split irq does not turn off ppu
setSplitIrq:
dex
lda IRQ_SCROLL_2006_FIRST, x
sta PPU_ADDR
lda IRQ_SCROLL_2005_Y, x
sta PPU_SCRL
lda IRQ_SCROLL_2005_X, x
sta PPU_SCRL
lda IRQ_SCROLL_2006_SECOND, x
sta PPU_ADDR
jmp endIrq
; ===============================================
; Interrupt handlers
; ===============================================
irq:
multiLineIrq:
php ;push flags
pha ;push a
txa
pha ;push x
tya
pha ;push y
lda #0
sta MMC3_IRQ_ACK
ldx R_MMC_NUM_IRQ_HIT
beq setPaletteIrq
cpx R_CONVO_IRQ_NUM
bne notConvoIrq
jmp convoIrq
notConvoIrq:
inx
cpx R_MMC_NUM_IRQ
bne @notFinalIrq
jmp setBlankingAndFinishIrq
@notFinalIrq:
lda R_MMC_IRQ_LINE0, x ; accum contains number of scanlines until next irq, setup next irq
setMMC3ScanlineIrq;
@noNewIrq:
;how many irq previously hit
ldx R_MMC_NUM_IRQ_HIT
cpx R_SPLIT_IRQ_NUM
beq setSplitIrq
dex ; irq #1 index 0, irq#2 index 1, etc...
; between 2 and x nops stops shaking
; 2 seems best on real hardware
nop
nop
;note, setting scroll value to different X value midscreen requires PPU
; drawing to be disabled so that internal X counter does not interfere with
; setting scroll address and values
lda #PPU_MASK_SPR_VIS
sta PPU_MASK
postBlankIrq:
lda IRQ_SCROLL_2006_FIRST, x
sta PPU_ADDR
lda IRQ_SCROLL_2005_Y, x
sta PPU_SCRL
lda IRQ_SCROLL_2005_X, x
sta PPU_SCRL
lda IRQ_SCROLL_2006_SECOND, x
sta PPU_ADDR
lda #(PPU_MASK_SPR_VIS | PPU_MASK_BKG_VIS )
sta PPU_MASK
ldx R_MMC_NUM_IRQ_HIT
cpx #1
bne noSetupPlayscreenChar
setMMC3ChrBankLo 0, LEVEL_DATA_CHR_PAGE_0
setMMC3ChrBankLo 1, LEVEL_DATA_CHR_PAGE_1
setMMC3ChrBankLo 2, LEVEL_DATA_CHR_PAGE_2
setMMC3ChrBankLo 3, LEVEL_DATA_CHR_PAGE_3
nop
nop
nop
nop
nop
noSetupPlayscreenChar:
endIrq:
inc R_MMC_NUM_IRQ_HIT
pla
tay ;pull y
pla
tax ;pull X
pla ;pull a
plp ;pull flags
rti
endPaletteIrq:
pla
tay ;pull y
pla
tax ;pull X
pla ;pull a
plp ; pull flags
rti
; ===============================================
setBlankingAndFinishIrq:
setMMC3ChrBankLo 0, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 1, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 2, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 3, #K_EMPTY_CHR_PAGE
jmp endIrq
; ===============================================
setPaletteIrq:
lda R_MMC_IRQ_LINE0 +1 ; setup next irq
setMMC3ScanlineIrq;
inc R_MMC_NUM_IRQ_HIT
nop
nop
nop
nop
nop
jsr setPlayScreenPaletteIrq
;blank screen but still allow mmc3 irq counter by setting to empty character page
setMMC3ChrBankLo 0, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 1, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 2, #K_EMPTY_CHR_PAGE
setMMC3ChrBankLo 3, #K_EMPTY_CHR_PAGE
lda #(PPU_MASK_SPR_VIS | PPU_MASK_BKG_VIS )
sta PPU_MASK
jmp endPaletteIrq
;note split irq does not turn off ppu
setSplitIrq:
dex
lda IRQ_SCROLL_2006_FIRST, x
sta PPU_ADDR
lda IRQ_SCROLL_2005_Y, x
sta PPU_SCRL
lda IRQ_SCROLL_2005_X, x
sta PPU_SCRL
lda IRQ_SCROLL_2006_SECOND, x
sta PPU_ADDR
jmp endIrq
; ===============================================
; Interrupt handlers
; ===============================================
irq:
multiLineIrq:
php ;push flags
pha ;push a
txa
pha ;push x
tya
pha ;push y
lda #0
sta MMC3_IRQ_ACK
ldx R_MMC_NUM_IRQ_HIT
beq setPaletteIrq
cpx R_CONVO_IRQ_NUM
bne notConvoIrq
jmp convoIrq
notConvoIrq:
inx
cpx R_MMC_NUM_IRQ
bne @notFinalIrq
jmp setBlankingAndFinishIrq
@notFinalIrq:
lda R_MMC_IRQ_LINE0, x ; accum contains number of scanlines until next irq, setup next irq
setMMC3ScanlineIrq;
@noNewIrq:
;how many irq previously hit
ldx R_MMC_NUM_IRQ_HIT
cpx R_SPLIT_IRQ_NUM
beq setSplitIrq
dex ; irq #1 index 0, irq#2 index 1, etc...
; between 2 and x nops stops shaking
; 2 seems best on real hardware
nop
nop
;note, setting scroll value to different X value midscreen requires PPU
; drawing to be disabled so that internal X counter does not interfere with
; setting scroll address and values
lda #PPU_MASK_SPR_VIS
sta PPU_MASK
postBlankIrq:
lda IRQ_SCROLL_2006_FIRST, x
sta PPU_ADDR
lda IRQ_SCROLL_2005_Y, x
sta PPU_SCRL
lda IRQ_SCROLL_2005_X, x
sta PPU_SCRL
lda IRQ_SCROLL_2006_SECOND, x
sta PPU_ADDR
lda #(PPU_MASK_SPR_VIS | PPU_MASK_BKG_VIS )
sta PPU_MASK
ldx R_MMC_NUM_IRQ_HIT
cpx #1
bne noSetupPlayscreenChar
setMMC3ChrBankLo 0, LEVEL_DATA_CHR_PAGE_0
setMMC3ChrBankLo 1, LEVEL_DATA_CHR_PAGE_1
setMMC3ChrBankLo 2, LEVEL_DATA_CHR_PAGE_2
setMMC3ChrBankLo 3, LEVEL_DATA_CHR_PAGE_3
nop
nop
nop
nop
nop
noSetupPlayscreenChar:
endIrq:
inc R_MMC_NUM_IRQ_HIT
pla
tay ;pull y
pla
tax ;pull X
pla ;pull a
plp ;pull flags
rti