mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-06-26 17:29:42 +00:00
This significantly simplifies the dispatch process by creating a proper backing store for the tiles. Most values that were calcualted on the fly are now stored as constants in the tile store. Also, all tile updated are run through the dirty tile list which solved a checken-and-egg problem of which order to do sprites vs new tiles and affords a lot of optimizations since tile rendering is deferred and each tile is only drawn at most once per frame.
636 lines
27 KiB
ArmAsm
636 lines
27 KiB
ArmAsm
; Collection of functions that deal with tiles. Primarily rendering tile data into
|
|
; the code fields.
|
|
;
|
|
; Tile data can be done faily often, so these routines are performance-sensitive.
|
|
;
|
|
; CopyTileConst -- the first 16 tile numbers are reserved and can be used
|
|
; to draw a solid tile block
|
|
; CopyTileLinear -- copies the tile data from the tile bank in linear order, e.g.
|
|
; 32 consecutive bytes are copied
|
|
|
|
; _RenderTile
|
|
;
|
|
; A high-level function that takes a 16-bit tile descriptor and dispatched to the
|
|
; appropriate tile copy routine based on the descriptor flags
|
|
;
|
|
; Bit 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
|
|
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
; |xx|xx|FF|MM|DD|VV|HH| | | | | | | | | |
|
|
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
; \____/ | | | | | \________________________/
|
|
; | | | | | | Tile ID (0 to 511)
|
|
; | | | | | |
|
|
; | | | | | +-- H : Flip tile horizontally
|
|
; | | | | +----- V : Flip tile vertically
|
|
; | | | +-------- D : Render as a Dynamic Tile (Tile ID < 32, V and H have no effect)
|
|
; | | +----------- M : Apply tile mask
|
|
; | +-------------- F : Overlay a fringe tile
|
|
; +------------------- Reserved (must be zero)
|
|
;
|
|
; Each logical tile (corresponding to each Tile ID) actually takes up 128 bytes of memory in the
|
|
; tile bank
|
|
;
|
|
; +0 : 32 bytes of tile data
|
|
; +32 : 32 bytes of tile mask
|
|
; +64 : 32 bytes of horizontally flipped tile data
|
|
; +96 : 32 bytes of horizontally flipped tile mask
|
|
;
|
|
; It is simply too slow to try to horizontally reverse the pixel data on the fly. This still allows
|
|
; for up to 512 tiles to be stored in a single bank, which should be sufficient.
|
|
|
|
TILE_ID_MASK equ $01FF
|
|
TILE_SPRITE_BIT equ $8000 ; Set if this tile intersects an active sprite
|
|
TILE_PRIORITY_BIT equ $4000 ; Put tile on top of sprite
|
|
TILE_FRINGE_BIT equ $2000
|
|
TILE_MASK_BIT equ $1000
|
|
TILE_DYN_BIT equ $0800
|
|
TILE_VFLIP_BIT equ $0400
|
|
TILE_HFLIP_BIT equ $0200
|
|
TILE_CTRL_MASK equ $FE00
|
|
TILE_PROC_MASK equ $F800 ; Select tile proc for rendering
|
|
|
|
; Temporary direct page locatinos used by some of the complext tile renderers
|
|
|
|
_X_REG equ tiletmp
|
|
_Y_REG equ tiletmp+2
|
|
_T_PTR equ tiletmp+4 ; Copy of the tile address pointer
|
|
_BASE_ADDR equ tiletmp+6 ; Copy of BTableLow for this tile
|
|
|
|
; Low-level function to take a tile descriptor and return the address in the tiledata
|
|
; bank. This is not too useful in the fast-path because the fast-path does more
|
|
; incremental calculations, but it is handy for other utility functions
|
|
;
|
|
; A = tile descriptor
|
|
;
|
|
; The address is the TileID * 128 + (HFLIP * 64)
|
|
GetTileAddr ENT
|
|
jsr _GetTileAddr
|
|
rtl
|
|
_GetTileAddr
|
|
asl ; Multiply by 2
|
|
bit #2*TILE_HFLIP_BIT ; Check if the horizontal flip bit is set
|
|
beq :no_flip
|
|
inc ; Set the LSB
|
|
:no_flip and #TILE_ID_MASK*2 ; Mask out non-id bits
|
|
asl ; x4
|
|
asl ; x8
|
|
asl ; x16
|
|
asl ; x32
|
|
asl ; x64
|
|
asl ; x128
|
|
rts
|
|
|
|
; On entry
|
|
;
|
|
; B is set to the correct BG1 data bank
|
|
; A is set to the the tile descriptor
|
|
; Y is set to the top-left address of the tile in the BG1 data bank
|
|
;
|
|
; tmp0/tmp1 is reserved
|
|
_RenderTileBG1
|
|
pha ; Save the tile descriptor
|
|
|
|
and #TILE_VFLIP_BIT+TILE_HFLIP_BIT ; Only horizontal and vertical flips are supported for BG1
|
|
xba
|
|
tax
|
|
ldal :actions,x
|
|
stal :tiledisp+1
|
|
|
|
pla
|
|
and #TILE_ID_MASK ; Mask out the ID and save just that
|
|
_Mul128 ; multiplied by 128
|
|
tax
|
|
:tiledisp jmp $0000
|
|
|
|
:actions dw _TBSolidBG1_00,_TBSolidBG1_0H,_TBSolidBG1_V0,_TBSolidBG1_VH
|
|
|
|
; Given an address to a Tile Store record, dispatch to the appropriate tile renderer. The Tile
|
|
; Store record contains all of the low-level information that's needed to call the renderer.
|
|
;
|
|
; Y = address of tile
|
|
_RenderTile2
|
|
lda TileStore+TS_TILE_ID,y ; build the finalized tile descriptor
|
|
ora TileStore+TS_SPRITE_FLAG,y
|
|
and #TILE_CTRL_MASK
|
|
tax
|
|
lda TileProcs,x ; load and patch in the appropriate subroutine
|
|
sta :tiledisp+1
|
|
|
|
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
|
|
|
sep #$20 ; load the bank of the target code field line
|
|
lda TileStore+TS_CODE_ADDR_HIGH,y
|
|
pha
|
|
rep #$20
|
|
lda TileStore+TS_CODE_ADDR_LOW,y ; load the address of the code field
|
|
sta _BASE_ADDR
|
|
|
|
lda TileStore+TS_WORD_OFFSET,y
|
|
ldy _BASE_ADDR
|
|
plb ; set the bank
|
|
|
|
; B is set to the correct code field bank
|
|
; A is set to the tile word offset (0 through 80 in steps of 4)
|
|
; Y is set to the top-left address of the tile in the code field
|
|
; X is set to the address of the tile data
|
|
|
|
:tiledisp jmp $0000 ; render the tile
|
|
|
|
; Reference all of the tile rendering subroutines defined in the TileXXXXX files. Each file defines
|
|
; 8 entry points:
|
|
;
|
|
; One set for normal, horizontally flipped, vertically flipped and hors & vert flipped.
|
|
; A second set that are optimized for when EngineMode has BG1 disabled.
|
|
TileProcs dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 00000 : normal tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 00001 : dynamic tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 00010 : masked normal tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 00011 : masked dynamic tiles
|
|
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 00100 : fringed normal tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 00101 : fringed dynamic tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 00110 : fringed masked normal tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 00111 : fringed masked dynamic tiles
|
|
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 01000 : high-priority normal tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 01001 : high-priority dynamic tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 01010 : high-priority masked normal tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 01011 : high-priority masked dynamic tiles
|
|
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 01100 : high-priority fringed normal tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 01101 : high-priority fringed dynamic tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 01110 : high-priority fringed masked normal tiles
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 01111 : high-priority fringed masked dynamic tiles
|
|
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 10000 : normal tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 10001 : dynamic tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 10010 : masked normal tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 10011 : masked dynamic tiles w/sprite
|
|
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 10100 : fringed normal tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 10101 : fringed dynamic tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 10110 : fringed masked normal tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 10111 : fringed masked dynamic tiles w/sprite
|
|
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 11000 : high-priority normal tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 11001 : high-priority dynamic tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 11010 : high-priority masked normal tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 11011 : high-priority masked dynamic tiles w/sprite
|
|
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 11100 : high-priority fringed normal tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 11101 : high-priority fringed dynamic tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 11110 : high-priority fringed masked normal tiles w/sprite
|
|
dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH ; 11111 : high-priority fringed masked dynamic tiles w/sprite
|
|
|
|
; _TBConstTile
|
|
;
|
|
; A specialized routine that fills in a tile with a single constant value. It's intended to be used to
|
|
; fill in solid colors, so there are no specialized horizontal or verical flipped variants
|
|
_TBConstTile
|
|
sta: $0001,y
|
|
sta: $0004,y
|
|
sta $1001,y
|
|
sta $1004,y
|
|
sta $2001,y
|
|
sta $2004,y
|
|
sta $3001,y
|
|
sta $3004,y
|
|
sta $4001,y
|
|
sta $4004,y
|
|
sta $5001,y
|
|
sta $5004,y
|
|
sta $6001,y
|
|
sta $6004,y
|
|
sta $7001,y
|
|
sta $7004,y
|
|
jmp _TBFillPEAOpcode
|
|
|
|
ClearTile
|
|
and #$00FF
|
|
ora #$4800
|
|
sta: $0004,y
|
|
sta $1004,y
|
|
sta $2004,y
|
|
sta $3004,y
|
|
sta $4004,y
|
|
sta $5004,y
|
|
sta $6004,y
|
|
sta $7004,y
|
|
inc
|
|
inc
|
|
sta: $0001,y
|
|
sta $1001,y
|
|
sta $2001,y
|
|
sta $3001,y
|
|
sta $4001,y
|
|
sta $5001,y
|
|
sta $6001,y
|
|
sta $7001,y
|
|
|
|
sep #$20
|
|
lda #$B1 ; This is a special case where we can set all the words to LDA (DP),y
|
|
sta: $0000,y
|
|
sta: $0003,y
|
|
sta $1000,y
|
|
sta $1003,y
|
|
sta $2000,y
|
|
sta $2003,y
|
|
sta $3000,y
|
|
sta $3003,y
|
|
sta $4000,y
|
|
sta $4003,y
|
|
sta $5000,y
|
|
sta $5003,y
|
|
sta $6000,y
|
|
sta $6003,y
|
|
sta $7000,y
|
|
sta $7003,y
|
|
rep #$20
|
|
rts
|
|
|
|
; Helper functions to copy tile data to the appropriate location in Bank 0
|
|
; X = tile ID
|
|
; Y = dynamic tile ID
|
|
CopyTileToDyn ENT
|
|
txa
|
|
jsr _GetTileAddr
|
|
tax
|
|
|
|
tya
|
|
and #$001F ; Maximum of 32 dynamic tiles
|
|
asl
|
|
asl ; 4 bytes per page
|
|
adc BlitterDP ; Add to the bank 00 base address
|
|
adc #$0100 ; Go to the next page
|
|
tay
|
|
jsr CopyTileDToDyn ; Copy the tile data
|
|
jsr CopyTileMToDyn ; Copy the tile mask
|
|
rtl
|
|
|
|
; X = address of tile
|
|
; Y = tile address in bank 0
|
|
CopyTileDToDyn
|
|
phb
|
|
pea $0000
|
|
plb
|
|
plb
|
|
|
|
ldal tiledata+0,x
|
|
sta: $0000,y
|
|
ldal tiledata+2,x
|
|
sta: $0002,y
|
|
ldal tiledata+4,x
|
|
sta $0100,y
|
|
ldal tiledata+6,x
|
|
sta $0102,y
|
|
ldal tiledata+8,x
|
|
sta $0200,y
|
|
ldal tiledata+10,x
|
|
sta $0202,y
|
|
ldal tiledata+12,x
|
|
sta $0300,y
|
|
ldal tiledata+14,x
|
|
sta $0302,y
|
|
ldal tiledata+16,x
|
|
sta $0400,y
|
|
ldal tiledata+18,x
|
|
sta $0402,y
|
|
ldal tiledata+20,x
|
|
sta $0500,y
|
|
ldal tiledata+22,x
|
|
sta $0502,y
|
|
ldal tiledata+24,x
|
|
sta $0600,y
|
|
ldal tiledata+26,x
|
|
sta $0602,y
|
|
ldal tiledata+28,x
|
|
sta $0700,y
|
|
ldal tiledata+30,x
|
|
sta $0702,y
|
|
|
|
plb
|
|
rts
|
|
|
|
; Helper function to copy tile mask to the appropriate location in Bank 0
|
|
;
|
|
; X = address of tile
|
|
; Y = tile address in bank 0
|
|
;
|
|
; Argument are the same as CopyTileDToDyn, the code takes care of adjust offsets.
|
|
; This make is possible to call the two functions back-to-back
|
|
;
|
|
; ldx tileAddr
|
|
; ldy dynTileAddr
|
|
; jsr CopyTileDToDyn
|
|
; jsr CopyTileMToDyn
|
|
CopyTileMToDyn
|
|
phb
|
|
pea $0000
|
|
plb
|
|
plb
|
|
|
|
ldal tiledata+32+0,x
|
|
sta: $0080,y
|
|
ldal tiledata+32+2,x
|
|
sta: $0082,y
|
|
ldal tiledata+32+4,x
|
|
sta $0180,y
|
|
ldal tiledata+32+6,x
|
|
sta $0182,y
|
|
ldal tiledata+32+8,x
|
|
sta $0280,y
|
|
ldal tiledata+32+10,x
|
|
sta $0282,y
|
|
ldal tiledata+32+12,x
|
|
sta $0380,y
|
|
ldal tiledata+32+14,x
|
|
sta $0382,y
|
|
ldal tiledata+32+16,x
|
|
sta $0480,y
|
|
ldal tiledata+32+18,x
|
|
sta $0482,y
|
|
ldal tiledata+32+20,x
|
|
sta $0580,y
|
|
ldal tiledata+32+22,x
|
|
sta $0582,y
|
|
ldal tiledata+32+24,x
|
|
sta $0680,y
|
|
ldal tiledata+32+26,x
|
|
sta $0682,y
|
|
ldal tiledata+32+28,x
|
|
sta $0780,y
|
|
ldal tiledata+32+30,x
|
|
sta $0782,y
|
|
|
|
plb
|
|
rts
|
|
|
|
; CopyBG0Tile
|
|
;
|
|
; A low-level function that copies 8x8 tiles directly into the code field space.
|
|
;
|
|
; A = Tile ID (0 - 511)
|
|
; X = Tile column (0 - 40)
|
|
; Y = Tile row (0 - 25)
|
|
CopyBG0Tile ENT
|
|
phb
|
|
phk
|
|
plb
|
|
jsr _CopyBG0Tile
|
|
plb
|
|
rtl
|
|
|
|
_CopyBG0Tile
|
|
phb ; save the current bank
|
|
phx ; save the original x-value
|
|
pha ; save the tile ID
|
|
|
|
tya ; lookup the address of the virtual line (y * 8)
|
|
asl
|
|
asl
|
|
asl
|
|
asl ; x2 because the table contains words, not
|
|
tay
|
|
|
|
sep #$20 ; set the bank register
|
|
lda BTableHigh,y
|
|
pha ; save for a few instruction
|
|
rep #$20
|
|
|
|
txa
|
|
asl ; there are two columns per tile, so multiple by 4
|
|
asl ; asl will clear the carry bit
|
|
tax
|
|
|
|
lda BTableLow,y
|
|
sta _BASE_ADDR ; Used in masked tile renderer
|
|
clc
|
|
adc Col2CodeOffset+2,x ; Get the right edge (which is the lower physical address)
|
|
tay
|
|
|
|
plb ; set the bank
|
|
pla ; pop the tile ID
|
|
; jsr _RenderTile
|
|
|
|
:exit
|
|
plx ; pop the x-register
|
|
plb ; restore the data bank and return
|
|
rts
|
|
|
|
|
|
; CopyBG1Tile
|
|
;
|
|
; A low-level function that copies 8x8 tiles directly into the BG1 data buffer.
|
|
;
|
|
; A = Tile ID (0 - 511)
|
|
; X = Tile column (0 - 40)
|
|
; Y = Tile row (0 - 25)
|
|
CopyBG1Tile
|
|
phb
|
|
phk
|
|
plb
|
|
jsr _CopyBG1Tile
|
|
plb
|
|
rtl
|
|
|
|
_CopyBG1Tile
|
|
phb ; save the current bank
|
|
phx ; save the original x-value
|
|
pha ; save the tile ID
|
|
|
|
tya ; lookup the address of the virtual line (y * 8)
|
|
asl
|
|
asl
|
|
asl
|
|
asl
|
|
tay
|
|
|
|
txa
|
|
asl
|
|
asl ; 4 bytes per tile column
|
|
clc
|
|
adc BG1YTable,y
|
|
tay
|
|
|
|
sep #$20
|
|
lda BG1DataBank
|
|
pha
|
|
plb ; set the bank
|
|
rep #$20
|
|
|
|
pla ; pop the tile ID
|
|
jsr _RenderTileBG1
|
|
|
|
plx ; pop the x-register
|
|
plb ; restore the data bank and return
|
|
rts
|
|
|
|
MAX_TILES equ {26*41} ; Number of tiles in the code field (41 columns * 26 rows)
|
|
TILE_STORE_SIZE equ {MAX_TILES*2} ; The tile store contains a tile descriptor in each slot
|
|
|
|
; Tile Store that holds tile records which contain all the essential information for rendering
|
|
; a tile.
|
|
;
|
|
; TileStore+TS_TILE_ID : Tile descriptor
|
|
; TileStore+TS_DIRTY : $FFFF is clean, otherwise stores a back-reference to the DirtyTiles array
|
|
; TileStore+TS_SPRITE_FLAG : Set to TILE_SPRITE_BIT is a sprite is present at this tile location
|
|
; TileStore+TS_TILE_ADDR : Address of the tile in the tile data buffer
|
|
; TIleStore+TS_CODE_ADDR_LOW : Low word of the address in the code field that receives the tile
|
|
; TileStore+TS_CODE_ADDR_HIGH : High word of the address in the code field that receives the tile
|
|
; TileStore+TS_WORD_OFFSET : Logical number of word for this location
|
|
|
|
TileStore ds TILE_STORE_SIZE*7
|
|
TS_TILE_ID equ TILE_STORE_SIZE*0
|
|
TS_DIRTY equ TILE_STORE_SIZE*1
|
|
TS_SPRITE_FLAG equ TILE_STORE_SIZE*2
|
|
TS_TILE_ADDR equ TILE_STORE_SIZE*3 ; const value
|
|
TS_CODE_ADDR_LOW equ TILE_STORE_SIZE*4 ; const value
|
|
TS_CODE_ADDR_HIGH equ TILE_STORE_SIZE*5 ; const value
|
|
TS_WORD_OFFSET equ TILE_STORE_SIZE*6
|
|
|
|
; A list of dirty tiles that need to be updated in a given frame
|
|
DirtyTileCount ds 2
|
|
DirtyTiles ds TILE_STORE_SIZE ; At most this many tiles can possibly be update at once
|
|
|
|
; Initialize the tile storage data structures. This takes care of populating the tile records with the
|
|
; appropriate constant values.
|
|
_InitDirtyTiles
|
|
ldx #TILE_STORE_SIZE-2 ; Initialize the tile backing store with zeros
|
|
|
|
:loop lda #0
|
|
sta TileStore+TS_TILE_ID,x
|
|
lda #$FFFF
|
|
sta TileStore+TS_DIRTY
|
|
|
|
dex
|
|
dex
|
|
bpl :loop
|
|
rts
|
|
|
|
_ClearDirtyTiles
|
|
:loop
|
|
lda DirtyTileCount
|
|
beq :done
|
|
jsr _PopDirtyTile
|
|
bra :loop
|
|
:done
|
|
rts
|
|
|
|
; Helper function to get the address offset into the tile cachce / tile backing store
|
|
; X = tile column [0, 40] (41 columns)
|
|
; Y = tile row [0, 25] (26 rows)
|
|
_GetTileStoreOffset
|
|
phx ; preserve the registers
|
|
phy
|
|
|
|
jsr _GetTileStoreOffset0
|
|
|
|
ply
|
|
plx
|
|
rts
|
|
|
|
_GetTileStoreOffset0
|
|
tya
|
|
asl
|
|
tay
|
|
txa
|
|
asl
|
|
clc
|
|
adc TileStoreYTable,y
|
|
rts
|
|
|
|
; Set a tile value in the tile backing store. Mark dirty if the value changes
|
|
;
|
|
; A = tile id
|
|
; X = tile column [0, 40] (41 columns)
|
|
; Y = tile row [0, 25] (26 rows)
|
|
_SetTile
|
|
pha
|
|
jsr _GetTileStoreOffset0
|
|
tay
|
|
pla
|
|
cmp TileStore+TS_TILE_ID,y
|
|
beq :nochange
|
|
|
|
sta TileStore+TS_TILE_ID,y
|
|
tya
|
|
jmp _PushDirtyTile
|
|
|
|
:nochange rts
|
|
|
|
|
|
; Append a new dirty tile record
|
|
;
|
|
; A = result of _GetTileStoreOffset for X, Y
|
|
; X = tile column [0, 40] (41 columns)
|
|
; Y = tile row [0, 25] (26 rows)
|
|
;
|
|
; The main purposed 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
|
|
tay ; check if this already marked immediately
|
|
lda TileStore+TS_DIRTY,y ; If the lookup === $FFFF (<$8000), it is free.
|
|
bpl :occupied
|
|
|
|
; At this point, keep the Y register value because it is the correct offset to all of the tile
|
|
; record fields.
|
|
|
|
ldx DirtyTileCount
|
|
|
|
txa
|
|
sta TileStore+TS_DIRTY,y ; Store a back-link to this record
|
|
|
|
tya
|
|
sta DirtyTiles,x ; Store the lookup address in the list
|
|
|
|
inx
|
|
inx
|
|
stx DirtyTileCount ; Commit
|
|
rts
|
|
|
|
:occupied
|
|
ply
|
|
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,
|
|
; because this routine merges the tile IDs stored in the Tile Store with the Sprite
|
|
; information to set the TILE_SPRITE_BIT. This is the *only* place in the entire code base that
|
|
; applies this bit to a tile descriptor.
|
|
_PopDirtyTile
|
|
ldx DirtyTileCount
|
|
bne _PopDirtyTile2
|
|
rts
|
|
|
|
_PopDirtyTile2 ; alternate entry point
|
|
dex
|
|
dex
|
|
stx DirtyTileCount ; remove last item from the list
|
|
|
|
ldy DirtyTiles,x ; load the offset into the Tile Store
|
|
lda #$FFFF
|
|
sta DirtyTileCache,y ; clear the occupied backlink
|
|
rts
|
|
|
|
; Run through the dirty tile list and render them into the code field
|
|
_ApplyTiles
|
|
bra :begin
|
|
|
|
:loop
|
|
; Retrieve the offset of the next dirty Tile Store items
|
|
|
|
jsr _PopDirtyTile2
|
|
|
|
; Call the generic dispatch with the Tile Store record pointer at by the Y-register.
|
|
|
|
phb
|
|
jsr _RenderTile2
|
|
plb
|
|
|
|
; Loop again until the list of dirty tiles is empty
|
|
|
|
:begin ldx DirtyTileCount
|
|
bne :loop
|
|
rts |