mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2025-03-10 17:33:24 +00:00
Add initial build-out of BG1 tile map support
This commit is contained in:
parent
4c5b090afe
commit
e607612344
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
17
src/Render.s
17
src/Render.s
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
277
src/TileMap.s
277
src/TileMap.s
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
--^
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user