Add initial build-out of BG1 tile map support

This commit is contained in:
Lucas Scharenbroich 2021-08-19 01:22:36 -05:00
parent 4c5b090afe
commit e607612344
8 changed files with 341 additions and 31 deletions

View File

@ -145,7 +145,7 @@ mixed cmp #$FFFF ; All 1's in the mask is fully transparent
ldx _X_REG ; Get the addressing offset
ldal JTableOffset,x ; Get the address offset and add to the base address
clc ; may be able to be removed...
; clc ; may be able to be removed...
adc _BASE_ADDR ; of the current code field line
adc #{]3&$F000} ; adjust for the current row offset
sta: ]3+1,y
@ -175,3 +175,6 @@ transparent
next
eom

View File

@ -3,9 +3,9 @@ MoveLeft
adc StartX ; Increment the virtual X-position
jsr SetBG0XPos
; lda StartX
; lsr
; jsr SetBG1XPos
lda StartX
lsr
jsr SetBG1XPos
jsr Render
rts
@ -19,9 +19,9 @@ MoveRight
lda #0
jsr SetBG0XPos
; lda StartX
; lsr
; jsr SetBG1XPos
lda StartX
lsr
jsr SetBG1XPos
jsr Render
pla
@ -294,3 +294,4 @@ _DoTimers

View File

@ -128,13 +128,7 @@ NO_MUSIC equ 1 ; turn music + tool load
; Set up our level data
jsr BG0SetUp
ldx #0
ldy #0
lda #56
jsr CopyTile
; jsr Render
jsr WaitForKey
jsr BG1SetUp
; Allocate room to load data
@ -142,13 +136,17 @@ NO_MUSIC equ 1 ; turn music + tool load
sta BankLoad ; Store "Bank Pointer"
jsr MovePlayerToOrigin ; Put the player at the beginning of the map
lda #74
jsr SetBG0XPos
lda #DIRTY_BIT_BG0_REFRESH ; Redraw all of the tiles on the next Render
ora #DIRTY_BIT_BG1_REFRESH
tsb DirtyBits
; jsr DoTiles
; jsr DoLoadBG1
; jsr Demo
jsr Render
EvtLoop
jsr ReadControl
and #$007F ; Ignore the buttons for now
@ -273,6 +271,8 @@ Fatal brk $00
MovePlayerToOrigin
lda #0 ; Set the player's position
jsr SetBG0XPos
lda #0
jsr SetBG1XPos
lda TileMapHeight
asl
@ -280,7 +280,10 @@ MovePlayerToOrigin
asl
sec
sbc ScreenHeight
pha
jsr SetBG0YPos
pla
jsr SetBG1YPos
rts
@ -397,10 +400,6 @@ DoTiles
lda :tile,s
jsr CopyTile
; lda :tile,s
; eor #$0003
; sta :tile,s
lda :column,s
inc
sta :column,s
@ -1298,3 +1297,13 @@ qtRec adrl $0000
PUT TileMap.s
PUT App.TileMapBG0.s
PUT App.TileMapBG1.s

View File

@ -65,17 +65,18 @@ Render
; used in all of the other loops
jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
jsr _ApplyBG1YPos
; _ApplyBG0Xpos need to be split because we have to set the offsets, then draw in any updated tiles, and
; finally patch out the code field. Right now, the BRA operand is getting overwritten by tile data.
jsr _ApplyBG0XPosPre
jsr _ApplyBG1XPosPre
jsr _UpdateBG0TileMap
; jsr _UpdateBG1TileMap
jsr _ApplyBG0XPos ; Patch the PEA instructions with exit BRA opcode
; jsr _ApplyBG1YPos ; Adjust the index values into the BG1 bank buffer
; jsr _ApplyBG1XPos ; Adjust the direct page pointers to the BG1 bank
jsr _ApplyBG1XPos ; Patch the PEA instructions with exit BRA opcode
; Copy any tiles that have come into view
@ -112,6 +113,11 @@ Render
lda StartX
sta OldStartX
lda BG1StartY
sta OldBG1StartY
lda BG1StartX
sta OldBG1StartX
stz DirtyBits
rts
@ -129,5 +135,10 @@ Render

View File

