Start adding scanline variants

This commit is contained in:
Lucas Scharenbroich 2022-07-30 11:04:13 -05:00
parent a33779ae28
commit 794bc1fc09
2 changed files with 172 additions and 226 deletions

View File

@ -1,226 +0,0 @@
; Old code the was in Version 1, but is not needed. May be adapted for Verions 2.
; Y = _Sprites array offset
_EraseSpriteY
lda _Sprites+OLD_VBUFF_ADDR,y
beq :noerase
ldx _Sprites+SPRITE_DISP,y ; get the dispatch index for this sprite (32 values)
jmp (:do_erase,x)
:noerase rts
:do_erase dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8
dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16
dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8
dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16
dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8
dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16
dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8
dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16
; A = bank address
_EraseTileSprite8x8
tax
phb ; Save the bank to switch to the sprite plane
pei SpriteBanks
plb ; pop the data bank (low byte)
]line equ 0
lup 8
stz: {]line*SPRITE_PLANE_SPAN}+0,x
stz: {]line*SPRITE_PLANE_SPAN}+2,x
]line equ ]line+1
--^
plb ; pop the mask bank (high byte)
lda #$FFFF
]line equ 0
lup 8
sta: {]line*SPRITE_PLANE_SPAN}+0,x
sta: {]line*SPRITE_PLANE_SPAN}+2,x
]line equ ]line+1
--^
plb
rts
_EraseTileSprite8x16
tax
phb ; Save the bank to switch to the sprite plane
pei SpriteBanks
plb ; pop the data bank (low byte)
]line equ 0
lup 16
stz: {]line*SPRITE_PLANE_SPAN}+0,x
stz: {]line*SPRITE_PLANE_SPAN}+2,x
]line equ ]line+1
--^
plb ; pop the mask bank (high byte)
lda #$FFFF
]line equ 0
lup 16
sta: {]line*SPRITE_PLANE_SPAN}+0,x
sta: {]line*SPRITE_PLANE_SPAN}+2,x
]line equ ]line+1
--^
plb
rts
_EraseTileSprite16x8
tax
phb ; Save the bank to switch to the sprite plane
pei SpriteBanks
plb ; pop the data bank (low byte)
]line equ 0
lup 8
stz: {]line*SPRITE_PLANE_SPAN}+0,x
stz: {]line*SPRITE_PLANE_SPAN}+2,x
stz: {]line*SPRITE_PLANE_SPAN}+4,x
stz: {]line*SPRITE_PLANE_SPAN}+6,x
]line equ ]line+1
--^
plb ; pop the mask bank (high byte)
lda #$FFFF
]line equ 0
lup 8
sta: {]line*SPRITE_PLANE_SPAN}+0,x
sta: {]line*SPRITE_PLANE_SPAN}+2,x
sta: {]line*SPRITE_PLANE_SPAN}+4,x
sta: {]line*SPRITE_PLANE_SPAN}+6,x
]line equ ]line+1
--^
plb
rts
_EraseTileSprite16x16
tax
phb ; Save the bank to switch to the sprite plane
pei SpriteBanks
plb ; pop the data bank (low byte)
]line equ 0
lup 16
stz: {]line*SPRITE_PLANE_SPAN}+0,x
stz: {]line*SPRITE_PLANE_SPAN}+2,x
stz: {]line*SPRITE_PLANE_SPAN}+4,x
stz: {]line*SPRITE_PLANE_SPAN}+6,x
]line equ ]line+1
--^
plb ; pop the mask bank (high byte)
lda #$FFFF
]line equ 0
lup 16
sta: {]line*SPRITE_PLANE_SPAN}+0,x
sta: {]line*SPRITE_PLANE_SPAN}+2,x
sta: {]line*SPRITE_PLANE_SPAN}+4,x
sta: {]line*SPRITE_PLANE_SPAN}+6,x
]line equ ]line+1
--^
plb
rts
; First, if there is only one sprite, then we can skip any overhead and do a single lda/and/ora/sta to put the
; sprite data on the screen.
;
; Second, if there are 4 or less, then we "stack" the sprite data using an unrolled loop that allows each
; sprite to just be a single and/ora pair and the final result is not written to any intermediate memory buffer.
;
; Third, if there are 5 or more sprites, then we assume that the sprites are "dense" and that there will be a
; non-trivial amount of overdraw. In this case we do a series of optimized copies of the sprite data *and*
; masks into a direct page buffer in *reverse order*. Once a mask value becomes zero, then nothing else can
; show through and that value can be skipped. Once all of the mask values are zero, then the render is terminated
; and the data buffer copied to the final destination.
;
; Note that these rendering algorithms impose a priority ordering on the sprites where lower sprite IDs are drawn
; underneath higher sprite IDs.
RenderActiveSpriteTiles
cmp #0 ; Is there only one active sprite? If so optimise
bne :many
ldx vbuff ; load the address to the (adjusted) sprite tile
lda TileStore+TS_SCREEN_ADDR,y
tay
lda tiledata+0,y
andl spritemask,x
oral spritedata,x
sta 00,s
lda tiledata+2,y
andl spritemask+2,x
oral spritedata+2,x
sta 02,s
...
tsc
adc #320
tcs
...
lda tiledata+{line*4},y
andl spritemask+{line*SPAN},x
oral spritedata+{line*SPAN},x
sta 160,s
lda tiledata+{line*4}+2,y
andl spritemask+{line*SPAN}+2,x
oral spritedata+{line*SPAN}+2,x
sta 162,s
rts
:many
lda TileStore+TS_SCREEN_ADDR,y
tcs
lda TileStore+TS_TILE_ADDR,y
tay
ldx count
jmp (:arr,x)
lda tiledata+0,y
ldx vbuff
andl spritemask,x
oral spritedata,x
ldx vbuff+2
andl spritemask,x
oral spritedata,x
ldx vbuff+4
andl spritemask,x
oral spritedata,x
...
sta 00,s
ldx count
jmp (:arr,x)
lda tiledata+0,y
ldx vbuff
andl spritemask,x
oral spritedata,x
ldx vbuff+2
andl spritemask,x
oral spritedata,x
ldx vbuff+4
andl spritemask,x
oral spritedata,x
...
sta 02,s
sta 160,s
sta 162,s
tsc
adc #320

