From 1d17b802add172be30a5b87cd561f9c35f71e705 Mon Sep 17 00:00:00 2001 From: Lucas Scharenbroich Date: Thu, 5 Aug 2021 08:20:38 -0500 Subject: [PATCH] Add basic tilemap support back in --- src/Actions.s | 32 ---- src/App.Main.s | 21 +-- src/App.Tile.s | 1 - src/App.s | 58 +------ src/Render.s | 11 -- src/TileMap.s | 325 +++++++++++++++++++++++++++++++++++++++ src/blitter/BG1.s | 58 ------- src/blitter/DirectPage.s | 130 ++++++++-------- src/blitter/Tiles.s | 16 -- src/blitter/Vert.s | 2 - 10 files changed, 389 insertions(+), 265 deletions(-) create mode 100644 src/TileMap.s diff --git a/src/Actions.s b/src/Actions.s index a1a903b..ec1f4e7 100644 --- a/src/Actions.s +++ b/src/Actions.s @@ -276,35 +276,3 @@ _DoTimers pla rts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/App.Main.s b/src/App.Main.s index c59043e..d77bafc 100644 --- a/src/App.Main.s +++ b/src/App.Main.s @@ -1196,23 +1196,4 @@ qtRec adrl $0000 put blitter/Tiles.s put blitter/Vert.s put blitter/BG1.s -; put RotData.s - - - - - - - - - - - - - - - - - - - + PUT TileMap.s diff --git a/src/App.Tile.s b/src/App.Tile.s index 0954dcc..1d7ecc7 100644 --- a/src/App.Tile.s +++ b/src/App.Tile.s @@ -64,4 +64,3 @@ tiledata ENT hex 89ABCDEF tileend - diff --git a/src/App.s b/src/App.s index 78d83e0..629f277 100644 --- a/src/App.s +++ b/src/App.s @@ -25,61 +25,5 @@ ASM RotData.s DS 0 KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data) -; ALI BANK + ALI BANK SNA RotData - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Render.s b/src/Render.s index 5c27174..e67a59b 100644 --- a/src/Render.s +++ b/src/Render.s @@ -92,14 +92,3 @@ Render jsr _RestoreBG0Opcodes rts - - - - - - - - - - - diff --git a/src/TileMap.s b/src/TileMap.s new file mode 100644 index 0000000..e717a20 --- /dev/null +++ b/src/TileMap.s @@ -0,0 +1,325 @@ +; Routines for handling tilemaps +; +; This module contains higher-level functions than the low-level tile rendering routines. The +; goal here is to take a rectangular tilemap data structure and efficiently render it into +; code buffer. Especially inportant is to only draw new tiles as they come into view. +; +; Also, we maintain a tilemap cache to track the current state of the tiles rendered into +; the code field so if, by chance, a tile that comes into view is the same as a tile that +; has already been drawn, then there is no reason to update it. This happen quite often +; in actual games since the primary background is often large empty areas, or runs +; of repeating tiles. + +_UpdateBG0TileMap +:Left equ tmp0 +:Right equ tmp1 +:Top equ tmp2 +:Bottom equ tmp3 + +:Width equ tmp4 ; Used in DrawRectBG0 +: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 StartY ; calculate the tile index of the current location + and #$FFF8 + lsr + lsr + sta BG0TileOriginY + + lda OldStartY + and #$FFF8 + lsr + lsr + sta OldBG0TileOriginY + + lda StartX + and #$FFF8 + lsr + lsr + sta BG0TileOriginX + + lda OldStartX + and #$FFF8 + lsr + lsr + sta OldBG0TileOriginY + +; Figure out the two rectangular regions that need to be updated. We check for changes in Y-direction +; first because it's a bit more efficient to redraw tiles in long horizontal strips, because we do not +; have to skip to different banks. +; +; +---------------------------+----------+ <-- Top +; | | | +; | | New | +; | | | +; | Old Area | (drawn) | +; | | (second) | +; | | | +; +---------------------------+==========| +; | | +; | New Area (drawn first) | +; | | +; +--------------------------------------+ <-- Bottom +; ^ ^ +; | | +; +--- Left Right --+ + + stz :Left ; prepare to do the entire screen + lda ScreenTileWidth ; and then whack off the parts + sta :Right ; that are not needed + + stz :Top + lda ScreenTileHeight + sta :Bottom + + lda BG0TileOriginY + cmp OldBG0TileOriginY + beq :NoYUpdate ; if equal, don't change Y + + sec + sbc OldBG0TileOriginY ; 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 + sta :Bottom ; to fill in the top row(s) from 0 to Y_new - Y_old - 1 + bra :DoYUpdate + +:DoBottom + eor #$FFFF ; same explanation as above, except we are filling in from + inc a ; Bottom - (Y_new - Y_old) to Bottom + clc + adc ScreenTileHeight + sta :Top + +:DoYUpdate + jsr :DrawRectBG0 ; 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 +; +; +---------------------------+----------+ +; | | | +; | | New | +; | | | +; | Old Area | (drawn) | +; | | (second) | +; | | | +; +---------------------------+==========| <-- Top +; |//////////////////////////////////////| +; |// New Area (drawn first) ////////////| +; |//////////////////////////////////////| +; +--------------------------------------+ <-- Bottom +; ^ ^ +; | | +; +--- Left Right --+ + + lda :Top + beq :drewTop + dec a ; 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 a ; so do Y+1 to HEIGHT + sta :Top + lda ScreenTileHeight + sta :Bottom + +; +---------------------------+----------+ <-- Top +; | | | +; | | New | +; | | | +; | Old Area | (drawn) | +; | | (second) | +; | | | <-- Bottom +; +---------------------------+==========| +; |//////////////////////////////////////| +; |// New Area (drawn first) ////////////| +; |//////////////////////////////////////| +; +--------------------------------------+ +; ^ ^ +; | | +; +--- Left Right --+ + +; The Top an 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 BG0TileOriginX ; Did the first column of the tile map change from before? + cmp OldBG0TileOriginX ; Did it change from before? + beq :NoXUpdate ; no, so we can ignore this + + sec + sbc BG0TileOriginX ; 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 + sta :Right + bra :DoXUpdate + +:DoRightSide + eor #$FFFF + inc + clc + adc ScreenTileWidth + sta :Left + +:DoXUpdate + jsr :DrawRectBG0 ; 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. +:DrawRectBG0 + + lda :Bottom + sec + sbc :Top + inc + sta :Height + + lda :Right + sec + sbc :Left + inc + sta :Width + +; Compute the offset into the tile array of the top-left corner + + lda :Left + clc + adc BG0TileOriginX + sta :GlobalTileIdxX + + lda :Top + clc + adc BG0TileOriginY ; This is the global verical index + sta :GlobalTileIdxY + + ldx TileMapWidth + jsr :MulAX + clc + adc :GlobalTileIdxX + asl ; Double for word sizes + sta :Offset ; Stash the pointer offset in Y + + lda TileMapWidth + 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 StartYMod208 ; 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 + sta :BlkY ; This is the Y-block we start drawing from + + lda StartXMod164 ; Dx the same thing for X, except only need to clamp by 4 + and #$FFFC + lsr + lsr + clc + adc :Left + 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 [TileMapPtr],y + iny ; pre-increment the address. A bit faster than two "INC DP" instructions + iny + sty :Offset + + ldx :BlkX + ldy :BlkY + jsr CopyTile + + inc :BlkX ; Move to the next block + 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 + + inc :BlkY + dec :Height ; Have we done all of the rows? + bne :yloop + + pla ; Pop off cached values + pla + + rts + + +; Quick multiplication of the accumulator and x-register +; A = A * X +:MulAX + stx :MulA + cmp :MulA ; Put the smaller value in MulA (less shifts on average) + bcc :swap + sta :MulB + bra :entry +:swap stx :MulB + sta :MulA + +:entry + lda #0 + +; Start shifting and adding. We actually do an extra +; shift if MulA is zero, but a zero value does not +; change the result and it allows us to eliminate a +; branch on the inner loop + +:loop + lsr :MulA ; shift out the LSB + bcc :skip ; zero is no multiply + clc + adc :MulB + +:skip + asl :MulB ; double the multplicand + ldx :MulA + bne :loop + + rts diff --git a/src/blitter/BG1.s b/src/blitter/BG1.s index c7db57c..d3f8b5c 100644 --- a/src/blitter/BG1.s +++ b/src/blitter/BG1.s @@ -609,61 +609,3 @@ ApplyBG1OffsetValues :none rts BG1YCache ds 32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/blitter/DirectPage.s b/src/blitter/DirectPage.s index 625f34d..04306ed 100644 --- a/src/blitter/DirectPage.s +++ b/src/blitter/DirectPage.s @@ -1,87 +1,81 @@ ; Direct page locations used by the engine -ScreenHeight equ 0 ; Height of the playfield in scan lines -ScreenWidth equ 2 ; Width of the playfield in bytes -ScreenY0 equ 4 ; First vertical line on the physical screen of the playfield -ScreenY1 equ 6 ; End of playfield on the physical screen. If the height is 20 and Y0 is -ScreenX0 equ 8 ; 100, then ScreenY1 = 120. -ScreenX1 equ 10 -ScreenTileHeight equ 12 ; Height of the playfield in 8x8 blocks -ScreenTileWidth equ 14 ; Width of the playfield in 8x8 blocks - -StartX equ 16 ; Which code buffer byte is the left edge of the screen. Range = 0 to 167 -StartY equ 18 ; Which code buffer line is the top of the screen. Range = 0 to 207 -EngineMode equ 20 ; Defined the mode/capabilities that are enabled - ; bit 0: 0 = Single Background, 1 = Parallax -DirtyBits equ 22 ; Identify values that have changed between frames - -BG1DataBank equ 24 ; Data bank that holds BG1 layer data -BG1AltBank equ 26 ; Alternate BG1 bank - -BlitterDP equ 28 ; Direct page address the holder blitter data - -OldStartX equ 30 -OldStartY equ 32 - -LastPatchOffset equ 34 ; Offset into code field that was patched with BRA instructions -StartXMod164 equ 36 -StartYMod208 equ 38 - -BG1StartX equ 40 ; Logical offset of the second background -BG1StartXMod164 equ 42 - -BG1StartY equ 44 -BG1StartYMod208 equ 46 - -OldBG1StartX equ 48 -OldBG1StartY equ 50 - -BG1OffsetIndex equ 52 - -BankLoad equ 128 - -bstk equ 208 ; 16-byte stack to push bank addresses - -tmp8 equ 224 -tmp9 equ 226 -tmp10 equ 228 - -tmp0 equ 240 ; 16 bytes of temporary space to be used as scratch -tmp1 equ 242 -tmp2 equ 244 -tmp3 equ 246 -tmp4 equ 248 -tmp5 equ 250 -tmp6 equ 252 -tmp7 equ 254 - -DIRTY_BIT_BG0_X equ $0001 -DIRTY_BIT_BG0_Y equ $0002 -DIRTY_BIT_BG1_X equ $0004 -DIRTY_BIT_BG1_Y equ $0008 - - - - - - - - - +ScreenHeight equ 0 ; Height of the playfield in scan lines +ScreenWidth equ 2 ; Width of the playfield in bytes +ScreenY0 equ 4 ; First vertical line on the physical screen of the playfield +ScreenY1 equ 6 ; End of playfield on the physical screen. If the height is 20 and Y0 is +ScreenX0 equ 8 ; 100, then ScreenY1 = 120. +ScreenX1 equ 10 +ScreenTileHeight equ 12 ; Height of the playfield in 8x8 blocks +ScreenTileWidth equ 14 ; Width of the playfield in 8x8 blocks +StartX equ 16 ; Which code buffer byte is the left edge of the screen. Range = 0 to 167 +StartY equ 18 ; Which code buffer line is the top of the screen. Range = 0 to 207 +EngineMode equ 20 ; Defined the mode/capabilities that are enabled + ; bit 0: 0 = Single Background, 1 = Parallax +DirtyBits equ 22 ; Identify values that have changed between frames +BG1DataBank equ 24 ; Data bank that holds BG1 layer data +BG1AltBank equ 26 ; Alternate BG1 bank +BlitterDP equ 28 ; Direct page address the holder blitter data +OldStartX equ 30 +OldStartY equ 32 +LastPatchOffset equ 34 ; Offset into code field that was patched with BRA instructions +StartXMod164 equ 36 +StartYMod208 equ 38 +BG1StartX equ 40 ; Logical offset of the second background +BG1StartXMod164 equ 42 +BG1StartY equ 44 +BG1StartYMod208 equ 46 +OldBG1StartX equ 48 +OldBG1StartY equ 50 +BG1OffsetIndex equ 52 +BG0TileOriginX equ 54 ; Coordinate in the tile map that corresponds to the top-left corner +BG0TileOriginY equ 56 +OldBG0TileOriginX equ 58 +OldBG0TileOriginY equ 60 +BG1TileOriginX equ 62 ; Coordinate in the tile map that corresponds to the top-left corner +BG1TileOriginY equ 64 +OldBG1TileOriginX equ 66 +OldBG1TileOriginY equ 68 +TileMapWidth equ 70 +TileMapHeight equ 72 +TileMapPtr equ 74 +Next equ 78 +BankLoad equ 128 +blttmp equ 192 ; 32 bytes of local cache/scratch space +tmp8 equ 224 +tmp9 equ 226 +tmp10 equ 228 +tmp11 equ 230 +tmp12 equ 232 +tmp13 equ 234 +tmp14 equ 236 +tmp15 equ 238 +tmp0 equ 240 ; 16 bytes of temporary space to be used as scratch +tmp1 equ 242 +tmp2 equ 244 +tmp3 equ 246 +tmp4 equ 248 +tmp5 equ 250 +tmp6 equ 252 +tmp7 equ 254 +DIRTY_BIT_BG0_X equ $0001 +DIRTY_BIT_BG0_Y equ $0002 +DIRTY_BIT_BG1_X equ $0004 +DIRTY_BIT_BG1_Y equ $0008 diff --git a/src/blitter/Tiles.s b/src/blitter/Tiles.s index ab6fcee..5d27f21 100644 --- a/src/blitter/Tiles.s +++ b/src/blitter/Tiles.s @@ -235,19 +235,3 @@ CopyTile sta $7003,y rep #$20 rts - - - - - - - - - - - - - - - - diff --git a/src/blitter/Vert.s b/src/blitter/Vert.s index 7e1d144..c82ca96 100644 --- a/src/blitter/Vert.s +++ b/src/blitter/Vert.s @@ -189,5 +189,3 @@ CopyRTableToStkAddr :x01 ldal RTable+00,x sta: STK_ADDR+$0000,y :none rts - -