@ -230,7 +230,6 @@ _UpdateBG0TileMap
; This is a private subroutine that draws in tiles into the code fields using the
; data from the tilemap and the local :Top, :Left, :Bottom and :Right parameters.
:DrawRectBG0
lda :Bottom
sec
sbc :Top
@ -383,3 +382,279 @@ _UpdateBG0TileMap
bne :loop
rts
; Exact same logic as _UpdateBG0TileMap, except for the other background
_UpdateBG1TileMap
:Left equ tmp0
:Right equ tmp1
:Top equ tmp2
:Bottom equ tmp3
lda BG1StartY ; calculate the tile index of the current location
lsr
lsr
lsr
sta BG1TileOriginY
lda OldBG1StartY
lsr
lsr
lsr
sta OldBG1TileOriginY
lda BG1StartX
lsr
lsr
sta BG1TileOriginX
lda OldBG1StartX
lsr
lsr
sta OldBG1TileOriginX
; Figure out the two rectangular regions that need to be updated.
stz :Left ; prepare to do the entire screen
lda ScreenTileWidth ; and then whack off the parts
sta :Right ; that are not needed
stz :Top ; since the ranges are inclusive, we are
lda ScreenTileHeight ; always going to be drawing width+1 tiles
sta :Bottom ; which takes care of edge tiles.
; If we are supposed to refresh the whole field, just do that and return
lda #DIRTY_BIT_BG1_REFRESH
bit DirtyBits
beq :NoRefresh
trb DirtyBits ; Clear the dirty bit
:FullScreen jmp _DrawRectBG1 ; Let the DrawRectBG1 RTS take care of the return for us
:NoRefresh
lda BG1TileOriginY
cmp OldBG1TileOriginY
beq :NoYUpdate ; if equal, don't change Y
sec
sbc OldBG1TileOriginY ; find the difference; D = Y_new - Y_old
bpl :DoBottom ; if we scrolled up, fill in the bottom row(s)
eor #$FFFF ; if we scrolled down, Y_new < Y_old and we need
cmp :Bottom ; to fill in the top row(s) from 0 to Y_new - Y_old - 1
bcs :FullScreen ; If the displacement was very large, just fill in the whole screen
sta :Bottom
bra :DoYUpdate
:DoBottom
eor #$FFFF ; same explanation as above, except we are filling in from
inc ; Bottom - (Y_new - Y_old) to Bottom
clc
adc ScreenTileHeight
bmi :FullScreen
sta :Top
:DoYUpdate
jsr _DrawRectBG1 ; Fill in the rectangle.
; We performed an update in the Y-direction, so now change the bounds so
; an update in the X-direction will not draw too many rows
lda :Top
beq :drewTop
dec ; already did Y to HEIGHT, so only need to draw from
sta :Bottom ; 0 to (Y-1) for any horizontal updates
stz :Top
bra :NoYUpdate
:drewTop
lda :Bottom ; opposite, did 0 to Y
inc ; so do Y+1 to HEIGHT
sta :Top
lda ScreenTileHeight
sta :Bottom
; The Top and Bottom are set the the correct values to draw in whatever potential range of tiles
; need to be draws if there was any horizontal displacement
:NoYUpdate
lda BG1TileOriginX ; Did the first column of the tile map change from before?
cmp OldBG1TileOriginX ; Did it change from before?
beq :NoXUpdate ; no, so we can ignore this
sec
sbc OldBG1TileOriginX ; find the difference
bpl :DoRightSide ; did we move in a pos or neg?
; Handle the two sides in an analagous way as the vertical code
eor #$FFFF
cmp :Right
bcs :FullScreen
sta :Right
bra :DoXUpdate
:DoRightSide
eor #$FFFF
inc
clc
adc ScreenTileWidth
bmi :FullScreen
sta :Left
:DoXUpdate
jsr _DrawRectBG1 ; Fill in the rectangle.
:NoXUpdate
rts
; This is a private subroutine that draws in tiles into the code fields using the
; data from the tilemap and the local :Top, :Left, :Bottom and :Right parameters.
_DrawRectBG1
:Left equ tmp0
:Right equ tmp1
:Top equ tmp2
:Bottom equ tmp3
:Width equ tmp4
:Height equ tmp5
:MulA equ tmp6 ; Scratch space for multiplication
:MulB equ tmp7
:Offset equ tmp8 ; Address offset into the tilemap
:Span equ tmp9
:GlobalTileIdxX equ tmp10
:GlobalTileIdxY equ tmp11
:BlkX equ tmp12
:BlkY equ tmp13
lda :Bottom
sec
sbc :Top
inc
sta :Height ; Maximum value of 26 (top = 0, bottom = 25)
lda :Right
sec
sbc :Left
inc
sta :Width ; Maximum value of 41 (left = 0, right = 40)
; Compute the offset into the tile array of the top-left corner
lda :Left
clc
adc BG1TileOriginX
sta :GlobalTileIdxX
lda :Top
clc
adc BG1TileOriginY ; This is the global verical index
sta :GlobalTileIdxY
ldx BG1TileMapWidth
jsr :MulAX
clc
adc :GlobalTileIdxX
asl ; Double for word sizes
sta :Offset ; Stash the pointer offset in Y
; Draw the tiles
lda BG1TileMapWidth
sec
sbc :Width
asl ; This is the number of bytes to move the Offset to advance from the end of
sta :Span ; one line to the beginning of the next
; Now we need to figure out the code field tile coordinate of corner of
; play field. That is, becuase the screen is scrolling, the location of
; tile (0, 0) could be anywhere within the code field
lda BG1StartYMod208 ; This is the code field line that is at the top of the screen
and #$FFF8 ; Clamp to the nearest block
lsr
lsr
lsr ; Could optimize because the Tile code shifts back....
clc
adc :Top
cmp #MAX_TILE_Y+1 ; Top can be less than or equal to 25
bcc *+5
sbc #MAX_TILE_Y+1
sta :BlkY ; This is the Y-block we start drawing from
lda BG1StartXMod164 ; Do the same thing for X, except only need to clamp by 4
and #$FFFC
lsr
lsr
clc
adc :Left
cmp #MAX_TILE_X+1 ; Left can be less than or equal to 40
bcc *+5
sbc #MAX_TILE_X+1
sta :BlkX
; Call the copy tile routine to blit the tile data into the playfield
;
; A = Tile ID (0 - 1023)
; X = Tile column (0 - 40)
; Y = Tile row (0 - 25)
pei :BlkX ; cache the starting X-block index to restore later
pei :Width ; cache the Width value to restore later
:yloop
:xloop
ldy :Offset ; Set up the arguments and call the tile blitter
lda [BG1TileMapPtr],y
iny ; pre-increment the address. A bit faster than two "INC DP" instructions
iny
sty :Offset
ldx :BlkX
ldy :BlkY
jsr CopyTileBG1
lda :BlkX
inc
cmp #MAX_TILE_X+1 ; If we go past the maximum block index, wrap around
bcc *+5
lda #0
sta :BlkX
dec :Width ; Decrement out count
bne :xloop
lda :Offset ; Move to the next line of the Tile Map
clc
adc :Span
sta :Offset
lda 3,s ; Reset the BlkX
sta :BlkX
lda 1,s ; Reset the width
sta :Width
lda :BlkY ; The y lookup has a double-length array, may not need the bounds check
inc
cmp #MAX_TILE_Y+1
bcc *+5
lda #0
sta :BlkY
dec :Height ; Have we done all of the rows?
bne :yloop
pla ; Pop off cached values
pla
rts

