mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2025-02-17 01:30:52 +00:00
Tile rendering reorganization
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.
This commit is contained in:
parent
c4762888ed
commit
4e779e71d2
11
src/Core.s
11
src/Core.s
@ -8,12 +8,16 @@
|
||||
use .\Defs.s
|
||||
|
||||
; Feature flags
|
||||
NO_INTERRUPTS equ 1 ; turn off for crossrunner debugging
|
||||
NO_INTERRUPTS equ 0 ; turn off for crossrunner debugging
|
||||
NO_MUSIC equ 1 ; turn music + tool loading off
|
||||
|
||||
; External data provided by the main program segment
|
||||
tiledata EXT
|
||||
|
||||
; Sprite plane data and mask banks are provided as an exteral segment
|
||||
spritedata EXT
|
||||
spritemask EXT
|
||||
|
||||
; IF there are overlays, they are provided as an external
|
||||
Overlay EXT
|
||||
|
||||
@ -247,6 +251,8 @@ EngineReset
|
||||
jsr BuildBank
|
||||
]step equ ]step+4
|
||||
--^
|
||||
|
||||
jsr _InitDirtyTiles
|
||||
rts
|
||||
|
||||
; Allow the user to dynamically select one of the pre-configured screen sizes, or pass
|
||||
@ -370,6 +376,7 @@ ReadControl ENT
|
||||
|
||||
put Memory.s
|
||||
put Graphics.s
|
||||
put Sprite.s
|
||||
put Render.s
|
||||
put Timer.s
|
||||
put Script.s
|
||||
@ -379,7 +386,9 @@ ReadControl ENT
|
||||
put blitter/Tables.s
|
||||
put blitter/Template.s
|
||||
put blitter/Tiles.s
|
||||
put blitter/Tiles00000.s
|
||||
put blitter/Vert.s
|
||||
put blitter/BG0.s
|
||||
put blitter/BG1.s
|
||||
put TileMap.s
|
||||
|
@ -36,6 +36,9 @@ DoTimers EXT
|
||||
StartScript EXT
|
||||
StopScript EXT
|
||||
|
||||
; Sprite functions
|
||||
AddSprite EXT
|
||||
|
||||
; Direct access to internals
|
||||
DoScriptSeq EXT
|
||||
GetTileAddr EXT
|
||||
|
34
src/Memory.s
34
src/Memory.s
@ -67,7 +67,8 @@ InitMemory PushLong #0 ; space for result
|
||||
]step equ ]step+4
|
||||
--^
|
||||
|
||||
; Fill in a tables with the adddress of all 208 scanlines across all 13 banks
|
||||
; Fill in a table with the adddress of all 208 scanlines across all 13 banks. Also fill in
|
||||
; a shorter table that just holds the starting address of the 26 tile block rows.
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
@ -99,9 +100,38 @@ InitMemory PushLong #0 ; space for result
|
||||
adc #4 ; move to the next bank address
|
||||
tay
|
||||
cmp #4*13
|
||||
bcs :exit
|
||||
bcs :exit1
|
||||
brl :bloop
|
||||
:exit1
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
:bloop2
|
||||
lda BlitBuff+2,y ; Copy the high word first
|
||||
|
||||
sta BRowTableHigh,x ; Two rows per bank
|
||||
sta BRowTableHigh+{26*2},x
|
||||
sta BRowTableHigh+2,x
|
||||
sta BRowTableHigh+{26*2}+2,x
|
||||
|
||||
lda BlitBuff,y
|
||||
sta BRowTableLow,x
|
||||
sta BRowTableLow+{26*2},x
|
||||
clc
|
||||
adc #$8000
|
||||
sta BRowTableLow+2,x
|
||||
sta BRowTableLow+{26*2}+2,x
|
||||
|
||||
txa
|
||||
adc #4
|
||||
tax
|
||||
|
||||
tya
|
||||
adc #4 ; move to the next bank address
|
||||
tay
|
||||
cmp #4*13
|
||||
bcs :exit
|
||||
brl :bloop2
|
||||
:exit
|
||||
rts
|
||||
|
||||
|
134
src/Render.s
134
src/Render.s
@ -78,22 +78,39 @@ _Render
|
||||
jsr _ApplyBG0XPosPre
|
||||
jsr _ApplyBG1XPosPre
|
||||
|
||||
jsr _UpdateBG0TileMap
|
||||
jsr _UpdateBG1TileMap
|
||||
jsr _RenderSprites ; Once the BG0 X and Y positions are committed, update sprite data
|
||||
jsr _UpdateBG0TileMap ; and the tile maps. These subroutines build up a list of tiles
|
||||
jsr _UpdateBG1TileMap ; that need to be updated in the code field
|
||||
|
||||
jsr _ApplyBG0XPos ; Patch the PEA instructions with exit BRA opcode
|
||||
jsr _ApplyBG1XPos ; Patch the PEA instructions with exit BRA opcode
|
||||
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||
|
||||
; The code fields are locked in now and reder to be rendered
|
||||
jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode
|
||||
jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position
|
||||
|
||||
; The code fields are locked in now and ready to be rendered
|
||||
|
||||
jsr _ShadowOff
|
||||
|
||||
ldx #0 ; Blit the full virtual buffer to the screen
|
||||
ldy #8
|
||||
jsr _BltRange
|
||||
; Shadowing is turned off. Render all of the scan lines that need a second pass. These
|
||||
; are the lines that have a masked overlay, or a sprite. One optimization that can
|
||||
; be done here is that the lines can be rendered in any order since it is not shown
|
||||
; on-screen yet.
|
||||
|
||||
; jsr _RenderPhaseA ; Draw all of the background lines
|
||||
; jsr _RenderSprites ; Draw all of the sprites
|
||||
|
||||
; ldx #152 ; Blit the full virtual buffer to the screen
|
||||
; ldy #160
|
||||
; jsr _BltRange
|
||||
|
||||
; Turn shadowing back on
|
||||
|
||||
jsr _ShadowOn
|
||||
|
||||
; Now render all of the remaining lines in top-to-bottom (or bottom-to-top) order
|
||||
|
||||
; jsr _RenderPhaseB ; Draw the mix of background lines overlays and PEI slams
|
||||
|
||||
; ldx #0 ; Expose the top 8 rows
|
||||
; ldy #8
|
||||
; jsr _PEISlam
|
||||
@ -102,15 +119,21 @@ _Render
|
||||
; ldy #16
|
||||
; jsr _BltRange
|
||||
|
||||
lda ScreenY0 ; pass the address of the first line of the overlay
|
||||
asl
|
||||
tax
|
||||
lda ScreenAddr,x
|
||||
clc
|
||||
adc ScreenX0
|
||||
jsl Overlay
|
||||
; ldx #0 ; Blit the full virtual buffer to the screen
|
||||
; ldy #152
|
||||
; jsr _BltRange
|
||||
|
||||
ldx #8 ; Blit the full virtual buffer to the screen
|
||||
; lda ScreenY0 ; pass the address of the first line of the overlay
|
||||
; clc
|
||||
; adc #152
|
||||
; asl
|
||||
; tax
|
||||
; lda ScreenAddr,x
|
||||
; clc
|
||||
; adc ScreenX0
|
||||
; jsl Overlay
|
||||
|
||||
ldx #0 ; Blit the full virtual buffer to the screen
|
||||
ldy ScreenHeight
|
||||
jsr _BltRange
|
||||
|
||||
@ -131,3 +154,82 @@ _Render
|
||||
stz DirtyBits
|
||||
rts
|
||||
|
||||
MAX_SEGMENTS equ 128
|
||||
|
||||
PhaseACount ds 0
|
||||
PhaseATop ds 2*MAX_SEGMENTS
|
||||
PhaseABot ds 2*MAX_SEGMENTS
|
||||
PhaseAOp ds 2*MAX_SEGMENTS
|
||||
|
||||
PhaseBCount ds 0
|
||||
PhaseBTop ds 2*MAX_SEGMENTS
|
||||
PhaseBBot ds 2*MAX_SEGMENTS
|
||||
PhaseBOp ds 2*MAX_SEGMENTS
|
||||
|
||||
; Initialize the rendering tree to just render all of the code fields
|
||||
_InitRenderTree
|
||||
lda #1 ; Put the whole screen into Phase B
|
||||
sta PhaseBCount
|
||||
|
||||
lda #0
|
||||
sta PhaseBTop
|
||||
lda ScreenHeight
|
||||
sta PhaseBBot
|
||||
lda #_BltRange
|
||||
sta PhaseBOp
|
||||
|
||||
stz PhaseACount ; Phase A is initially empty
|
||||
rts
|
||||
|
||||
; Solid overlays are called in Phase B, but do not require the screen
|
||||
; to be drawn underneath, so this provides an opportunity to optimize
|
||||
; the rendering pipeline
|
||||
_AddSolidOverlay
|
||||
rts
|
||||
|
||||
; A mixed overlay signals that the underlying scan line data must be
|
||||
; redered first.
|
||||
_AddMixedOverlay
|
||||
rts
|
||||
|
||||
_RenderPhaseA
|
||||
ldy #0
|
||||
:loop
|
||||
cpy PhaseACount
|
||||
bcs :out
|
||||
phy ; save the counter
|
||||
|
||||
lda PhaseAOp,y ; dispatch to the appropriate function
|
||||
sta :op+1
|
||||
ldx PhaseATop,y
|
||||
lda PhaseABot,y
|
||||
tay
|
||||
:op jsr $0000
|
||||
|
||||
ply ; restore the counter
|
||||
iny
|
||||
iny
|
||||
bra :loop
|
||||
:out
|
||||
rts
|
||||
|
||||
_RenderPhaseB
|
||||
ldy #0
|
||||
:loop
|
||||
cpy PhaseBCount
|
||||
bcs :out
|
||||
phy ; save the counter
|
||||
|
||||
lda PhaseBOp,y ; dispatch to the appropriate function
|
||||
sta :op+1
|
||||
ldx PhaseBTop,y
|
||||
lda PhaseBBot,y
|
||||
tay
|
||||
:op jsr $0000
|
||||
|
||||
ply ; restore the counter
|
||||
iny
|
||||
iny
|
||||
bra :loop
|
||||
:out
|
||||
rts
|
||||
|
401
src/Sprite.s
401
src/Sprite.s
@ -1,5 +1,398 @@
|
||||
; Some sample code / utilities to help integrate compiled sprites int the GTE rendering
|
||||
; pipeline.
|
||||
; Functions for sprie handling. Mostly maintains the sprite list and provides
|
||||
; utility functions to calculate sprite/tile intersections
|
||||
;
|
||||
; The main point of this file to to establish calling conventions and provide a framework
|
||||
; for blitting a range of sprite lines, instead of always the full sprite.
|
||||
; The sprite plane actually covers two banks so that more than 32K can be used as a virtual
|
||||
; screen buffer. In order to be able to draw sprites offscreen, the virtual screen must be
|
||||
; wider and taller than the physical graphics screen.
|
||||
;
|
||||
; Initialize the sprite plane data and mask banks (all data = $0000, all masks = $FFFF)
|
||||
_InitSprite
|
||||
ldx #$FFFE
|
||||
lda #0
|
||||
:loop stal spritedata,x
|
||||
dex
|
||||
dex
|
||||
bpl :loop
|
||||
|
||||
ldx #$FFFE
|
||||
lda #$FFFF
|
||||
:loop stal spritemask,x
|
||||
dex
|
||||
dex
|
||||
bpl :loop
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; This function looks at the sprite list and renders the sprite plane data into the appropriate
|
||||
; tiles in the code field
|
||||
_RenderSprites
|
||||
ldx #0
|
||||
:loop lda _Sprites+SPRITE_STATUS,x
|
||||
beq :out
|
||||
cmp #SPRITE_STATUS_DIRTY
|
||||
beq :render
|
||||
:next inx
|
||||
inx
|
||||
bra :loop
|
||||
:out rts
|
||||
|
||||
; This is the complicated part; we need to draw the sprite into the sprite place, but then
|
||||
; calculate the code field tiles that this sprite potentially overlaps with and mark those
|
||||
; tiles as dirty.
|
||||
:render
|
||||
jsr _DrawTileSprite ; draw the sprite into the sprite plane
|
||||
|
||||
stz tmp0 ; flags to mark if the sprite is aligned to the code field grid or not
|
||||
stz tmp1
|
||||
|
||||
lda _Sprites+SPRITE_X,x ; Will need some special handling for X < 0
|
||||
clc
|
||||
adc StartXMod164
|
||||
|
||||
bit #$0003 ; If the botton bit are zero, then we're aligned
|
||||
beq *+4
|
||||
inc tmp0
|
||||
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
lsr
|
||||
lsr
|
||||
pha ; Save the tile
|
||||
|
||||
lda _Sprites+SPRITE_Y,x
|
||||
clc
|
||||
adc StartYMod208
|
||||
|
||||
bit #$0007
|
||||
beq *+4
|
||||
inc tmp1
|
||||
|
||||
cmp #208
|
||||
bcc *+5
|
||||
sbc #208
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
pha
|
||||
|
||||
; We have the code field tile that needs to be filled; calculate the address of the corresponding
|
||||
; location in the sprite plane
|
||||
;
|
||||
; Corner_X = -StartXMod164; if < -3, add 164
|
||||
; Corner_Y = -StartYMod208; if < -7, add 208
|
||||
|
||||
; lda StartXMod164
|
||||
; cmp #4
|
||||
; bcc *+5
|
||||
; sbc #164
|
||||
; eor #$FFFF
|
||||
; inc
|
||||
; pha
|
||||
|
||||
; lda StartYMod208
|
||||
; cmp #8
|
||||
; bcc *+5
|
||||
; sbc #208
|
||||
; eor #$FFFF
|
||||
; inc
|
||||
; clc
|
||||
; adc #NUM_BUFF_LINES
|
||||
; xba
|
||||
; clc
|
||||
; adc 1,s
|
||||
|
||||
; Copy the tile from the direct page scratch space into the playfield
|
||||
ply
|
||||
plx
|
||||
lda #$FFFF ; Sentinel value to pick direct page rendering
|
||||
jsr _PushDirtyTile ; Enqueue for processing
|
||||
|
||||
; jsr _CopyBG0Tile
|
||||
brl :next
|
||||
|
||||
; X = address of sprite _plane
|
||||
; Y = address of tile
|
||||
_ComposeSpriteAndTileNoMask
|
||||
phb
|
||||
pea #^tiledata
|
||||
plb
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda: tiledata+{]line*4},y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
lda: tiledata+{]line*4}+2,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
--^
|
||||
|
||||
plb
|
||||
plb
|
||||
rts
|
||||
|
||||
; X = address of sprite plane
|
||||
; Y = address of tile
|
||||
_ComposeSpriteAndTileWithMask
|
||||
phb
|
||||
pea #^tiledata
|
||||
plb
|
||||
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda: tiledata+{]line*4},y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]line*4}
|
||||
lda: tiledata+{]line*4}+32,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]line*4}+32
|
||||
|
||||
lda: tiledata+{]line*4}+2,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
lda: tiledata+{]line*4}+32+2,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]line*4}+32+2
|
||||
--^
|
||||
|
||||
plb
|
||||
plb
|
||||
rts
|
||||
|
||||
; _GetTileAt
|
||||
;
|
||||
; Given a relative playfield coordinate [0, ScreenWidth), [0, ScreenHeight) return the
|
||||
; X = horizontal point [0, ScreenTileWidth]
|
||||
; Y = vertical point [0, ScreenTileHeight]
|
||||
;
|
||||
; Return
|
||||
; C = 1, out of range
|
||||
; C = 0, X = column, Y = row
|
||||
_GetTileAt
|
||||
cpx ScreenWidth
|
||||
bcc *+3
|
||||
rts
|
||||
|
||||
cpy ScreenHeight
|
||||
bcc *+3
|
||||
rts
|
||||
|
||||
tya ; carry is clear here
|
||||
adc StartYMod208 ; This is the code field line that is at the top of the screen
|
||||
cmp #208
|
||||
bcc *+5
|
||||
sbc #208
|
||||
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tay ; This is the code field row for this point
|
||||
|
||||
clc
|
||||
txa
|
||||
adc StartXMod164
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
|
||||
lsr
|
||||
lsr
|
||||
tax ; Could call _CopyBG0Tile with these arguments
|
||||
|
||||
clc
|
||||
rts
|
||||
|
||||
; _DrawSprite
|
||||
;
|
||||
; Draw the sprites on the _Sprite list into the Sprite Plane data and mask buffers. This is using the
|
||||
; tile data right now, but could be replaced with compiled sprite routines.
|
||||
_DrawSprites
|
||||
ldx #0
|
||||
:loop lda _Sprites+SPRITE_STATUS,x
|
||||
bne :draw ; The first open slot is the end of the list
|
||||
rts
|
||||
|
||||
:draw cmp #SPRITE_STATUS_DIRTY
|
||||
bne :loop
|
||||
|
||||
jsr _DrawTileSprite
|
||||
bra :loop
|
||||
|
||||
_DrawTileSprite
|
||||
phx ; preserve the x register
|
||||
|
||||
; Copy the tile data + mask into the sprite plane
|
||||
lda _Sprites+VBUFF_ADDR,x ; Load the address in the sprite plane
|
||||
ldy _Sprites+TILE_DATA_OFFSET,x
|
||||
tax
|
||||
|
||||
phb
|
||||
pea #^tiledata ; Set the bank to the tile data
|
||||
plb
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda: tiledata+32+{]line*4},y
|
||||
andl spritemask+{]line*256},x
|
||||
stal spritemask+{]line*256},x
|
||||
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
ora: tiledata+{]line*4},y
|
||||
and: tiledata+32+{]line*4},y
|
||||
stal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
|
||||
lda: tiledata+32+{]line*4}+2,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
stal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
ora: tiledata+{]line*4}+2,y
|
||||
and: tiledata+32+{]line*4}+2,y
|
||||
stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb ; pop extra byte
|
||||
plb
|
||||
plx
|
||||
rts
|
||||
|
||||
; Erase is easy -- set an 8x8 area of the data region to all $0000 and the corresponding mask
|
||||
; resgion to all $FFFF
|
||||
;
|
||||
; A = sprite ID
|
||||
SPRITE_PLANE_SPAN equ 256
|
||||
|
||||
_EraseSprite
|
||||
asl
|
||||
tay
|
||||
ldx _Sprites+VBUFF_ADDR,y
|
||||
|
||||
phb
|
||||
|
||||
pea #^spritedata
|
||||
plb
|
||||
|
||||
lda #0
|
||||
sta: {0*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {0*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {1*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {1*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {2*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {2*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {3*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {3*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {4*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {4*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {5*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {5*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {6*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {6*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {7*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {7*SPRITE_PLANE_SPAN}+2,x
|
||||
|
||||
pea #^spritemask
|
||||
plb
|
||||
|
||||
lda #$FFFF
|
||||
sta: {0*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {0*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {1*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {1*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {2*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {2*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {3*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {3*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {4*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {4*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {5*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {5*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {6*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {6*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {7*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {7*SPRITE_PLANE_SPAN}+2,x
|
||||
|
||||
pla
|
||||
plb
|
||||
rts
|
||||
|
||||
; Add a new sprite to the rendering pipeline
|
||||
;
|
||||
; A = tileId
|
||||
; X = x position
|
||||
; Y = y position
|
||||
AddSprite ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _AddSprite
|
||||
plb
|
||||
rtl
|
||||
|
||||
_AddSprite
|
||||
phx ; Save the parameters
|
||||
pha
|
||||
|
||||
ldx #0
|
||||
:loop lda _Sprites+SPRITE_STATUS,x ; Look for an open slot
|
||||
beq :open
|
||||
inx
|
||||
inx
|
||||
cpx #MAX_SPRITES*2
|
||||
bcc :loop
|
||||
|
||||
pla ; Early out
|
||||
pla
|
||||
rts
|
||||
|
||||
:open lda #SPRITE_STATUS_DIRTY
|
||||
sta _Sprites+SPRITE_STATUS,x ; Mark this sprite slot as occupied and that it needs to be drawn
|
||||
pla
|
||||
jsr _GetTileAddr
|
||||
sta _Sprites+TILE_DATA_OFFSET,x
|
||||
|
||||
tya
|
||||
clc
|
||||
adc #NUM_BUFF_LINES ; The virtual buffer has 24 lines of off-screen space
|
||||
xba ; Each virtual scan line is 256 bytes wide for overdraw space
|
||||
clc
|
||||
adc 1,s
|
||||
sta _Sprites+VBUFF_ADDR,x
|
||||
|
||||
pla
|
||||
rts
|
||||
|
||||
; Sprite data structures. We cache quite a few pieces of information about the sprite
|
||||
; to make calculations faster, so this is hidden from the caller.
|
||||
;
|
||||
; Each sprite record contains the following properties:
|
||||
;
|
||||
; +0: Sprite status word (0 = unoccupied)
|
||||
; +2: Tile data address
|
||||
; +4: Screen offset address (used for data and masks)
|
||||
|
||||
; Number of "off-screen" lines above logical (0,0)
|
||||
NUM_BUFF_LINES equ 24
|
||||
|
||||
MAX_SPRITES equ 64
|
||||
SPRITE_REC_SIZE equ 10
|
||||
|
||||
SPRITE_STATUS_EMPTY equ 0
|
||||
SPRITE_STATUS_CLEAN equ 1
|
||||
SPRITE_STATUS_DIRTY equ 2
|
||||
|
||||
SPRITE_STATUS equ 0
|
||||
TILE_DATA_OFFSET equ {MAX_SPRITES*2}
|
||||
VBUFF_ADDR equ {MAX_SPRITES*4}
|
||||
SPRITE_X equ {MAX_SPRITES*6}
|
||||
SPRITE_Y equ {MAX_SPRITES*8}
|
||||
|
||||
_Sprites ds SPRITE_REC_SIZE*MAX_SPRITES
|
||||
|
@ -290,7 +290,7 @@ _UpdateBG0TileMap
|
||||
sbc #MAX_TILE_Y+1
|
||||
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
|
||||
lda StartXMod164 ; Do the same thing for X, except only need to clamp by 4
|
||||
and #$FFFC
|
||||
lsr
|
||||
lsr
|
||||
@ -316,25 +316,27 @@ _UpdateBG0TileMap
|
||||
|
||||
; Handle fringe tiles -- if the fringe bit is set, then we need to get the fringe tile index
|
||||
; and merge the tiles before rendering
|
||||
bit #TILE_FRINGE_BIT
|
||||
beq :no_fringe
|
||||
jsr _GetTileAddr
|
||||
tax
|
||||
lda FringeMapPtr
|
||||
ora FringeMapPtr+2
|
||||
beq :no_fringe
|
||||
lda [FringeMapPtr],y
|
||||
jsr _GetTileAddr
|
||||
tay
|
||||
jsr _MergeTiles
|
||||
|
||||
:no_fringe
|
||||
; bit #TILE_FRINGE_BIT
|
||||
; beq :no_fringe
|
||||
; jsr _GetTileAddr
|
||||
; tax
|
||||
; lda FringeMapPtr
|
||||
; ora FringeMapPtr+2
|
||||
; beq :no_fringe
|
||||
; lda [FringeMapPtr],y
|
||||
; jsr _GetTileAddr
|
||||
; tay
|
||||
; jsr _MergeTiles
|
||||
;
|
||||
;:no_fringe
|
||||
inc :Offset ; pre-increment the address.
|
||||
inc :Offset
|
||||
|
||||
ldx :BlkX
|
||||
ldy :BlkY
|
||||
jsr _CopyBG0Tile
|
||||
; jsr _CopyBG0Tile
|
||||
jsr _PushDirtyTile ; queue this tile for processing
|
||||
|
||||
lda :BlkX
|
||||
inc
|
||||
|
@ -106,7 +106,7 @@ _SetBG1YPos
|
||||
|
||||
|
||||
; Everytime either BG1 or BG0 X-position changes, we have to update the direct page values. We
|
||||
; *could* do this by adjusting the since address offset, but we have to change up to 200 values
|
||||
; *could* do this by adjusting the since the address offset, but we have to change up to 200 values
|
||||
; when the vertical position changes, and only 41 when the horizontal value changes. Plus
|
||||
; these are all direct page values
|
||||
;
|
||||
|
@ -90,8 +90,3 @@ stk_save lda #0000 ; load the stack
|
||||
|
||||
plb ; restore the bank
|
||||
rts
|
||||
|
||||
; Placeholder for actual sprite drawing. The implementation will be simple because
|
||||
; we don't do anything sprite related; just call function pointers provided to us.
|
||||
_RenderSprites
|
||||
rts
|
||||
|
@ -221,6 +221,16 @@ ScreenAddr ENT
|
||||
]step = ]step+160
|
||||
--^
|
||||
|
||||
; Table of offsets into each row of a Tile Store table. We currently have two tables defined; one
|
||||
; that is the backing store for the tiles rendered into the code field, and another that holds
|
||||
; backlink information on the sprite entries that overlap various tiles.
|
||||
]step equ 0
|
||||
TileStoreYTable ENT
|
||||
lup 26
|
||||
dw ]step
|
||||
]step = ]step+{41*2}
|
||||
--^
|
||||
|
||||
; This is a double-length table that holds the right-edge adresses of the playfield on the physical
|
||||
; screen. At most, it needs to hold 200 addresses for a full height playfield. It is double-length
|
||||
; so that code can pick any offset and copy values without needing to check for a wrap-around. If the
|
||||
@ -238,6 +248,10 @@ BlitBuff ENT
|
||||
BTableHigh ds 208*2*2
|
||||
BTableLow ds 208*2*2
|
||||
|
||||
; A shorter table that just holds the blitter row addresses
|
||||
BRowTableHigh ds 26*2*2
|
||||
BRowTableLow ds 26*2*2
|
||||
|
||||
; A double-length table of addresses for the BG1 bank. The BG1 buffer is 208 rows of 256 bytes each and
|
||||
; the first row starts $1800 bytes in to cenrer the buffer in the bank
|
||||
]step equ $1800
|
||||
|
@ -8,10 +8,10 @@
|
||||
; CopyTileLinear -- copies the tile data from the tile bank in linear order, e.g.
|
||||
; 32 consecutive bytes are copied
|
||||
|
||||
; RenderTile
|
||||
; _RenderTile
|
||||
;
|
||||
; A high-level function that takes a 16-bit tile descriptor and dispatched to the
|
||||
; appropriate tile copy courinte based on the descritor flags
|
||||
; 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
|
||||
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
@ -19,13 +19,13 @@
|
||||
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
; \____/ | | | | | \________________________/
|
||||
; | | | | | | 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
|
||||
; | | | | | |
|
||||
; | | | | | +-- 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
|
||||
@ -38,13 +38,23 @@
|
||||
; 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_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 $1E00 ; Deliberately ignore the Fringe bit in the dispatch
|
||||
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
|
||||
@ -77,147 +87,105 @@ _GetTileAddr
|
||||
; Y is set to the top-left address of the tile in the BG1 data bank
|
||||
;
|
||||
; tmp0/tmp1 is reserved
|
||||
RenderTileBG1
|
||||
tax ; Save the tile descriptor
|
||||
and #TILE_ID_MASK ; Mask out the ID and save just that
|
||||
_Mul128 ; multiplied by 128
|
||||
pha
|
||||
_RenderTileBG1
|
||||
pha ; Save the tile descriptor
|
||||
|
||||
txa
|
||||
and #TILE_VFLIP_BIT+TILE_HFLIP_BIT ; Only horizontal and vertical flips are supported for BG1
|
||||
xba
|
||||
tax
|
||||
jmp (:actions,x)
|
||||
ldal :actions,x
|
||||
stal :tiledisp+1
|
||||
|
||||
:actions dw bg1_noflip,bg1_hflip,bg1_vflip,bg1_hvflip
|
||||
|
||||
bg1_noflip
|
||||
pla
|
||||
brl _CopyTileBG1
|
||||
|
||||
bg1_hflip
|
||||
pla
|
||||
clc
|
||||
adc #64 ; Advance to the flipped version
|
||||
brl _CopyTileBG1
|
||||
|
||||
bg1_vflip
|
||||
pla
|
||||
brl _CopyTileBG1V
|
||||
|
||||
bg1_hvflip
|
||||
pla
|
||||
clc
|
||||
adc #64 ; Advance to the flipped version
|
||||
brl _CopyTileBG1V
|
||||
|
||||
_CopyTileBG1 tax
|
||||
|
||||
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
|
||||
rts
|
||||
|
||||
_CopyTileBG1V tax
|
||||
|
||||
ldal tiledata+0,x
|
||||
sta: $0700,y
|
||||
ldal tiledata+2,x
|
||||
sta: $0702,y
|
||||
ldal tiledata+4,x
|
||||
sta $0600,y
|
||||
ldal tiledata+6,x
|
||||
sta $0602,y
|
||||
ldal tiledata+8,x
|
||||
sta $0500,y
|
||||
ldal tiledata+10,x
|
||||
sta $0502,y
|
||||
ldal tiledata+12,x
|
||||
sta $0400,y
|
||||
ldal tiledata+14,x
|
||||
sta $0402,y
|
||||
ldal tiledata+16,x
|
||||
sta $0300,y
|
||||
ldal tiledata+18,x
|
||||
sta $0302,y
|
||||
ldal tiledata+20,x
|
||||
sta $0200,y
|
||||
ldal tiledata+22,x
|
||||
sta $0202,y
|
||||
ldal tiledata+24,x
|
||||
sta $0100,y
|
||||
ldal tiledata+26,x
|
||||
sta $0102,y
|
||||
ldal tiledata+28,x
|
||||
sta $0000,y
|
||||
ldal tiledata+30,x
|
||||
sta $0002,y
|
||||
rts
|
||||
|
||||
; On entry
|
||||
;
|
||||
; B is set to the correct code field bank
|
||||
; A is set to the the tile descriptor
|
||||
; Y is set to the top-left address of the tile in the code field
|
||||
; X is set to the tile word offset (0 through 80 in steps of 4)
|
||||
;
|
||||
; tmp0/tmp1 is reserved
|
||||
RenderTile
|
||||
bit #TILE_CTRL_MASK ; Fast path for "normal" tiles
|
||||
beq _CopyTile
|
||||
cmp #TILE_MASK_BIT ; Tile 0 w/mask bit set is special, too
|
||||
bne *+5
|
||||
brl ClearTile
|
||||
|
||||
phx ; Save the tile offset
|
||||
|
||||
tax
|
||||
and #TILE_ID_MASK ; Mask out the ID and save just that
|
||||
_Mul128 ; multiplied by 128
|
||||
pha
|
||||
|
||||
txa
|
||||
and #TILE_CTRL_MASK ; Mask out the different modifiers
|
||||
xba
|
||||
tax
|
||||
jmp (:actions,x)
|
||||
:tiledisp jmp $0000
|
||||
|
||||
:actions dw solid,solid_hflip,solid_vflip,solid_hvflip
|
||||
; dw dynamic,dynamic,dynamic,dynamic
|
||||
dw dyn_masked,dyn_masked,dyn_masked,dyn_masked
|
||||
dw masked,masked_hflip,masked_vflip,masked_hvflip
|
||||
dw dyn_masked,dyn_masked,dyn_masked,dyn_masked
|
||||
:actions dw _TBSolidBG1_00,_TBSolidBG1_0H,_TBSolidBG1_V0,_TBSolidBG1_VH
|
||||
|
||||
FillWord0
|
||||
; 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
|
||||
@ -234,195 +202,9 @@ FillWord0
|
||||
sta $6004,y
|
||||
sta $7001,y
|
||||
sta $7004,y
|
||||
bra FillPEAOpcode
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
; _CopyTile
|
||||
;
|
||||
; Copy a solid tile into one of the code banks
|
||||
;
|
||||
; B = bank of the code field
|
||||
; A = Tile ID (0 - 1023)
|
||||
; Y = Base Adddress in the code field
|
||||
|
||||
|
||||
_CopyTile cmp #$0000 ; Fast-path the special zero tile
|
||||
beq FillWord0
|
||||
|
||||
CopyTileMem
|
||||
_Mul128 ; Take care of getting the right tile address
|
||||
|
||||
CopyTileMem0
|
||||
tax
|
||||
|
||||
ldal tiledata+0,x ; The low word goes in the *next* instruction
|
||||
sta: $0004,y
|
||||
ldal tiledata+2,x
|
||||
sta: $0001,y
|
||||
ldal tiledata+4,x
|
||||
sta $1004,y
|
||||
ldal tiledata+6,x
|
||||
sta $1001,y
|
||||
ldal tiledata+8,x
|
||||
sta $2004,y
|
||||
ldal tiledata+10,x
|
||||
sta $2001,y
|
||||
ldal tiledata+12,x
|
||||
sta $3004,y
|
||||
ldal tiledata+14,x
|
||||
sta $3001,y
|
||||
ldal tiledata+16,x
|
||||
sta $4004,y
|
||||
ldal tiledata+18,x
|
||||
sta $4001,y
|
||||
ldal tiledata+20,x
|
||||
sta $5004,y
|
||||
ldal tiledata+22,x
|
||||
sta $5001,y
|
||||
ldal tiledata+24,x
|
||||
sta $6004,y
|
||||
ldal tiledata+26,x
|
||||
sta $6001,y
|
||||
ldal tiledata+28,x
|
||||
sta $7004,y
|
||||
ldal tiledata+30,x
|
||||
sta $7001,y ; Fall through
|
||||
|
||||
; For solid tiles
|
||||
FillPEAOpcode
|
||||
sep #$20
|
||||
lda #$F4
|
||||
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
|
||||
|
||||
; Masked tiles
|
||||
;
|
||||
; Can result in one of three different code sequences
|
||||
;
|
||||
; If mask === $0000, then insert PEA $DATA
|
||||
; If mask === $FFFF, then insert LDA (DP),y / PHA
|
||||
; Else then insert JMP and patch exception handler
|
||||
;
|
||||
; Because every word of the tile can lead to different opcodes, we
|
||||
; do the entire setup for each word rather than breaking them up into
|
||||
; 16-bit and 8-bit operations.
|
||||
|
||||
; Macro to make the loop simpler. Takes three arguments
|
||||
;
|
||||
; ]1 = address of tile data
|
||||
; ]2 = address of tile mask
|
||||
; ]3 = address of target in code field
|
||||
|
||||
_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
|
||||
|
||||
CopyTileMemM
|
||||
|
||||
stx _X_REG ; Save these values as we will need to reload them
|
||||
sty _Y_REG ; at certain points
|
||||
sta _T_PTR
|
||||
tax
|
||||
|
||||
; Do the left column first
|
||||
|
||||
CopyMaskedWord tiledata+0;tiledata+32+0;$0003
|
||||
CopyMaskedWord tiledata+4;tiledata+32+4;$1003
|
||||
CopyMaskedWord tiledata+8;tiledata+32+8;$2003
|
||||
CopyMaskedWord tiledata+12;tiledata+32+12;$3003
|
||||
CopyMaskedWord tiledata+16;tiledata+32+16;$4003
|
||||
CopyMaskedWord tiledata+20;tiledata+32+20;$5003
|
||||
CopyMaskedWord tiledata+24;tiledata+32+24;$6003
|
||||
CopyMaskedWord tiledata+28;tiledata+32+28;$7003
|
||||
|
||||
; Move the index for the JTableOffset array. This is the same index used for transparent words,
|
||||
; so, if _X_REG is zero, then we would be patching out the last word in the code field with LDA (0),y
|
||||
; and then increment _X_REG by two to patch the next-to-last word in the code field with LDA (2),y
|
||||
|
||||
inc _X_REG
|
||||
inc _X_REG
|
||||
|
||||
; Do the right column
|
||||
|
||||
CopyMaskedWord tiledata+2;tiledata+32+2;$0000
|
||||
CopyMaskedWord tiledata+6;tiledata+32+6;$1000
|
||||
CopyMaskedWord tiledata+10;tiledata+32+10;$2000
|
||||
CopyMaskedWord tiledata+14;tiledata+32+14;$3000
|
||||
CopyMaskedWord tiledata+18;tiledata+32+18;$4000
|
||||
CopyMaskedWord tiledata+22;tiledata+32+22;$5000
|
||||
CopyMaskedWord tiledata+26;tiledata+32+26;$6000
|
||||
CopyMaskedWord tiledata+30;tiledata+32+30;$7000
|
||||
|
||||
rts
|
||||
|
||||
CopyTileMemMV
|
||||
|
||||
stx _X_REG ; Save these values as we will need to reload them
|
||||
sty _Y_REG ; at certain points
|
||||
sta _T_PTR
|
||||
tax
|
||||
|
||||
CopyMaskedWord tiledata+0;tiledata+32+0;$7003
|
||||
CopyMaskedWord tiledata+2;tiledata+32+2;$7000
|
||||
CopyMaskedWord tiledata+4;tiledata+32+4;$6003
|
||||
CopyMaskedWord tiledata+6;tiledata+32+6;$6000
|
||||
CopyMaskedWord tiledata+8;tiledata+32+8;$5003
|
||||
CopyMaskedWord tiledata+10;tiledata+32+10;$5000
|
||||
CopyMaskedWord tiledata+12;tiledata+32+12;$4003
|
||||
CopyMaskedWord tiledata+14;tiledata+32+14;$4000
|
||||
CopyMaskedWord tiledata+16;tiledata+32+16;$3003
|
||||
CopyMaskedWord tiledata+18;tiledata+32+18;$3000
|
||||
CopyMaskedWord tiledata+20;tiledata+32+20;$2003
|
||||
CopyMaskedWord tiledata+22;tiledata+32+22;$2000
|
||||
CopyMaskedWord tiledata+24;tiledata+32+24;$1003
|
||||
CopyMaskedWord tiledata+28;tiledata+32+26;$1000
|
||||
CopyMaskedWord tiledata+30;tiledata+32+28;$0003
|
||||
CopyMaskedWord tiledata+32;tiledata+32+30;$0000
|
||||
|
||||
rts
|
||||
|
||||
TilePatterns dw $0000,$1111,$2222,$3333
|
||||
dw $4444,$5555,$6666,$7777
|
||||
dw $8888,$9999,$AAAA,$BBBB
|
||||
dw $CCCC,$DDDD,$EEEE,$FFFF
|
||||
|
||||
ClearTile 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
|
||||
|
||||
txa
|
||||
ClearTile
|
||||
and #$00FF
|
||||
ora #$4800
|
||||
sta: $0004,y
|
||||
@ -443,126 +225,9 @@ ClearTile sep #$20
|
||||
sta $5001,y
|
||||
sta $6001,y
|
||||
sta $7001,y
|
||||
rts
|
||||
|
||||
; Copy a tile, but vertically flip the data
|
||||
CopyTileMemV
|
||||
tax
|
||||
|
||||
ldal tiledata+0,x ; The low word goes in the *next* instruction
|
||||
sta $7004,y
|
||||
ldal tiledata+2,x
|
||||
sta $7001,y
|
||||
ldal tiledata+4,x
|
||||
sta $6004,y
|
||||
ldal tiledata+6,x
|
||||
sta $6001,y
|
||||
ldal tiledata+8,x
|
||||
sta $5004,y
|
||||
ldal tiledata+10,x
|
||||
sta $5001,y
|
||||
ldal tiledata+12,x
|
||||
sta $4004,y
|
||||
ldal tiledata+14,x
|
||||
sta $4001,y
|
||||
ldal tiledata+16,x
|
||||
sta $3004,y
|
||||
ldal tiledata+18,x
|
||||
sta $3001,y
|
||||
ldal tiledata+20,x
|
||||
sta $2004,y
|
||||
ldal tiledata+22,x
|
||||
sta $2001,y
|
||||
ldal tiledata+24,x
|
||||
sta $1004,y
|
||||
ldal tiledata+26,x
|
||||
sta $1001,y
|
||||
ldal tiledata+28,x
|
||||
sta: $0004,y
|
||||
ldal tiledata+30,x
|
||||
sta: $0001,y
|
||||
rts
|
||||
|
||||
; Primitives to render a dynamic tile
|
||||
;
|
||||
; LDA 00,x / PHA where the operand is fixed when the tile is rendered
|
||||
; $B5 $00 $48
|
||||
;
|
||||
; A = dynamic tile id (must be <32)
|
||||
|
||||
DynamicTile
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
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 #$B5
|
||||
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
|
||||
|
||||
DynamicTileM
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
sta _T_PTR
|
||||
stx _X_REG
|
||||
|
||||
CopyMaskedDWord $0003
|
||||
CopyMaskedDWord $1003
|
||||
CopyMaskedDWord $2003
|
||||
CopyMaskedDWord $3003
|
||||
CopyMaskedDWord $4003
|
||||
CopyMaskedDWord $5003
|
||||
CopyMaskedDWord $6003
|
||||
CopyMaskedDWord $7003
|
||||
|
||||
inc _T_PTR ; Move to the next column
|
||||
inc _T_PTR
|
||||
inc _X_REG ; Move to the next column
|
||||
inc _X_REG
|
||||
|
||||
CopyMaskedDWord $0000
|
||||
CopyMaskedDWord $1000
|
||||
CopyMaskedDWord $2000
|
||||
CopyMaskedDWord $3000
|
||||
CopyMaskedDWord $4000
|
||||
CopyMaskedDWord $5000
|
||||
CopyMaskedDWord $6000
|
||||
CopyMaskedDWord $7000
|
||||
|
||||
sep #$20
|
||||
lda #$4C ; Set everything to JMP instructions
|
||||
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
|
||||
@ -598,26 +263,7 @@ CopyTileToDyn ENT
|
||||
adc #$0100 ; Go to the next page
|
||||
tay
|
||||
jsr CopyTileDToDyn ; Copy the tile data
|
||||
jsr CopyTileMToDyn ; Copy the tile data
|
||||
rtl
|
||||
|
||||
; Helper functions to copy tile data and mask to the appropriate location in Bank 0
|
||||
; X = tile ID
|
||||
; Y = dynamic tile ID
|
||||
CopyTileAndMaskToDyn 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 data
|
||||
jsr CopyTileMToDyn ; Copy the tile mask
|
||||
rtl
|
||||
|
||||
; X = address of tile
|
||||
@ -718,105 +364,6 @@ CopyTileMToDyn
|
||||
plb
|
||||
rts
|
||||
|
||||
; This should never be called, because empty control value should be fast-pathed
|
||||
solid
|
||||
pla
|
||||
plx
|
||||
brl CopyTileMem
|
||||
|
||||
solid_hflip
|
||||
pla
|
||||
clc
|
||||
adc #64 ; Advance to the flipped version
|
||||
plx
|
||||
brl CopyTileMem
|
||||
|
||||
solid_vflip
|
||||
pla
|
||||
plx
|
||||
brl CopyTileMemV
|
||||
|
||||
solid_hvflip
|
||||
pla
|
||||
clc
|
||||
adc #64 ; Advance to the flipped version
|
||||
plx
|
||||
brl CopyTileMemV
|
||||
|
||||
masked
|
||||
pla
|
||||
plx
|
||||
brl CopyTileMemM
|
||||
|
||||
masked_hflip
|
||||
pla
|
||||
clc
|
||||
adc #64 ; Advance to the flipped version
|
||||
plx
|
||||
brl CopyTileMemM
|
||||
|
||||
masked_vflip
|
||||
pla
|
||||
plx
|
||||
brl CopyTileMemMV
|
||||
|
||||
masked_hvflip
|
||||
pla
|
||||
clc
|
||||
adc #64 ; Advance to the flipped version
|
||||
plx
|
||||
brl CopyTileMemMV
|
||||
|
||||
dynamic
|
||||
pla
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
xba ; Undo the x128 we just need x4
|
||||
plx
|
||||
brl DynamicTile
|
||||
|
||||
dyn_masked
|
||||
pla
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
xba ; Undo the x128 we just need x4
|
||||
plx
|
||||
brl DynamicTileM
|
||||
|
||||
; Merge
|
||||
;
|
||||
; For fringe support -- takes a pointer to two tiles and composites them into
|
||||
; some scratch space.
|
||||
;
|
||||
; X = primary tile address
|
||||
; Y = fringe tile address
|
||||
|
||||
tilescratch equ $FF80
|
||||
_MergeTiles
|
||||
; Merge the tile data
|
||||
]step equ 0
|
||||
lup 16
|
||||
lda: tiledata+]step,x
|
||||
and: tiledata+32+]step,y
|
||||
ora: tiledata+]step,y
|
||||
sta: tilescratch+]step
|
||||
]step equ ]step+2
|
||||
--^
|
||||
|
||||
; Merge the tile masks
|
||||
]step equ 0
|
||||
lup 16
|
||||
lda: tiledata+32+]step,x
|
||||
and: tiledata+32+]step,y
|
||||
sta: tilescratch+32+]step
|
||||
]step equ ]step+2
|
||||
--^
|
||||
|
||||
lda #tilescratch/128
|
||||
rts
|
||||
|
||||
; CopyBG0Tile
|
||||
;
|
||||
; A low-level function that copies 8x8 tiles directly into the code field space.
|
||||
@ -841,7 +388,7 @@ _CopyBG0Tile
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl ; x2 because the table contains words, not
|
||||
tay
|
||||
|
||||
sep #$20 ; set the bank register
|
||||
@ -860,20 +407,17 @@ _CopyBG0Tile
|
||||
adc Col2CodeOffset+2,x ; Get the right edge (which is the lower physical address)
|
||||
tay
|
||||
|
||||
; Optimization note: We could make a Tile2CodeOffset table that is pre-reversed, which should simplify
|
||||
; the code starting after the 'rep #$20' to just be this. Saves around 16 cycles / tile...
|
||||
;
|
||||
; There would need to be a similar modification made to the JTable as well.
|
||||
|
||||
plb ; set the bank
|
||||
pla ; pop the tile ID
|
||||
jsr RenderTile
|
||||
; jsr _RenderTile
|
||||
|
||||
:exit
|
||||
plx ; pop the x-register
|
||||
plb ; restore the data bank and return
|
||||
rts
|
||||
|
||||
; CopyTileBG1
|
||||
|
||||
; CopyBG1Tile
|
||||
;
|
||||
; A low-level function that copies 8x8 tiles directly into the BG1 data buffer.
|
||||
;
|
||||
@ -914,26 +458,179 @@ _CopyBG1Tile
|
||||
rep #$20
|
||||
|
||||
pla ; pop the tile ID
|
||||
jsr RenderTileBG1
|
||||
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
|
112
src/blitter/Tiles00000.s
Normal file
112
src/blitter/Tiles00000.s
Normal file
@ -0,0 +1,112 @@
|
||||
; _TBSolidTile
|
||||
;
|
||||
; Define the addresses of the subroutines that draw the normal and flipped variants of the tiles, both
|
||||
; in the optimized (no second background) and normal cases.
|
||||
;
|
||||
; On entry, the following register values need to be set
|
||||
;
|
||||
; X : address of base tile in the tiledata bank (tileId * 128)
|
||||
; Y : address of the top-left corder of the tile location in the code field
|
||||
; B : set to the code field bank
|
||||
;_TBSolidTile dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH
|
||||
; dw _TBCopyData,_TBCopyDataH,_TBCopyDataV,_TBCopyDataVH
|
||||
|
||||
_TBSolidTile_00
|
||||
jsr _TBCopyData
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidTile_0H
|
||||
jsr _TBCopyDataH
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidTile_V0
|
||||
jsr _TBCopyDataV
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidTile_VH
|
||||
jsr _TBCopyDataVH
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
; The workhorse blitter. This blitter copies tile data into the code field without masking. This is the
|
||||
; most common blitter function. It is slightly optimized to fall through to the code that sets the PEA
|
||||
; opcodes in order to be slightly more efficient given it's frequent usage.
|
||||
;
|
||||
; There is a small variation of this blitter that just copies the data without setting the PEA opcodes. This
|
||||
; is used by the engine when the capabilitiy bits have turned off the second background layer. In fact, most
|
||||
; of the tile rendering routines have an optimized version for this important use case. Skipping the opcode
|
||||
; step results in a 37% speed boost in tile rendering.
|
||||
;
|
||||
; This does not increase the FPS by 37% because only a small number of tiles are drawn each frame, but it
|
||||
; has an impact and can significantly help out when sprites trigger more dirty tile updates than normal.
|
||||
_TBCopyData
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyDataH
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4}+64,x
|
||||
sta: $0004+{]line*$1000},y
|
||||
ldal tiledata+{]line*4}+66,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyDataV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta: $0004+{]dest*$1000},y
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta: $0001+{]dest*$1000},y
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyDataVH
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4}+64,x
|
||||
sta: $0004+{]dest*$1000},y
|
||||
ldal tiledata+{]src*4}+66,x
|
||||
sta: $0001+{]dest*$1000},y
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; A simple helper function that fill in all of the opcodes of a tile with the PEA opcode. This is
|
||||
; a common function since a tile must be explicitly flagged to use a mask, so this routine is used
|
||||
; quite frequently in a well-designed tile map.
|
||||
_TBFillPEAOpcode
|
||||
sep #$20
|
||||
lda #$F4
|
||||
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
|
70
src/blitter/Tiles00001.s
Normal file
70
src/blitter/Tiles00001.s
Normal file
@ -0,0 +1,70 @@
|
||||
; _TBDynamicTile
|
||||
;
|
||||
; These subroutines fill in the code field with the instructions to render data from the dynamic
|
||||
; code buffer. This is a bit different, because no tile data is manipulated. It is the
|
||||
; responsibiliy of the user of the API to use the CopyTileToDyn subroutine to get data
|
||||
; into the correct location.
|
||||
;
|
||||
; This tile type does not explicitly support horizontal or vertical flipping. An appropriate tile
|
||||
; descriptor should be passed into CopyTileToDyn to put the horizontally or vertically flipped source
|
||||
; data into the dynamic tile buffer
|
||||
_TBDynamicTile dw _TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00
|
||||
dw _TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00
|
||||
|
||||
_TBDynamicTile_00
|
||||
jsr _TBDynamicData
|
||||
jmp _TBFillLdaDpOpcode
|
||||
|
||||
; Primitives to render a dynamic tile
|
||||
;
|
||||
; LDA 00,x / PHA where the operand is fixed when the tile is rendered
|
||||
; $B5 $00 $48
|
||||
;
|
||||
; A = dynamic tile id (must be <32)
|
||||
_TBDynamicData
|
||||
txa
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
xba ; Undo the x128 we just need x4
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$4800 ; insert the PHA instruction
|
||||
|
||||
]line equ 0 ; render the first column
|
||||
lup 8
|
||||
sta: $0004+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
inc ; advance to the next word
|
||||
inc
|
||||
|
||||
]line equ 0 ; render the second column
|
||||
lup 8
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
|
||||
rts
|
||||
|
||||
; A simple helper function that fill in all of the opcodes of a tile with the LDA dp,x opcode.
|
||||
_TBFillLdaDpOpcode
|
||||
sep #$20
|
||||
lda #$B5
|
||||
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
|
130
src/blitter/Tiles00010.s
Normal file
130
src/blitter/Tiles00010.s
Normal file
@ -0,0 +1,130 @@
|
||||
; _TBMaskedTile
|
||||
;
|
||||
; These tile renderes are for "normal" tiles that also apply their mask data. If the case of the second
|
||||
; background being disabled, the optimized variants are the same as Tile00000
|
||||
_TBMaskedTile dw _TBMaskedTile_00,_TBMaskedTile_0H,_TBMaskedTile_V0,_TBMaskedTile_VH
|
||||
dw _TBCopyData,_TBCopyDataH,_TBCopyDataV,_TBCopyDataVH
|
||||
|
||||
_TBMaskedTile_00
|
||||
stx _X_REG ; Save these values as we will need to reload them
|
||||
sty _Y_REG ; at certain points
|
||||
sta _T_PTR
|
||||
tax
|
||||
|
||||
; Do the left column first
|
||||
|
||||
CopyMaskedWord tiledata+0;tiledata+32+0;$0003
|
||||
CopyMaskedWord tiledata+4;tiledata+32+4;$1003
|
||||
CopyMaskedWord tiledata+8;tiledata+32+8;$2003
|
||||
CopyMaskedWord tiledata+12;tiledata+32+12;$3003
|
||||
CopyMaskedWord tiledata+16;tiledata+32+16;$4003
|
||||
CopyMaskedWord tiledata+20;tiledata+32+20;$5003
|
||||
CopyMaskedWord tiledata+24;tiledata+32+24;$6003
|
||||
CopyMaskedWord tiledata+28;tiledata+32+28;$7003
|
||||
|
||||
; Move the index for the JTableOffset array. This is the same index used for transparent words,
|
||||
; so, if _X_REG is zero, then we would be patching out the last word in the code field with LDA (0),y
|
||||
; and then increment _X_REG by two to patch the next-to-last word in the code field with LDA (2),y
|
||||
|
||||
inc _X_REG
|
||||
inc _X_REG
|
||||
|
||||
; Do the right column
|
||||
|
||||
CopyMaskedWord tiledata+2;tiledata+32+2;$0000
|
||||
CopyMaskedWord tiledata+6;tiledata+32+6;$1000
|
||||
CopyMaskedWord tiledata+10;tiledata+32+10;$2000
|
||||
CopyMaskedWord tiledata+14;tiledata+32+14;$3000
|
||||
CopyMaskedWord tiledata+18;tiledata+32+18;$4000
|
||||
CopyMaskedWord tiledata+22;tiledata+32+22;$5000
|
||||
CopyMaskedWord tiledata+26;tiledata+32+26;$6000
|
||||
CopyMaskedWord tiledata+30;tiledata+32+30;$7000
|
||||
|
||||
rts
|
||||
|
||||
_TBMaskedTile_0H
|
||||
stx _X_REG ; Save these values as we will need to reload them
|
||||
sty _Y_REG ; at certain points
|
||||
sta _T_PTR
|
||||
tax
|
||||
|
||||
CopyMaskedWord tiledata+64+0;tiledata+64+32+0;$0003
|
||||
CopyMaskedWord tiledata+64+4;tiledata+64+32+4;$1003
|
||||
CopyMaskedWord tiledata+64+8;tiledata+64+32+8;$2003
|
||||
CopyMaskedWord tiledata+64+12;tiledata+64+32+12;$3003
|
||||
CopyMaskedWord tiledata+64+16;tiledata+64+32+16;$4003
|
||||
CopyMaskedWord tiledata+64+20;tiledata+64+32+20;$5003
|
||||
CopyMaskedWord tiledata+64+24;tiledata+64+32+24;$6003
|
||||
CopyMaskedWord tiledata+64+28;tiledata+64+32+28;$7003
|
||||
|
||||
inc _X_REG
|
||||
inc _X_REG
|
||||
|
||||
CopyMaskedWord tiledata+64+2;tiledata+64+32+2;$0000
|
||||
CopyMaskedWord tiledata+64+6;tiledata+64+32+6;$1000
|
||||
CopyMaskedWord tiledata+64+10;tiledata+64+32+10;$2000
|
||||
CopyMaskedWord tiledata+64+14;tiledata+64+32+14;$3000
|
||||
CopyMaskedWord tiledata+64+18;tiledata+64+32+18;$4000
|
||||
CopyMaskedWord tiledata+64+22;tiledata+64+32+22;$5000
|
||||
CopyMaskedWord tiledata+64+26;tiledata+64+32+26;$6000
|
||||
CopyMaskedWord tiledata+64+30;tiledata+64+32+30;$7000
|
||||
|
||||
rts
|
||||
|
||||
_TBMaskedTile_V0
|
||||
stx _X_REG ; Save these values as we will need to reload them
|
||||
sty _Y_REG ; at certain points
|
||||
sta _T_PTR
|
||||
tax
|
||||
|
||||
CopyMaskedWord tiledata+0;tiledata+32+0;$7003
|
||||
CopyMaskedWord tiledata+4;tiledata+32+4;$6003
|
||||
CopyMaskedWord tiledata+8;tiledata+32+8;$5003
|
||||
CopyMaskedWord tiledata+12;tiledata+32+12;$4003
|
||||
CopyMaskedWord tiledata+16;tiledata+32+16;$3003
|
||||
CopyMaskedWord tiledata+20;tiledata+32+20;$2003
|
||||
CopyMaskedWord tiledata+24;tiledata+32+24;$1003
|
||||
CopyMaskedWord tiledata+28;tiledata+32+28;$0003
|
||||
|
||||
inc _X_REG
|
||||
inc _X_REG
|
||||
|
||||
CopyMaskedWord tiledata+2;tiledata+32+2;$7000
|
||||
CopyMaskedWord tiledata+6;tiledata+32+6;$6000
|
||||
CopyMaskedWord tiledata+10;tiledata+32+10;$5000
|
||||
CopyMaskedWord tiledata+14;tiledata+32+14;$4000
|
||||
CopyMaskedWord tiledata+18;tiledata+32+18;$3000
|
||||
CopyMaskedWord tiledata+22;tiledata+32+22;$2000
|
||||
CopyMaskedWord tiledata+26;tiledata+32+26;$1000
|
||||
CopyMaskedWord tiledata+30;tiledata+32+30;$0000
|
||||
|
||||
rts
|
||||
|
||||
_TBMaskedTile_VH
|
||||
stx _X_REG ; Save these values as we will need to reload them
|
||||
sty _Y_REG ; at certain points
|
||||
sta _T_PTR
|
||||
tax
|
||||
|
||||
CopyMaskedWord tiledata+64+0;tiledata+64+32+0;$7003
|
||||
CopyMaskedWord tiledata+64+4;tiledata+64+32+4;$6003
|
||||
CopyMaskedWord tiledata+64+8;tiledata+64+32+8;$5003
|
||||
CopyMaskedWord tiledata+64+12;tiledata+64+32+12;$4003
|
||||
CopyMaskedWord tiledata+64+16;tiledata+64+32+16;$3003
|
||||
CopyMaskedWord tiledata+64+20;tiledata+64+32+20;$2003
|
||||
CopyMaskedWord tiledata+64+24;tiledata+64+32+24;$1003
|
||||
CopyMaskedWord tiledata+64+28;tiledata+64+32+28;$0003
|
||||
|
||||
inc _X_REG
|
||||
inc _X_REG
|
||||
|
||||
CopyMaskedWord tiledata+64+2;tiledata+64+32+2;$7000
|
||||
CopyMaskedWord tiledata+64+6;tiledata+64+32+6;$6000
|
||||
CopyMaskedWord tiledata+64+10;tiledata+64+32+10;$5000
|
||||
CopyMaskedWord tiledata+64+14;tiledata+64+32+14;$4000
|
||||
CopyMaskedWord tiledata+64+18;tiledata+64+32+18;$3000
|
||||
CopyMaskedWord tiledata+64+22;tiledata+64+32+22;$2000
|
||||
CopyMaskedWord tiledata+64+26;tiledata+64+32+26;$1000
|
||||
CopyMaskedWord tiledata+64+30;tiledata+64+32+30;$0000
|
||||
|
||||
rts
|
64
src/blitter/Tiles00011.s
Normal file
64
src/blitter/Tiles00011.s
Normal file
@ -0,0 +1,64 @@
|
||||
; _TBDynamicMaskTile
|
||||
;
|
||||
; Insert a code sequence to mask the dynamic tile against the background. This is quite a slow process because
|
||||
; every word needs to be handled with a JMP exception; but it looks good!
|
||||
_TBDynamicMaskTile dw _TBDynamicMaskTile_00,_TBDynamicMaskTile_00,_TBDynamicMaskTile_00,_TBDynamicMaskTile_00
|
||||
dw _TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00
|
||||
|
||||
_TBDynamicMaskTile_00
|
||||
jsr _TBDynamicDataAndMask
|
||||
jmp _TBFillJMPOpcode
|
||||
|
||||
; A = dynamic tile id (must be <32)
|
||||
_TBDynamicDataAndMask
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
sta _T_PTR
|
||||
stx _X_REG
|
||||
|
||||
CopyMaskedDWord $0003
|
||||
CopyMaskedDWord $1003
|
||||
CopyMaskedDWord $2003
|
||||
CopyMaskedDWord $3003
|
||||
CopyMaskedDWord $4003
|
||||
CopyMaskedDWord $5003
|
||||
CopyMaskedDWord $6003
|
||||
CopyMaskedDWord $7003
|
||||
|
||||
inc _T_PTR ; Move to the next column
|
||||
inc _T_PTR
|
||||
inc _X_REG ; Move to the next column
|
||||
inc _X_REG
|
||||
|
||||
CopyMaskedDWord $0000
|
||||
CopyMaskedDWord $1000
|
||||
CopyMaskedDWord $2000
|
||||
CopyMaskedDWord $3000
|
||||
CopyMaskedDWord $4000
|
||||
CopyMaskedDWord $5000
|
||||
CopyMaskedDWord $6000
|
||||
CopyMaskedDWord $7000
|
||||
|
||||
rts
|
||||
|
||||
; A simple helper function that fill in all of the opcodes of a tile with the JMP opcode.
|
||||
_TBFillJMPOpcode
|
||||
sep #$20
|
||||
lda #$4C
|
||||
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
|
141
src/blitter/Tiles01000.s
Normal file
141
src/blitter/Tiles01000.s
Normal file
@ -0,0 +1,141 @@
|
||||
; _TBSolidSpriteTile
|
||||
;
|
||||
; Renders solid tiles with sprites layered on top of the tile data. Because we need to combine
|
||||
; data from the sprite plane, tile data and write to the code field (which are all in different banks),
|
||||
; there is no way to do everything inline, so a composite tile is created on the fly and written to
|
||||
; a direct page buffer. This direct page buffer is then used to render the tile.
|
||||
_TBSolidSpriteTile dw _TBSolidSpriteTile_00
|
||||
dw _TBSolidSpriteTile_0H
|
||||
dw _TBSolidSpriteTile_V0
|
||||
dw _TBSolidSpriteTile_VH
|
||||
|
||||
dw _TBFastSpriteTile_00
|
||||
dw _TBFastSpriteTile_0H
|
||||
dw _TBFastSpriteTile_V0
|
||||
dw _TBFastSpriteTile_VH
|
||||
|
||||
_TBSolidSpriteTile_00
|
||||
jsr _TBCopyTileDataToCBuff ; Copy the tile into the compositing buffer
|
||||
jsr _TBApplySpriteData ; Overlay the data form the sprite plane (and copy into the code field)
|
||||
jmp _TBFillPEAOpcode ; Fill in the code field opcodes
|
||||
|
||||
_TBSolidSpriteTile_0H
|
||||
jsr _TBCopyTileDataToCBuffH
|
||||
jsr _TBApplySpriteData
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidSpriteTile_V0
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jsr _TBApplySpriteData
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidSpriteTile_VH
|
||||
jsr _TBCopyTileDataToCBuffVH
|
||||
jsr _TBApplySpriteData
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
; Fast variation that does not need to set the opcode
|
||||
_TBFastSpriteTile_00
|
||||
jsr _TBCopyTileDataToCBuff ; Copy the tile into the compositing buffer
|
||||
jmp _TBApplySpriteData ; Overlay the data form the sprite plane (and copy into the code field)
|
||||
|
||||
_TBFastSpriteTile_0H
|
||||
jsr _TBCopyTileDataToCBuffH
|
||||
jmp _TBApplySpriteData
|
||||
|
||||
_TBFastSpriteTile_V0
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jmp _TBApplySpriteData
|
||||
|
||||
_TBFastSpriteTile_VH
|
||||
jsr _TBCopyTileDataToCBuffVH
|
||||
jmp _TBApplySpriteData
|
||||
|
||||
; Need to update the X-register before calling this
|
||||
_TBApplySpriteData
|
||||
ldx _SPR_X_REG ; set to the unaligned tile block address in the sprite plane
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
lda blttmp+{]line*4}+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
ldx _X_REG ; restore the original value
|
||||
rts
|
||||
|
||||
; Copy tile data into the direct page compositing buffer. The main reason to do this in full passes is
|
||||
; because we can avoid needing to use both the X and Y registers during the compositing process and
|
||||
; reserve Y to hold the code field address.
|
||||
;
|
||||
; Also, we can get away with not setting the bank register, this is a wash in terms of speed, but results
|
||||
; in simpler, more composable subroutines
|
||||
_TBCopyTileDataToCBuff
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyTileDataToCBuffH
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4}+64,x
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
ldal tiledata+{]line*4}+64+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyTileDataToCBuffV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta blttmp+{]dest*4}
|
||||
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta blttmp+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
rts
|
||||
|
||||
_TBCopyTileDataToCBuffVH
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4}+64,x
|
||||
sta blttmp+{]dest*4}
|
||||
|
||||
ldal tiledata+{]src*4}+64+2,x
|
||||
sta blttmp+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
rts
|
||||
|
||||
; Copy just the data into the code field from the composite buffer
|
||||
_TBSolidComposite
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
sta: $0004+{]line*$1000},y
|
||||
lda blttmp+{]line*4}+2
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
132
src/blitter/Tiles01010.s
Normal file
132
src/blitter/Tiles01010.s
Normal file
@ -0,0 +1,132 @@
|
||||
; _TBMaskedSpriteTile
|
||||
;
|
||||
; Renders a composited tile with masking to the code field.
|
||||
_TBMaskedSpriteTile dw _TBMaskedSpriteTile_00
|
||||
dw _TBMaskedSpriteTile_0H
|
||||
dw _TBMaskedSpriteTile_V0
|
||||
dw _TBMaskedSpriteTile_VH
|
||||
; dw _TBCopyData,_TBCopyDataH,_TBCopyDataV,_TBCopyDataVH
|
||||
|
||||
_TBSolidSpriteTile_00
|
||||
jsr _TBCreateComposite
|
||||
jsr _TBSolidComposite
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidSpriteTile_0H
|
||||
jsr _TBCreateCompositeH
|
||||
jsr _TBSolidComposite
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidSpriteTile_V0
|
||||
jsr _TBCreateCompositeV
|
||||
jsr _TBSolidComposite
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidSpriteTile_VH
|
||||
jsr _TBCreateCompositeVH
|
||||
jsr _TBSolidComposite
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBCreateCompositeDataAndMask
|
||||
phb
|
||||
pea #^tiledata
|
||||
plb
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda: tiledata+{]line*4},y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
lda: tiledata+{]line*4}+32,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]line*4}+32
|
||||
|
||||
lda: tiledata+{]line*4}+2,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
|
||||
lda: tiledata+{]line*4}+32+2,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]line*4}+32+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
plb
|
||||
rts
|
||||
|
||||
_TBCreateCompositeH
|
||||
phb
|
||||
pea #^tiledata
|
||||
plb
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda: tiledata+{]line*4}+64,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
lda: tiledata+{]line*4}+64+2,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
plb
|
||||
rts
|
||||
|
||||
|
||||
_TBCreateCompositeV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
lda: tiledata+{]src*4},y
|
||||
andl spritemask+{]dest*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]dest*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]dest*4}
|
||||
|
||||
lda: tiledata+{]src*4}+2,y
|
||||
andl spritemask+{]dest*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]dest*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCreateCompositeVH
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
lda: tiledata+{]src*4}+64,y
|
||||
andl spritemask+{]dest*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]dest*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]dest*4}
|
||||
|
||||
lda: tiledata+{]src*4}+64+2,y
|
||||
andl spritemask+{]dest*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]dest*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; Copy just the data into the code field from the composite buffer
|
||||
_TBSolidComposite
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
sta: $0004+{]line*$1000},y
|
||||
lda blttmp+{]line*4}+2
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
6
src/blitter/Tiles10000.s
Normal file
6
src/blitter/Tiles10000.s
Normal file
@ -0,0 +1,6 @@
|
||||
; _TBPriorityTile
|
||||
;
|
||||
; The priority bit allows the tile to be rendered in front of sprites. If there's no sprite
|
||||
; in this tile area, then just fallback to the Tile00000.s implementation
|
||||
_TBPriorityTile dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH
|
||||
dw _TBCopyData,_TBCopyDataH,_TBCopyDataV,_TBCopyDataVH
|
6
src/blitter/Tiles10001.s
Normal file
6
src/blitter/Tiles10001.s
Normal file
@ -0,0 +1,6 @@
|
||||
; _TBPriorityDynamicTile
|
||||
;
|
||||
; The priority bit allows the tile to be rendered in front of sprites. If there's no sprite
|
||||
; in this tile area, then just fallback to the Tile00001.s implementation
|
||||
_TBPriorityDynamicTile dw _TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00
|
||||
dw _TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00
|
19
src/blitter/Tiles10010.s
Normal file
19
src/blitter/Tiles10010.s
Normal file
@ -0,0 +1,19 @@
|
||||
; _TBMaskedPriorityTile
|
||||
;
|
||||
; The priority bit allows the tile to be rendered in front of sprites. If there's no sprite
|
||||
; in this tile area, then just fallback to the Tile00000.s implementation
|
||||
_TBMaskedPriorityTile dw _TBMaskedTile_00,_TBMaskedTile_0H,_TBMaskedTile_V0,_TBMaskedTile_VH
|
||||
dw _TBCopyData,_TBCopyDataH,_TBCopyDataV,_TBCopyDataVH
|
||||
|
||||
; NOTE: Eventually, we want a way to support this use-case
|
||||
;
|
||||
; When the high-priority bit is set for a tile, then the BG0 tile will be rendered behind the BG1 data. In
|
||||
; order to support this, the optional BG1 mask buffer needs to be enabled and *every* word in the tile
|
||||
; becomes a JMP handler (similar to masked dynamic tiles)
|
||||
;
|
||||
; The 8 bytes of code that is generated in the JMP handler is
|
||||
;
|
||||
; lda #tiledata
|
||||
; and [dp],y
|
||||
; ora (dp),y
|
||||
; nop
|
6
src/blitter/Tiles10011.s
Normal file
6
src/blitter/Tiles10011.s
Normal file
@ -0,0 +1,6 @@
|
||||
; _TBPriorityDynamicMaskTile
|
||||
;
|
||||
; The priority bit allows the tile to be rendered in front of sprites. If there's no sprite
|
||||
; in this tile area, then just fallback to the Tile00000.s implementation
|
||||
_TBPriorityDynamicMaskTile dw _TBDynamicMaskTile_00,_TBDynamicMaskTile_00,_TBDynamicMaskTile_00,_TBDynamicMaskTile_00
|
||||
dw _TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00
|
25
src/blitter/Tiles11000.s
Normal file
25
src/blitter/Tiles11000.s
Normal file
@ -0,0 +1,25 @@
|
||||
; _TBPrioritySpriteTile
|
||||
;
|
||||
; When the sprite is composited with the tile data, the tile mask is used to place the tile data on top of
|
||||
; any sprite data
|
||||
|
||||
; Need to update the X-register before calling this
|
||||
_TBApplyPrioritySpriteData
|
||||
ldx _SPR_X_REG ; set to the unaligned tile block address in the sprite plane
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
and blttmp+{]line*4}+32
|
||||
ora blttmp+{]line*4}
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
and blttmp+{]line*4}+32+2
|
||||
ora blttmp+{]line*4}+2
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
ldx _X_REG ; restore the original value
|
||||
rts
|
48
src/blitter/TilesBG1.s
Normal file
48
src/blitter/TilesBG1.s
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
_TBSolidBG1_00
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta: $0000+{]line*$0100},y
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta: $0002+{]line*$0100},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBSolidBG1_0H
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4}+64,x
|
||||
sta: $0000+{]line*$0100},y
|
||||
ldal tiledata+{]line*4}+64+2,x
|
||||
sta: $0002+{]line*$0100},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBSolidBG1_V0
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta: $0000+{]dest*$0100},y
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta: $0002+{]dest*$0100},y
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBSolidBG1_VH
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4}+64,x
|
||||
sta: $0000+{]dest*$0100},y
|
||||
ldal tiledata+{]src*4}+64+2,x
|
||||
sta: $0002+{]dest*$0100},y
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
Loading…
x
Reference in New Issue
Block a user