iigs-game-engine/src/tiles/DirtyTileQueue.s

181 lines
6.0 KiB
ArmAsm

_ClearDirtyTiles
bra :hop
:loop
jsr _PopDirtyTile
:hop
lda DirtyTileCount
bne :loop
rts
; Append a new dirty tile record
;
; A = result of _GetTileStoreOffset for X, Y
;
; The main purpose of this function is to
;
; 1. Avoid marking the same tile dirty multiple times, and
; 2. Pre-calculating all of the information necessary to render the tile
_PushDirtyTile
tax
; alternate entry point if the x-register is already set
_PushDirtyTileX
lda TileStore+TS_DIRTY,x
bne :occupied2
inc ; any non-zero value will work
sta TileStore+TS_DIRTY,x ; and is 1 cycle faster than loading a constant value
txa
ldx DirtyTileCount ; 4
sta DirtyTiles,x ; 6
inx ; 2
inx ; 2
stx DirtyTileCount ; 4 = 18
rts
:occupied2
txa ; Make sure TileStore offset is returned in the accumulator
rts
; alternate entry point if the Y-register is already set
_PushDirtyTileY
lda TileStore+TS_DIRTY,y
bne :occupied2
inc ; any non-zero value will work
sta TileStore+TS_DIRTY,y ; and is 1 cycle faster than loading a constant value
tya
ldy DirtyTileCount ; 4
sta DirtyTiles,y ; 6
iny ; 2
iny ; 2
sty DirtyTileCount ; 4 = 18
rts
:occupied2
tya ; Make sure TileStore offset is returned in the accumulator
rts
; Remove a dirty tile from the list and return it in state ready to be rendered. It is important
; that the core rendering functions *only* use _PopDirtyTile to get a list of tiles to update.
_PopDirtyTile
ldy DirtyTileCount
bne _PopDirtyTile2
rts
_PopDirtyTile2 ; alternate entry point
dey
dey
sty DirtyTileCount ; remove last item from the list
ldx DirtyTiles,y ; load the offset into the Tile Store
stz TileStore+TS_DIRTY,x ; clear the occupied backlink
rts
; An optimized subroutine that runs through the dirty tile list and executes a callback function
; for each dirty tile. This is an unrolled loop, so we avoid the need to track a register and
; decrement on each iteration.
;
; Also, if we are handling less than 8 dirty tiles, we use a code path that does not
; need to use an index register
;
; Bank = Tile Store
; D = Page 2
_PopDirtyTilesFast
ldx DP2_DIRTY_TILE_COUNT ; This is pre-multiplied by 2
bne pdtf_not_empty ; If there are no items, exit
at_exit rts
pdtf_not_empty
cpx #16 ; If there are >= 8 elements, then
bcs full_chunk ; do a full chunk
jmp (at_table,x)
at_table da at_exit,at_one,at_two,at_three
da at_four,at_five,at_six,at_seven
full_chunk txa
sbc #16 ; carry set from branch
sta DP2_DIRTY_TILE_COUNT ; fall through
tay ; use the Y-register for the index
; Because all of the registers get used in the subroutine, we
; push the values from the DirtyTiles array onto the stack and then pop off
; the values as we go
ldx DirtyTiles+14,y
stz TileStore+TS_DIRTY,x
jsr _RenderTile
ldy DP2_DIRTY_TILE_COUNT
ldx DirtyTiles+12,y
stz TileStore+TS_DIRTY,x
jsr _RenderTile
ldy DP2_DIRTY_TILE_COUNT
ldx DirtyTiles+10,y
stz TileStore+TS_DIRTY,x
jsr _RenderTile
ldy DP2_DIRTY_TILE_COUNT
ldx DirtyTiles+8,y
stz TileStore+TS_DIRTY,x
jsr _RenderTile
ldy DP2_DIRTY_TILE_COUNT
ldx DirtyTiles+6,y
stz TileStore+TS_DIRTY,x
jsr _RenderTile
ldy DP2_DIRTY_TILE_COUNT
ldx DirtyTiles+4,y
stz TileStore+TS_DIRTY,x
jsr _RenderTile
ldy DP2_DIRTY_TILE_COUNT
ldx DirtyTiles+2,y
stz TileStore+TS_DIRTY,x
jsr _RenderTile
ldy DP2_DIRTY_TILE_COUNT
ldx DirtyTiles+0,y
stz TileStore+TS_DIRTY,x
jsr _RenderTile
jmp _PopDirtyTilesFast
; These routines just handle between 1 and 7 dirty tiles
at_seven
ldx DirtyTiles+12
stz TileStore+TS_DIRTY,x
jsr _RenderTile
at_six
ldx DirtyTiles+10
stz TileStore+TS_DIRTY,x
jsr _RenderTile
at_five
ldx DirtyTiles+8
stz TileStore+TS_DIRTY,x
jsr _RenderTile
at_four
ldx DirtyTiles+6
stz TileStore+TS_DIRTY,x
jsr _RenderTile
at_three
ldx DirtyTiles+4
stz TileStore+TS_DIRTY,x
jsr _RenderTile
at_two
ldx DirtyTiles+2
stz TileStore+TS_DIRTY,x
jsr _RenderTile
at_one
ldx DirtyTiles+0
stz TileStore+TS_DIRTY,x
jmp _RenderTile