172
src/blitter/Scanline.s Normal file
View File

@ -0,0 +1,172 @@
; This support an alternate engine mode. When in scanline mode the renderer does not use the
; global StartX and StartY parameters to set up the code field. Instead, an array of scanline
; parameters must be provided to the blitter.
;
; This is a low-level mode and it is assumed that the arrays will contain valid values. This
; process is quite a bit slower that the normal setup because it must calculate code field
; entry points for each line, instead of once for the entire frame.
_ScanlineBG0XPos
:stk_save equ tmp0
:virt_line_x2 equ tmp1
:last_line_x2 equ tmp2
:src_bank equ tmp3
:exit_offset equ tmp4
:entry_offset equ tmp5
:exit_bra equ tmp6
:exit_address equ tmp7
:base_address equ tmp8
:opcode equ tmp9
:odd_entry_offset equ tmp10
lda StartYMod208 ; This is the base line of the virtual screen
asl
sta :virt_line_x2 ; Keep track of it
lda ScreenHeight
asl
clc
adc :virt_line_x2
sta :last_line_x2
phb
phb
pla
and #$FF00
sta :src_bank
:loop
ldx :virt_line_x2
lda StartXMod164Arr,x ; Get the offset for this line
dec ; The exit point is one byte sooner
bpl *+5
lda #163
bit #$0001 ; if odd, then original number was even
beq :odd_exit ; if even, the original number was odd
; This is the even code path
and #$FFFE
tay
lda CodeFieldEvenBRA,y
sta :exit_bra
lda Col2CodeOffset,y
sta :exit_offset
sta LastPatchOffsetArr,x ; Cache afor later
bra :do_entry
; This is the odd code path
:odd_exit tay
lda CodeFieldOddBRA,y
sta :exit_bra
lda Col2CodeOffset,y
sta :exit_offset
sta LastPatchOffsetArr,x
; Handle the entry point calculations
:do_entry
lda StartXMod164Arr,x
clc
adc ScreenWidth ; move to the right edge and back up a byte
dec ; to get the index of the first on-screen byte
cmp #164 ; Keep the value in range
bcc *+5
sbc #164
; Same logic as before
bit #$0001
beq :odd_entry
and #$FFFE
tay
lda Col2CodeOffset,y
sta :entry_offset
lda #$004C ; set the entry_jmp opcode to JMP
sta :opcode
stz :odd_entry_offset ; mark as an even case
bra :prep_complete
:odd_entry
tay
lda Col2CodeOffset,y
sta :entry_offset ; Will be used to load the data
lda Col2CodeOffset-2,y
sta :odd_entry_offset ; will the the actual location to jump to
lda #$00AF ; set the entry_jmp opcode to LDAL
sta :opcode
:prep_complete
; Not patch in the code field line
ldy BTableLow,x ; Get the address of the first code field line
clc
adc :exit_offset ; Add some offsets to get the base address in the code field line
sta :exit_address
sty :base_address
lda BTableHigh,x
ora src_bank
pha
plb
; First step is to set the BRA instruction to exit the code field at the proper location. There
; are two sub-steps to do here; we need to save the 16-bit value that exists at the location and
; then overwrite it with the branch instruction.
; SaveOpcode
; y is already set to :base_address
ldx :exit_address ; Save from this location
lda: $0000,x
sta: OPCODE_SAVE+$0000,y
;SetConst
txy ; ldy :exit_address -- starting at this address
ldx :exit_bra ; Copy this value into all of the lines
sta: $0000,y
; Next, patch in the CODE_ENTRY value, which is the low byte of a JMP instruction. This is an
; 8-bit operation and, since the PEA code is bank aligned, we use the entry_offset value directly
sep #$20
; SetCodeEntry
lda :entry_offset
ldy :base_address
sta: CODE_ENTRY+$0000,y
; SetCodeEntryOpcode
lda :opcode
sta: CODE_ENTRY_OPCODE+$0000,y
; If this is an odd entry, also set the odd_entry low byte and save the operand high byte
lda :odd_entry_offset
beq :not_odd
; SetOddCodeEntry
sta: ODD_ENTRY+$0000,y
; SaveHighOperand
ldx :exit_address
lda: $0002,x
sta: OPCODE_HIGH_SAVE+$0000,y
:not_odd
rep #$21 ; clear the carry
; Do the end of the loop -- update the virtual line counter and reduce the number
; of lines left to render
plb ; restore the bank
lda :virt_line_x2
inc
inc
sta :virt_line_x2
cmp :last_line_x2
jne :loop
rts