Better support for user-defined tiles

This commit is contained in:
Lucas Scharenbroich 2023-06-02 00:38:35 -05:00
parent 459bc645be
commit fa307e5542
9 changed files with 162 additions and 50 deletions

View File

@ -161,6 +161,14 @@ DP2_TILEDATA_AND_TILESTORE_BANKS equ 164
DP2_SPRITEDATA_AND_TILESTORE_BANKS equ 166
DP2_TILEDATA_AND_SPRITEDATA_BANKS equ 168
DP2_BANK01_AND_TILESTORE_BANKS equ 170
DP2_TILEDATA_AND_BANK01_BANKS equ 172
; Tile record passed to user-defined tile callback
USER_TILE_RECORD equ 178
USER_TILE_ID equ 178 ; copy of the tile id in the tile store
USER_TILE_CODE_PTR equ 180 ; pointer to the code bank in which to patch
USER_TILE_ADDR equ 184 ; address in the tile data bank
USER_FREE_SPACE equ 186 ; a few bytes of scratch space
SPRITE_VBUFF_PTR equ 224 ; 32 bytes of adjusted pointers to VBuffArray addresses
; End direct page values
@ -197,6 +205,7 @@ vblCallback equ $0004 ; User routine to be called by VBL int
extSpriteRenderer equ $0005
rawDrawTile equ $0006
extBG0TileUpdate equ $0007
userTileCallback equ $0008
; CopyPicToBG1 flags
COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode" treating the buffer as a 164x208 pixmap with stride of 256

View File

@ -913,6 +913,10 @@ _CacheSpriteBanks
ora #^tiledata
sta DP2_TILEDATA_AND_SPRITEDATA_BANKS,x
lda #$0100
ora #^tiledata
sta DP2_TILEDATA_AND_BANK01_BANKS,x
lda #>spritedata
and #$FF00
ora #^TileStore

View File

@ -13,6 +13,7 @@ _CompileStamp
:vbuffAddr equ tmp5
:rtnval equ tmp6
LDA_IND_LONG_IDX equ $B7
LDA_IMM_OPCODE equ $A9
LDA_ABS_X_OPCODE equ $BD
AND_IMM_OPCODE equ $29
@ -139,7 +140,7 @@ RTL_OPCODE equ $6B
; 4 palettes for the sprite data. Converts 4 pixels at a time from 0000 0000w wxxy yzz0 -> gggg hhhh iiii jjjj
; each swizzle table is 512 bytes long, 2048 bytes for all four. They need to be prec
swizzle
; Draw a tile directly to the graphics screen as a sprite
;
; Y = screen address
@ -147,49 +148,65 @@ swizzle
; A = $0001 = ignore mask
; = $0080 = vflip
; = $0600 = palette select
* _DrawSwizzleTileToScreen
* :palette equ 240
* ; Tile data must be 0000 000w wxxy yzz0
* ; Tile mask is normal pixel data
* and #$0600
* sta :palette ; cache the palette bits
_DrawTileToScreenX
rtl
* lda #^swizzle
* sta tmp+2
phb
phd ; Save the curren direct page and bank
* ldal tiledata+{]line*4},x
* ora :palette
* sta tmp
* lda: {]line*SHR_LINE_WIDTH},y
* andl tiledata+{]line*4}+32,x
* ora [tmp]
* sta: {]line*SHR_LINE_WIDTH},y
ldal tool_direct_page ; Can't assume where we are
clc
adc #$100 ; Sprite space is on the second page
tcd
* tay
* lda swizzle,y
pei DP2_TILEDATA_AND_BANK01_BANKS ; Push the two bank we need
plb ; Pop off the tile data bank
; lda #W11_S0
; stz SwizzlePtr
; lda #^W11_S0
; sta SwizzlePtr+2
* phb
* pea $0101
* plb
* plb
]line equ 0
lup 8
ldy tiledata+{]line*4}+2,x ; load the 8-bit NES tile data
; lda [SwizzlePtr],y ; lookup the swizzle value
; db LDA_IND_LONG_IDX,SwizzlePtr
; lda tiledata+{]line*4}+2,x
sta tmp_sprite_data+{]line*4}+2
* ]line equ 0
* lup 8
* lda: {]line*SHR_LINE_WIDTH}+2,y
* andl tiledata+{]line*4}+32+2,x
* oral tiledata+{]line*4}+2,x
* sta: {]line*SHR_LINE_WIDTH}+2,y
* lda: {]line*SHR_LINE_WIDTH},y
* andl tiledata+{]line*4}+32,x
* oral tiledata+{]line*4},x
* sta: {]line*SHR_LINE_WIDTH},y
* ]line equ ]line+1
* --^
* plb
* rtl ; special exit
ldy tiledata+{]line*4},x ; load the 8-bit NES tile data
; lda [SwizzlePtr],y ; lookup the swizzle value
; db LDA_IND_LONG_IDX,SwizzlePtr
; lda tiledata+{]line*4},x
sta tmp_sprite_data+{]line*4}
]line equ ]line+1
--^
plb ; Pop off bank 01
]line equ 0
lup 8
ldal tiledata+{]line*4}+32+2,x
eor #$FFFF
and: {]line*SHR_LINE_WIDTH}+2,y
ora tmp_sprite_data+{]line*4}+2
sta: {]line*SHR_LINE_WIDTH}+2,y
ldal tiledata+{]line*4}+32,x
eor #$FFFF
and: {]line*SHR_LINE_WIDTH},y
ora tmp_sprite_data+{]line*4}
sta: {]line*SHR_LINE_WIDTH},y
]line equ ]line+1
--^
; Restore the direct page and bank
pld
plb
rtl
pal_select dw $3333,$6666,$9999,$CCCC

View File

@ -404,25 +404,67 @@ _SetTile
jmp _PushDirtyTileX
:set_user_tile
and #$01FF
jsr _GetTileAddr ; The user tile callback needs access to this info, too, but
sta TileStore+TS_TILE_ADDR,x ; we just give the base tile address (hflip bit is ignored)
lda #UserTileDispatch
stal K_TS_BASE_TILE_DISP,x
lda #UserTileDispatch
stal K_TS_SPRITE_TILE_DISP,x
lda #UserTileDispatch
stal K_TS_ONE_SPRITE,x
jmp _PushDirtyTileX
; Trampoline / Dispatch table for user-defined tiles. If the user calls the GTESetCustomTileCallback toolbox routine,
; then this value is patched out. Calling GTESetCustomTileCallback with NULL will disconnect the user's routine.
; Trampoline / Dispatch table for user-defined tiles. If the user calls the GTESetAddress toolbox routine,
; then this value is patched out. Calling GTESetAddress with NULL will disconnect the user's routine.
;
; This hook copies essential information from the TileStore into a local record on the direct page and then
; passes that record to callback function. We are in the second direct page of the GTE bank 0 space.
UserTileDispatch
ldal TileStore+TS_TILE_ID,x ; Replace the tile data address (unset) with the tile id
_UTDPatch jsl UserHook1 ; Call the users code
plb ; Restore the data bank
lda TileStore+TS_TILE_ID,x
sta USER_TILE_ID
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
sta USER_TILE_CODE_PTR+2
lda TileStore+TS_CODE_ADDR_LOW,x
sta USER_TILE_CODE_PTR
lda TileStore+TS_TILE_ADDR,x
sta USER_TILE_ADDR
ldx #USER_TILE_RECORD ; pass the direct page offset to the user
pei DP2_TILEDATA_AND_TILESTORE_BANKS ; set the bank to the tiledata bank
plb
_UTDPatch jsl UserHook1 ; Call the users code
plb ; Restore the curent bank
; When the user's code returns, it can ask GTE to invoke a utility routine to copy data from the
; temporary buffer space into the code field
cmp #0
beq :done
jmp FastCopyTmpDataA ; Non-zero value to continue additional work
:done
rts
; Stub to have a valid address for initialization / reset
UserHook1 rtl
; Fast utility function to just copy tile data straight from the tmp_tile_data buffer to the code field. This is only
; used by the user callback, so we can assume knowledge of the values on the direct page.
FastCopyTmpDataA
pei USER_TILE_CODE_PTR+2
ldy USER_TILE_CODE_PTR
plb
]line equ 0
lup 8
lda tmp_tile_data+{]line*4}
sta: $0004+{]line*$1000},y
lda tmp_tile_data+{]line*4}+2
sta: $0001+{]line*$1000},y
]line equ ]line+1
--^
plb
rts
; X = Tile Store offset
; Y = Engine Mode Base Table address
; A = Table proc index

View File

@ -176,6 +176,7 @@ zpToUse = userId+4
pld ; Restore the caller's direct page
:exit
ldx #0 ; No error
ldy #6 ; Remove the 6 input bytes
jml ToStrip
@ -1011,8 +1012,28 @@ _TSSetAddress
lda :ptr+2,s
sta ExtUpdateBG0Tiles+2
bra :out
:next_5
:next_5 cmp #userTileCallback
bne :next_6
lda :ptr,s
ora :ptr+2,s
beq :utd_restore
lda :ptr,s
stal _UTDPatch+1 ; long addressing because we're patching code in the K bank
lda :ptr+1,s
stal _UTDPatch+2
brl :out
:utd_restore
lda #UserHook1
stal _UTDPatch+1
lda #>UserHook1
stal _UTDPatch+2
brl :out
:next_6
:out
_TSExit #0;#6

View File

@ -608,11 +608,11 @@ CopyTileToDyn
tax
tya
and #$001F ; Maximum of 32 dynamic tiles
and #$001F ; Maximum of 32 dynamic tiles
asl
asl ; 4 bytes per page
asl ; 4 bytes per page
adc BlitterDP ; Add to the bank 00 base address
adc #$0100 ; Go to the next page
adc #$0100 ; Go to the next page
tay
jsr CopyTileDToDyn ; Copy the tile data
jmp CopyTileMToDyn ; Copy the tile mask

View File

@ -4,6 +4,12 @@
; not needed to improve rendering speed.
ConstTile0Fast
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
pha ; and put on the stack for later. Has TileStore bank in high byte.
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
; lda TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated)
plb
lda #0
sta: $0001,y
sta: $0004,y
@ -273,6 +279,12 @@ FastCopyTileDataAndMaskV
; This is called via a JMP (abs,x) with an extra byte on the stack that holds the bank
; register value. This must be restored prior to returning
CopyTileAFast
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
pha ; and put on the stack for later. Has TileStore bank in high byte.
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
lda TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated)
plb
tax
_CopyTileAFast
]line equ 0
@ -288,6 +300,12 @@ _CopyTileAFast
CopyTileVFast
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
pha ; and put on the stack for later. Has TileStore bank in high byte.
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
lda TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated)
plb
tax
_CopyTileVFast
]src equ 7

View File

@ -3,6 +3,7 @@
_RenderTile
lda TileStore+TS_SPRITE_FLAG,x ; any sprites on this tile?
bne _HasSprites
jmp (K_TS_BASE_TILE_DISP,x) ; go to the tile copy routine
; Probably best to rework this to just jump to the tile routine directly, even if there
; is some boilerplate code because it is useful to be able to access the data bank before

View File

@ -10,8 +10,8 @@ TS_DIRTY equ {TILE_STORE_SIZE*1} ; Flag. Used to prevent a ti
TS_SPRITE_FLAG equ {TILE_STORE_SIZE*2} ; Bitfield of all sprites that intersect this tile. 0 if no sprites.
TS_TILE_ADDR equ {TILE_STORE_SIZE*3} ; cached value, the address of the tiledata for this tile
TS_CODE_ADDR_LOW equ {TILE_STORE_SIZE*4} ; const value, address of this tile in the code fields
TS_CODE_ADDR_HIGH equ {TILE_STORE_SIZE*5}
TS_WORD_OFFSET equ {TILE_STORE_SIZE*6} ; const value, word offset value for this tile if LDA (dp),y instructions re used
TS_CODE_ADDR_HIGH equ {TILE_STORE_SIZE*5} ; the top byte of this address holds the GTE data bank for easy restore
TS_WORD_OFFSET equ {TILE_STORE_SIZE*6} ; const value, word offset value for this tile if LDA (dp),y instructions are used
TS_JMP_ADDR equ {TILE_STORE_SIZE*7} ; const value, address of the 32-byte snippet space for this tile
TS_SCREEN_ADDR equ {TILE_STORE_SIZE*8} ; cached value of on-screen location of tile. Used for DirtyRender.