View File

@ -40,14 +40,16 @@ SetBG1YPos
; these are all direct page values
;
; Note: This routine can be optimized as an unrolled loop of PEI instructions
_ApplyBG1XPos
lda BG1StartX
_ApplyBG1XPosPre
lda BG1StartX ; This is the starting byte offset (0 - 163)
jsr Mod164
sta BG1StartXMod164
rts
_ApplyBG1XPos
lda #162
sec
sbc StartXMod164
sbc StartXMod164 ; Need to compensate for both BG0 and BG1 positions
bpl *+6
clc
adc #164
@ -609,3 +611,7 @@ ApplyBG1OffsetValues
:none rts
BG1YCache ds 32

View File

@ -54,11 +54,11 @@ _BltRange
; Now we need to set up the Bank, Stack Pointer and Direct Page registers for calling into
; the code field
lda StartX
bit #$01
beq :primary
lda BG1AltBank
bra :alt
; lda StartX
; bit #$01
; beq :primary
; lda BG1AltBank
; bra :alt
:primary lda BG1DataBank
:alt
pha
@ -95,3 +95,4 @@ stk_save lda #0000 ; load the stack
; we don't do anything sprite related; just call function pointers provided to us.
_RenderSprites
rts

View File

@ -27,7 +27,7 @@ Col2CodeOffset lup 82
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
]step equ ]step+1
--^
; dw CODE_TOP
dw CODE_TOP+{81*PER_TILE_SIZE}
; A parallel table to Col2CodeOffset that holds the offset to the exception handler address for each column
SNIPPET_SIZE equ 32
@ -37,6 +37,7 @@ JTableOffset lup 82
dw SNIPPET_BASE+{{81-]step}*SNIPPET_SIZE}
]step equ ]step+1
--^
dw SNIPPET_BASE+{81*SNIPPET_SIZE}
; Table of BRA instructions that are used to exit the code field. Separate tables for
; even and odd aligned cases.
@ -252,3 +253,6 @@ BG1YTable lup 208
BG1YOffsetTable lup 26
dw 1,1,1,2,2,2,2,2,1,1,1,0,0,0,0,0
--^