Start adding scanline variants
This commit is contained in:
parent
a33779ae28
commit
794bc1fc09
226
src/SpriteV1.s
226
src/SpriteV1.s
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue