mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2025-01-13 03:30:56 +00:00
Move most data storage to separate bank; fix many banking bugs
This commit is contained in:
parent
01e92a7b62
commit
755ac3fbfd
@ -11,6 +11,8 @@
|
||||
|
||||
mx %00
|
||||
|
||||
TSZelda EXT ; tileset buffer
|
||||
|
||||
ScreenX equ 0
|
||||
ScreenY equ 2
|
||||
|
||||
@ -29,12 +31,41 @@ ScreenY equ 2
|
||||
pea #160
|
||||
_GTESetScreenMode
|
||||
|
||||
; Load a tileset in from an uncompressed $C1 picture. The top-left 256x128 rectangle is used
|
||||
; to populate the 512 tiles.
|
||||
; Load a tileset
|
||||
|
||||
pea #^TSZelda
|
||||
pea #TSZelda
|
||||
_GTELoadTileSet
|
||||
|
||||
; Manually fill in the 41x26 tiles of the TileStore with a test pattern.
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
|
||||
:loop
|
||||
phx
|
||||
phy
|
||||
|
||||
phx
|
||||
phy
|
||||
pei 0
|
||||
_GTESetTile
|
||||
|
||||
lda 0
|
||||
inc
|
||||
and #$001F
|
||||
sta 0
|
||||
|
||||
ply
|
||||
plx
|
||||
inx
|
||||
cpx #41
|
||||
bcc :loop
|
||||
|
||||
ldx #0
|
||||
iny
|
||||
cpy #26
|
||||
bcc :loop
|
||||
|
||||
; Set the origin of the screen
|
||||
stz ScreenX
|
||||
@ -53,7 +84,7 @@ ScreenY equ 2
|
||||
pei ScreenY
|
||||
_GTESetBG0Origin
|
||||
|
||||
; _GTERender
|
||||
_GTERender
|
||||
|
||||
inc ScreenX ; Just keep incrementing, it's OK
|
||||
bra :loop
|
||||
|
@ -8,3 +8,8 @@
|
||||
|
||||
ASM App.Main.s
|
||||
SNA Main
|
||||
|
||||
; Segment #2 -- Tileset
|
||||
|
||||
ASM Zelda.TileSet.s
|
||||
SNA TSET
|
||||
|
@ -325,3 +325,57 @@ transparent
|
||||
sta: ]3+1,y
|
||||
next
|
||||
eom
|
||||
|
||||
; Large code blocks that can be used in sprite blitters
|
||||
; ]1: line number
|
||||
OneSpriteToCodeField mac
|
||||
lda blttmp+{]1*4}
|
||||
andl spritemask+{]1*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]1*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]1*$1000},y
|
||||
|
||||
lda blttmp+{]1*4}+2
|
||||
andl spritemask+{]1*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]1*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]1*$1000},y
|
||||
eom
|
||||
|
||||
TwoSpritesToCodeField mac
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}
|
||||
lda blttmp+{]1*4}
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0004+{]1*$1000},x
|
||||
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}+2
|
||||
lda blttmp+{]1*4}+2
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0001+{]1*$1000},x
|
||||
eom
|
||||
|
||||
ThreeSpritesToCodeField mac
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}
|
||||
lda blttmp+{]1*4}
|
||||
andl [spritemask_2],y
|
||||
oral [spritedata_2],y
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0004+{]1*$1000},x
|
||||
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}+2
|
||||
lda blttmp+{]1*4}+2
|
||||
andl [spritemask_2],y
|
||||
oral [spritedata_2],y
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0001+{]1*$1000},x
|
||||
eom
|
||||
|
@ -150,8 +150,8 @@ IntShutDown
|
||||
OneSecHandler mx %11
|
||||
phb
|
||||
pha
|
||||
phk
|
||||
plb
|
||||
|
||||
jsr _SetDataBank
|
||||
|
||||
rep #$20
|
||||
inc OneSecondCounter
|
||||
@ -167,10 +167,7 @@ OneSecHandler mx %11
|
||||
rtl
|
||||
mx %00
|
||||
|
||||
OneSecondCounter ENT
|
||||
dw 0
|
||||
OldOneSecVec ds 4
|
||||
|
||||
; This is OK, it's referenced by a long address
|
||||
VBLTASK hex 00000000
|
||||
dw 0
|
||||
hex 5AA5
|
||||
@ -270,11 +267,6 @@ ClearKbdStrobe sep #$20
|
||||
rts
|
||||
|
||||
; Read the keyboard and paddle controls and return in a game-controller-like format
|
||||
LastKey db 0
|
||||
ReadControl ENT
|
||||
jsr _ReadControl
|
||||
rtl
|
||||
|
||||
_ReadControl
|
||||
pea $0000 ; low byte = key code, high byte = %------AB
|
||||
|
||||
|
68
src/Defs.s
68
src/Defs.s
@ -92,7 +92,10 @@ TileStoreBankAndTileDataBank equ 108
|
||||
TileStoreBankDoubled equ 110
|
||||
UserId equ 112 ; Memory manager user Id to use
|
||||
ToolNum equ 114 ; Tool number assigned to us
|
||||
Next equ 116
|
||||
LastKey equ 116
|
||||
LastTick equ 118
|
||||
|
||||
Next equ 120
|
||||
|
||||
activeSpriteList equ 128 ; 32 bytes for the active sprite list (can persist across frames)
|
||||
; tiletmp equ 178 ; 16 bytes of temp storage for the tile renderers
|
||||
@ -141,8 +144,9 @@ _OP_CACHE equ 156 ; Cache of a relevant operand / oeprato
|
||||
_TILE_ID equ 158 ; Copy of the tile descriptor
|
||||
|
||||
; Define free space the the application to use
|
||||
FREE_SPACE_DP2 equ 160
|
||||
|
||||
; FREE_SPACE_DP2 equ 160
|
||||
DP2_DIRTY_TILE_COUNT equ 160 ; Local copy of dirty tile count to avoid banking
|
||||
DP2_DIRTY_TILE_CALLBACK equ 162
|
||||
; End direct page values
|
||||
|
||||
; EngineMode definitions
|
||||
@ -197,6 +201,7 @@ SPRITE_HFLIP equ $0200
|
||||
; Stamp storage parameters
|
||||
VBUFF_STRIDE_BYTES equ 12*4 ; Each line has 4 slots of 16 pixels + 8 buffer pixels
|
||||
VBUFF_TILE_ROW_BYTES equ 8*VBUFF_STRIDE_BYTES ; Each row is comprised of 8 lines
|
||||
VBUFF_TILE_COL_BYTES equ 4
|
||||
VBUFF_SPRITE_STEP equ VBUFF_TILE_ROW_BYTES*3 ; Allocate space fo 16 rows + 8 rows of buffer
|
||||
VBUFF_SPRITE_START equ {8*VBUFF_TILE_ROW_BYTES}+4 ; Start at an offset so $0000 can be used as an empty value
|
||||
VBUFF_SLOT_COUNT equ 48 ; Have space for this many stamps
|
||||
@ -204,31 +209,32 @@ VBUFF_SLOT_COUNT equ 48 ; Have space for this m
|
||||
; This is 13 blocks wide
|
||||
SPRITE_PLANE_SPAN equ VBUFF_STRIDE_BYTES
|
||||
|
||||
; Tile storage parameters
|
||||
TILE_DATA_SPAN equ 4
|
||||
TILE_STORE_WIDTH equ 41
|
||||
TILE_STORE_HEIGHT equ 26
|
||||
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
|
||||
|
||||
TS_TILE_ID equ TILE_STORE_SIZE*0 ; tile descriptor for this location
|
||||
TS_DIRTY equ TILE_STORE_SIZE*1 ; Flag. Used to prevent a tile from being queued multiple times per frame
|
||||
TS_SPRITE_FLAG equ TILE_STORE_SIZE*2 ; Bitfield of all sprites that intersect this tile. 0 if no sprites.
|
||||
TS_TILE_ADDR equ TILE_STORE_SIZE*3 ; cached value, the address of the tiledata for this tile
|
||||
TS_CODE_ADDR_LOW equ TILE_STORE_SIZE*4 ; const value, address of this tile in the code fields
|
||||
TS_CODE_ADDR_HIGH equ TILE_STORE_SIZE*5
|
||||
TS_WORD_OFFSET equ TILE_STORE_SIZE*6 ; const value, word offset value for this tile if LDA (dp),y instructions re used
|
||||
TS_BASE_ADDR equ TILE_STORE_SIZE*7 ; const value, because there are two rows of tiles per bank, this is set to $0000 ot $8000.
|
||||
TS_SCREEN_ADDR equ TILE_STORE_SIZE*8 ; cached value of on-screen location of tile. Used for DirtyRender.
|
||||
;TS_VBUFF_ARRAY_ADDR equ TILE_STORE_SIZE*9 ; const value to an aligned 32-byte array starting at $8000 in TileStore bank
|
||||
|
||||
TS_BASE_TILE_COPY equ TILE_STORE_SIZE*9 ; derived from TS_TILE_ID to optimize tile copy to support sprite rendering
|
||||
TS_BASE_TILE_DISP equ TILE_STORE_SIZE*10 ; derived from TS_TILE_ID to optimize base (non-sprite) tile dispatch in the Render function
|
||||
TS_DIRTY_TILE_DISP equ TILE_STORE_SIZE*11 ; derived from TS_TILE_ID to optimize dirty tile dispatch in the Render function
|
||||
|
||||
; Hold values for up to 4 sprites per tile
|
||||
TS_VBUFF_ADDR_0 equ TILE_STORE_SIZE*12
|
||||
TS_VBUFF_ADDR_1 equ TILE_STORE_SIZE*13
|
||||
TS_VBUFF_ADDR_2 equ TILE_STORE_SIZE*14
|
||||
TS_VBUFF_ADDR_3 equ TILE_STORE_SIZE*15
|
||||
TS_VBUFF_ADDR_COUNT equ TILE_STORE_SIZE*16 ; replace usage of TS_VBUFF_ARRAY_ADDR with this later
|
||||
; External references to data bank
|
||||
TileStore EXT
|
||||
DirtyTileCount EXT
|
||||
DirtyTiles EXT
|
||||
_Sprites EXT
|
||||
TileStore EXT
|
||||
TileStoreLookupYTable EXT
|
||||
TileStoreLookup EXT
|
||||
Col2CodeOffset EXT
|
||||
JTableOffset EXT
|
||||
CodeFieldEvenBRA EXT
|
||||
CodeFieldOddBRA EXT
|
||||
ScreenAddr EXT
|
||||
TileStoreYTable EXT
|
||||
NextCol EXT
|
||||
RTable EXT
|
||||
BlitBuff EXT
|
||||
BTableHigh EXT
|
||||
BTableLow EXT
|
||||
BRowTableHigh EXT
|
||||
BRowTableLow EXT
|
||||
BG1YTable EXT
|
||||
BG1YOffsetTable EXT
|
||||
OldOneSecVec EXT
|
||||
OneSecondCounter EXT
|
||||
Timers EXT
|
||||
DefaultPalette EXT
|
||||
ScreenModeWidth EXT
|
||||
ScreenModeHeight EXT
|
||||
|
18
src/GTE.s
18
src/GTE.s
@ -73,21 +73,3 @@ AllocBank EXT
|
||||
ScreenAddr EXT
|
||||
OneSecondCounter EXT
|
||||
BlitBuff EXT
|
||||
|
||||
;; Helper function to load the GTE User Toolset
|
||||
;GTEInstall
|
||||
; php
|
||||
; ~InitialLoad userId;localToolPath;#0
|
||||
|
||||
; pea $8000 ; User tool
|
||||
; pea $00A5 ; Tool 165
|
||||
; PushLong toolPtr
|
||||
; _SetTSPtr
|
||||
|
||||
; plp
|
||||
; rtl
|
||||
|
||||
; Look for the tool set in the System Tools folder and then next to the application
|
||||
;sysToolPath strl '*:System:Tools:ToolGTE'
|
||||
;localToolPath strl '9:ToolGTE'
|
||||
;toolPtr adrl 0
|
@ -24,11 +24,6 @@ InitGraphics
|
||||
:no_bg1
|
||||
rts
|
||||
|
||||
DefaultPalette dw $0000,$007F,$0090,$0FF0
|
||||
dw $000F,$0080,$0f70,$0FFF
|
||||
dw $0fa9,$0ff0,$00e0,$04DF
|
||||
dw $0d00,$078f,$0ccc,$0FFF
|
||||
|
||||
; Allow the user to dynamically select one of the pre-configured screen sizes, or pass
|
||||
; in a specific width and height. The screen is automatically centered. If this is
|
||||
; not desired, then SetScreenRect should be used directly
|
||||
@ -47,18 +42,6 @@ DefaultPalette dw $0000,$007F,$0090,$0FF0
|
||||
;
|
||||
; X = mode number OR width in pixels (must be multiple of 2)
|
||||
; Y = height in pixels (if X > 8)
|
||||
|
||||
ScreenModeWidth dw 320,272,256,256,280,256,240,288,160,288,160,320
|
||||
ScreenModeHeight dw 200,192,200,176,160,160,160,128,144,192,102,1
|
||||
|
||||
SetScreenMode ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _SetScreenMode
|
||||
plb
|
||||
rtl
|
||||
|
||||
_SetScreenMode
|
||||
cpx #11
|
||||
bcs :direct ; if x > 10, then assume X and Y are the dimensions
|
||||
@ -113,10 +96,6 @@ _GetBorderColor lda #0000
|
||||
rts
|
||||
|
||||
; Set the border color to the accumulator value.
|
||||
SetBorderColor ENT
|
||||
jsr _SetBorderColor
|
||||
rtl
|
||||
|
||||
_SetBorderColor sep #$20 ; ACC = $X_Y, REG = $W_Z
|
||||
eorl BORDER_REG ; ACC = $(X^Y)_(Y^Z)
|
||||
and #$0F ; ACC = $0_(Y^Z)
|
||||
@ -135,17 +114,6 @@ _ClearToColor
|
||||
rts
|
||||
|
||||
; Set a palette values
|
||||
; A = high word of palette data pointer, X = low word of palette data pointer, Y = palette number
|
||||
SetPalette ENT
|
||||
phb ; save old data bank
|
||||
pha ; push 16-bit value
|
||||
plb ; pop 8-bit bank register
|
||||
tya
|
||||
jsr _SetPalette
|
||||
plb ; pop the other half of the 16-bit push off
|
||||
plb ; restore the original data bank
|
||||
rtl
|
||||
|
||||
; A = palette number, X = palette address
|
||||
_SetPalette
|
||||
and #$000F ; palette values are 0 - 15 and each palette is 32 bytes
|
||||
@ -307,7 +275,7 @@ SetScreenRect sty ScreenHeight ; Save the screen height and
|
||||
ldx #0
|
||||
ldy #0
|
||||
:tsloop
|
||||
stal TileStore+TS_SCREEN_ADDR,x
|
||||
sta TileStore+TS_SCREEN_ADDR,x
|
||||
|
||||
clc
|
||||
adc #4 ; Go to the next tile
|
||||
|
26
src/Memory.s
26
src/Memory.s
@ -28,9 +28,9 @@ InitMemory lda EngineMode
|
||||
_NewHandle ; returns LONG Handle on stack
|
||||
plx ; base address of the new handle
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
_Deref
|
||||
stx Buff00
|
||||
sta Buff00+2
|
||||
; _Deref
|
||||
; stx Buff00
|
||||
; sta Buff00+2
|
||||
:no_bnk0_buff
|
||||
|
||||
PushLong #0 ; space for result
|
||||
@ -41,9 +41,9 @@ InitMemory lda EngineMode
|
||||
_NewHandle ; returns LONG Handle on stack
|
||||
plx ; base address of the new handle
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
_Deref
|
||||
stx Buff01
|
||||
sta Buff01+2
|
||||
; _Deref
|
||||
; stx Buff01
|
||||
; sta Buff01+2
|
||||
|
||||
PushLong #0 ; space for result
|
||||
|
||||
@ -153,8 +153,8 @@ InitMemory lda EngineMode
|
||||
:exit
|
||||
rts
|
||||
|
||||
Buff00 ds 4
|
||||
Buff01 ds 4
|
||||
;Buff00 ds 4
|
||||
;Buff01 ds 4
|
||||
|
||||
; Bank allocator (for one full, fixed bank of memory. Can be immediately deferenced)
|
||||
|
||||
@ -172,14 +172,6 @@ AllocOneBank PushLong #0
|
||||
rts
|
||||
|
||||
; Variation that returns the pointer in the X/A registers (X = low, A = high)
|
||||
AllocBank ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr AllocOneBank2
|
||||
plb
|
||||
rtl
|
||||
|
||||
AllocOneBank2 PushLong #0
|
||||
PushLong #$10000
|
||||
PushWord UserId
|
||||
@ -190,5 +182,3 @@ AllocOneBank2 PushLong #0
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
_Deref
|
||||
rts
|
||||
|
||||
|
||||
|
25
src/Render.s
25
src/Render.s
@ -21,12 +21,12 @@
|
||||
; used in all of the other loops
|
||||
_Render
|
||||
jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
|
||||
jsr _ApplyBG1YPos
|
||||
; jsr _ApplyBG1YPos
|
||||
|
||||
; _ApplyBG0Xpos need to be split because we have to set the offsets, then draw in any updated tiles, and
|
||||
; finally patch out the code field. Right now, the BRA operand is getting overwritten by tile data.
|
||||
jsr _ApplyBG0XPosPre
|
||||
jsr _ApplyBG1XPosPre
|
||||
; jsr _ApplyBG1XPosPre
|
||||
|
||||
; jsr _RenderSprites ; Once the BG0 X and Y positions are committed, update sprite data
|
||||
|
||||
@ -36,7 +36,7 @@ _Render
|
||||
jsr _ApplyTilesFast ; This function actually draws the new tiles into the code field
|
||||
|
||||
jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode
|
||||
jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position
|
||||
; jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position
|
||||
|
||||
; The code fields are locked in now and ready to be rendered
|
||||
|
||||
@ -99,26 +99,13 @@ _ApplyTilesFast
|
||||
adc #$100 ; move to the next page
|
||||
tcd
|
||||
|
||||
ldy DirtyTileCount
|
||||
beq :out
|
||||
|
||||
:loop
|
||||
; Retrieve the offset of the next dirty Tile Store items in the X-register
|
||||
lda DirtyTileCount ; Cache the dirty tile count
|
||||
sta DP2_DIRTY_TILE_COUNT
|
||||
|
||||
jsr _PopDirtyTile2
|
||||
|
||||
; Call the generic dispatch with the Tile Store record pointer at by the X-register.
|
||||
stz DirtyTileCount
|
||||
|
||||
phb
|
||||
jsr _RenderTileFast
|
||||
plb
|
||||
|
||||
; Loop again until the list of dirty tiles is empty
|
||||
|
||||
ldy DirtyTileCount
|
||||
bne :loop
|
||||
|
||||
:out
|
||||
tdc ; Move back to the original direct page
|
||||
sec
|
||||
sbc #$100
|
||||
|
15
src/Script.s
15
src/Script.s
@ -35,8 +35,7 @@
|
||||
; timer's user data section.
|
||||
StartScript ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _SetDataBank
|
||||
|
||||
phx ; Save the script array address
|
||||
pha
|
||||
@ -69,14 +68,6 @@ ARG1 equ 2
|
||||
ARG2 equ 4
|
||||
ARG3 equ 6
|
||||
|
||||
DoScriptSeq ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsl _DoScriptSeq ; Yes, this is a special JSL, because _DoScriptSeq is a time callback
|
||||
plb
|
||||
rtl
|
||||
|
||||
_DoScriptSeq
|
||||
phx ; save the timer index; will need to update user data at the end
|
||||
phb ; save the current data bank
|
||||
@ -180,9 +171,9 @@ _SetDTile
|
||||
|
||||
_UserCallback
|
||||
lda: ARG1,y
|
||||
sta :dispatch+1
|
||||
stal :dispatch+1
|
||||
lda: ARG1+1,y
|
||||
sta :dispatch+2
|
||||
stal :dispatch+2
|
||||
lda: ARG3,y
|
||||
:dispatch jsl $000000
|
||||
brl _dss_cmd_rtn
|
||||
|
139
src/Sprite.s
139
src/Sprite.s
@ -27,24 +27,6 @@ InitSprites
|
||||
; dex
|
||||
; bpl :loop3
|
||||
|
||||
; Initialize the VBUFF address offsets in the data and mask banks for each sprite
|
||||
;
|
||||
; The internal grid 12 tiles wide where each sprite has a 2x2 interior square with a
|
||||
; tile-size buffer all around. We pre-render each sprite with all four vert/horz flips
|
||||
;
|
||||
; Eventually we should be able to have a separate rendering path for vertically flipped
|
||||
; sprites and will be able to double the capacity of the stamp buffer
|
||||
|
||||
ldx #0
|
||||
lda #VBUFF_SPRITE_START
|
||||
clc
|
||||
:loop4 sta VBuffAddrTable,x
|
||||
adc #VBUFF_SPRITE_STEP
|
||||
inx
|
||||
inx
|
||||
cpx #VBUFF_SLOT_COUNT*2
|
||||
bcc :loop4
|
||||
|
||||
; Precalculate some bank values
|
||||
jsr _CacheSpriteBanks
|
||||
rts
|
||||
@ -68,38 +50,25 @@ InitSprites
|
||||
; the stamp every time. So this allows users to create stamps in advance and then
|
||||
; assign them to the sprites as needed.
|
||||
;
|
||||
; Currently, we support a maximum of 48 stamps.
|
||||
; Note that the user had full freedom to create a stamp at any VBUFF address, however,
|
||||
; without leaving a buffer around each stamp, graphical corruption will occur. It is
|
||||
; recommended that the defines for VBUFF_SPRITE_START, VBUFF_TILE_ROW_BYTES and
|
||||
; VBUFF_TILE_COL_BYTES to calculate tile-aligned corner locations to lay out the
|
||||
; sprite stamps in VBUFF memory.
|
||||
;
|
||||
; Input:
|
||||
; A = sprite descriptor
|
||||
; X = stamp slot
|
||||
; Return:
|
||||
; A = vbuff address to be assigned to Sprite[VBUFF_ADDR]
|
||||
CreateSpriteStamp ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CreateSpriteStamp
|
||||
plb
|
||||
rtl
|
||||
|
||||
; Y = vbuff address
|
||||
;
|
||||
; The Sprite[VBUFF_ADDR] property must be set to the vbuff address passed into this function
|
||||
; to bind the sprite stamp to the sprite record.
|
||||
_CreateSpriteStamp
|
||||
pha ; Save the descriptor
|
||||
jsr _GetBaseTileAddr ; Get the address of the tile data
|
||||
pha
|
||||
|
||||
txa
|
||||
asl
|
||||
tax
|
||||
ldy VBuffAddrTable,x ; Load the address of the stamp slot
|
||||
|
||||
plx ; Pop the tile address
|
||||
tax ; Tile data address
|
||||
pla ; Pop the sprite ID
|
||||
phy ; VBUFF_ADDR value
|
||||
jsr _DrawSpriteStamp ; Render the sprite data and create a stamp
|
||||
|
||||
pla ; Pop the VBUFF_ADDR and return
|
||||
rts
|
||||
jmp _DrawSpriteStamp ; Render the sprite data and create a stamp
|
||||
|
||||
; Add a new sprite to the rendering pipeline
|
||||
;
|
||||
@ -123,14 +92,6 @@ _CreateSpriteStamp
|
||||
; A = tileId + flags
|
||||
; Y = High Byte = x-pos, Low Byte = y-pos
|
||||
; X = Sprite Slot (0 - 15)
|
||||
AddSprite ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _AddSprite
|
||||
plb
|
||||
rtl
|
||||
|
||||
_AddSprite
|
||||
pha
|
||||
txa
|
||||
@ -888,14 +849,6 @@ _PrecalcAllSpriteInfo
|
||||
; picked up in the next AddSprite.
|
||||
;
|
||||
; A = Sprite ID
|
||||
RemoveSprite ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _RemoveSprite
|
||||
plb
|
||||
rtl
|
||||
|
||||
_RemoveSprite
|
||||
cmp #MAX_SPRITES
|
||||
bcc :ok
|
||||
@ -917,14 +870,6 @@ _RemoveSprite
|
||||
; A = Sprite ID
|
||||
; X = New Sprite Flags
|
||||
; Y = New Sprite Stamp Address
|
||||
UpdateSprite ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _UpdateSprite
|
||||
plb
|
||||
rtl
|
||||
|
||||
_UpdateSprite
|
||||
cmp #MAX_SPRITES
|
||||
bcc :ok
|
||||
@ -961,14 +906,6 @@ _UpdateSprite
|
||||
; A = sprite ID
|
||||
; X = x position
|
||||
; Y = y position
|
||||
MoveSprite ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _MoveSprite
|
||||
plb
|
||||
rtl
|
||||
|
||||
_MoveSprite
|
||||
cmp #MAX_SPRITES
|
||||
bcc :ok
|
||||
@ -999,57 +936,3 @@ _MoveSprite
|
||||
sta _Sprites+SPRITE_STATUS,x
|
||||
|
||||
jmp _PrecalcAllSpriteInfo ; Can be specialized to only update (x,y) values
|
||||
|
||||
; 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.
|
||||
;
|
||||
;
|
||||
; Number of "off-screen" lines above logical (0,0)
|
||||
; NUM_BUFF_LINES equ 24
|
||||
|
||||
MAX_SPRITES equ 16
|
||||
SPRITE_REC_SIZE equ 52
|
||||
|
||||
; Mark each sprite as ADDED, UPDATED, MOVED, REMOVED depending on the actions applied to it
|
||||
; on this frame. Quick note, the same Sprite ID cannot be removed and added in the same frame.
|
||||
; A REMOVED sprite if removed from the sprite list during the Render call, so it's ID is not
|
||||
; available to the AddSprite function until the next frame.
|
||||
|
||||
SPRITE_STATUS_EMPTY equ $0000 ; If the status value is zero, this sprite slot is available
|
||||
SPRITE_STATUS_OCCUPIED equ $8000 ; Set the MSB to flag it as occupied
|
||||
SPRITE_STATUS_ADDED equ $0001 ; Sprite was just added (new sprite)
|
||||
SPRITE_STATUS_MOVED equ $0002 ; Sprite's position was changed
|
||||
SPRITE_STATUS_UPDATED equ $0004 ; Sprite's non-position attributes were changed
|
||||
SPRITE_STATUS_REMOVED equ $0008 ; Sprite has been removed.
|
||||
|
||||
SPRITE_STATUS equ {MAX_SPRITES*0}
|
||||
; TILE_DATA_OFFSET equ {MAX_SPRITES*2}
|
||||
VBUFF_ADDR equ {MAX_SPRITES*4} ; Base address of the sprite's stamp in the data/mask banks
|
||||
SPRITE_ID equ {MAX_SPRITES*6}
|
||||
SPRITE_X equ {MAX_SPRITES*8}
|
||||
SPRITE_Y equ {MAX_SPRITES*10}
|
||||
; TILE_STORE_ADDR_1 equ {MAX_SPRITES*12}
|
||||
TS_LOOKUP_INDEX equ {MAX_SPRITES*12} ; The index into the TileStoreLookup table corresponding to the top-left corner of the sprite
|
||||
; TILE_STORE_ADDR_2 equ {MAX_SPRITES*14}
|
||||
TS_COVERAGE_SIZE equ {MAX_SPRITES*14} ; Index into the lookup table of how many TileStore tiles are covered by this sprite
|
||||
;TILE_STORE_ADDR_3 equ {MAX_SPRITES*16}
|
||||
TS_VBUFF_BASE_ADDR equ {MAX_SPRITES*16} ; Fixed address of the TS_VBUFF_X memory locations
|
||||
;TILE_STORE_ADDR_4 equ {MAX_SPRITES*18}
|
||||
;TILE_STORE_ADDR_5 equ {MAX_SPRITES*20}
|
||||
;TILE_STORE_ADDR_6 equ {MAX_SPRITES*22}
|
||||
;TILE_STORE_ADDR_7 equ {MAX_SPRITES*24}
|
||||
;TILE_STORE_ADDR_8 equ {MAX_SPRITES*26}
|
||||
;TILE_STORE_ADDR_9 equ {MAX_SPRITES*28}
|
||||
;TILE_STORE_ADDR_10 equ {MAX_SPRITES*30}
|
||||
SPRITE_DISP equ {MAX_SPRITES*32} ; cached address of the specific stamp based on flags
|
||||
SPRITE_CLIP_LEFT equ {MAX_SPRITES*34}
|
||||
SPRITE_CLIP_RIGHT equ {MAX_SPRITES*36}
|
||||
SPRITE_CLIP_TOP equ {MAX_SPRITES*38}
|
||||
SPRITE_CLIP_BOTTOM equ {MAX_SPRITES*40}
|
||||
IS_OFF_SCREEN equ {MAX_SPRITES*42}
|
||||
SPRITE_WIDTH equ {MAX_SPRITES*44}
|
||||
SPRITE_HEIGHT equ {MAX_SPRITES*46}
|
||||
SPRITE_CLIP_WIDTH equ {MAX_SPRITES*48}
|
||||
SPRITE_CLIP_HEIGHT equ {MAX_SPRITES*50}
|
||||
|
||||
_Sprites ds SPRITE_REC_SIZE*MAX_SPRITES
|
||||
|
@ -134,8 +134,11 @@ InitTiles
|
||||
lda :row ; Set the long address of where this tile
|
||||
asl ; exists in the code fields
|
||||
tay
|
||||
lda BRowTableHigh,y
|
||||
lda #>TileStore ; get middle 16 bits: "00 -->BBHH<-- LL"
|
||||
and #$FF00 ; merge with code field bank
|
||||
ora BRowTableHigh,y
|
||||
stal TileStore+TS_CODE_ADDR_HIGH,x ; High word of the tile address (just the bank)
|
||||
|
||||
lda BRowTableLow,y
|
||||
stal TileStore+TS_BASE_ADDR,x ; May not be needed later if we can figure out the right constant...
|
||||
|
||||
|
55
src/Timer.s
55
src/Timer.s
@ -1,37 +1,5 @@
|
||||
; Timer implementation
|
||||
;
|
||||
; The engire provides four timer slot that can be used by one-shot or
|
||||
; recurring timers. Each timer is given an initial tick count, a
|
||||
; reset tick count (0 = one-shot), and an action to perform.
|
||||
;
|
||||
; The timers handle overflow, so if a recurring timer has a tick count of 3
|
||||
; and 7 VBL ticks have passed, then the timer will be fired twice and
|
||||
; a tick count of 2 will be set.
|
||||
;
|
||||
; As such, the timers are appropriate to drive physical and other game
|
||||
; behaviors at a frame-independent rate.
|
||||
;
|
||||
; A collection of 4 timers that are triggered when their countdown
|
||||
; goes below zero. Each timer takes up 16 bytes
|
||||
;
|
||||
; A timer can fire multiple times during a singular evaluation. For example, if the
|
||||
; timer delay is set to 1 and 3 VBL ticks happen, then the timer delta is -2, will fire,
|
||||
; have the delay added and get -1, fire again, increment to zero, first again and then
|
||||
; finally reset to 1.
|
||||
;
|
||||
; +0 counter decremented by the number of ticks since last run
|
||||
; +2 reset copied into counter when triggered. 0 turns off the timer.
|
||||
; +4 addr long address of timer routine
|
||||
; +8 user 8 bytes of user data space for timer state
|
||||
MAX_TIMERS equ 4
|
||||
TIMER_REC_SIZE equ 16
|
||||
mx %00
|
||||
|
||||
lastTick ds 2
|
||||
Timers ds TIMER_REC_SIZE*MAX_TIMERS
|
||||
|
||||
GetVBLTicks ENT
|
||||
jsr _GetVBLTicks
|
||||
rtl
|
||||
_GetVBLTicks
|
||||
PushLong #0
|
||||
_GetTick
|
||||
@ -42,7 +10,7 @@ _GetVBLTicks
|
||||
; Initialize the timers
|
||||
InitTimers
|
||||
jsr _GetVBLTicks
|
||||
sta lastTick
|
||||
sta LastTick
|
||||
|
||||
lda #0
|
||||
ldx #{TIMER_REC_SIZE*MAX_TIMERS}-2
|
||||
@ -71,8 +39,7 @@ AddTimer ENT
|
||||
pha
|
||||
phy
|
||||
|
||||
phk
|
||||
plb
|
||||
jsr _SetDataBank
|
||||
|
||||
ldx #0
|
||||
:loop lda Timers,x ; If the counter is zero, timer is free
|
||||
@ -125,8 +92,7 @@ AddTimer ENT
|
||||
; A = Timer ID
|
||||
RemoveTimer ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _SetDataBank
|
||||
cmp #{TIMER_REC_SIZE*{MAX_TIMERS-1}}+1
|
||||
bcs :exit
|
||||
|
||||
@ -143,17 +109,16 @@ RemoveTimer ENT
|
||||
; Execute the timer functions
|
||||
DoTimers ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _SetDataBank
|
||||
|
||||
jsr _GetVBLTicks
|
||||
|
||||
cmp lastTick ; Throttle to 60 fps
|
||||
cmp LastTick ; Throttle to 60 fps
|
||||
beq :exit
|
||||
tax ; Calculate the increment
|
||||
sec
|
||||
sbc lastTick
|
||||
stx lastTick
|
||||
sbc LastTick
|
||||
stx LastTick
|
||||
|
||||
; We don't want times to fire excessively. If the timer has nt been evaluated for over
|
||||
; one second, then just skip processing and wait for the next call.
|
||||
@ -186,9 +151,9 @@ _DoTimers
|
||||
phx ; Save our index
|
||||
|
||||
lda Timers+4,x ; execute the timer callback
|
||||
sta :dispatch+1
|
||||
stal :dispatch+1
|
||||
lda Timers+5,x
|
||||
sta :dispatch+2
|
||||
stal :dispatch+2
|
||||
:dispatch jsl $000000
|
||||
|
||||
plx
|
||||
|
21
src/Tool.s
21
src/Tool.s
@ -10,6 +10,7 @@
|
||||
use Core.MACS.s
|
||||
|
||||
use Defs.s
|
||||
use static/TileStoreDefs.s
|
||||
|
||||
ToStrip equ $E10184
|
||||
|
||||
@ -18,8 +19,7 @@ _TSEntry mac
|
||||
phd
|
||||
phb
|
||||
tcd
|
||||
phk ; Default to setting the data back to the current bank.
|
||||
plb
|
||||
jsr _SetDataBank
|
||||
<<<
|
||||
|
||||
_TSExit mac
|
||||
@ -53,6 +53,14 @@ _CallTable
|
||||
adrl _TSLoadTileSet-1
|
||||
_CTEnd
|
||||
|
||||
; Helper function to set the data back to the toolset default
|
||||
_SetDataBank sep #$20
|
||||
lda #^TileStore
|
||||
pha
|
||||
plb
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; Do nothing when the tool set is installed
|
||||
_TSBootInit
|
||||
lda #0
|
||||
@ -86,8 +94,7 @@ zpToUse = userId+4
|
||||
sta EngineMode
|
||||
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _SetDataBank
|
||||
jsr _CoreStartUp ; Initialize the library
|
||||
plb
|
||||
|
||||
@ -114,8 +121,7 @@ _TSShutDown
|
||||
tcd ; Set the direct page for the toolset
|
||||
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _SetDataBank
|
||||
jsr _CoreShutDown ; Shut down the library
|
||||
plb
|
||||
|
||||
@ -201,7 +207,7 @@ xTile equ FirstParam+4
|
||||
tax
|
||||
lda yTile,s ; Valid range [0, 25] (26 rows)
|
||||
tay
|
||||
lda tileId
|
||||
lda tileId,s
|
||||
jsr _SetTile
|
||||
|
||||
_TSExit #0;#6
|
||||
@ -255,7 +261,6 @@ TSPtr equ FirstParam
|
||||
put blitter/BG1.s
|
||||
put blitter/Template.s
|
||||
put blitter/TemplateUtils.s
|
||||
put blitter/Tables.s
|
||||
put blitter/Blitter.s
|
||||
put blitter/TileProcs.s
|
||||
put blitter/Tiles00000.s
|
||||
|
@ -8,14 +8,6 @@ _InitBG0
|
||||
;
|
||||
; A=low word of picture address
|
||||
; X=high word of pixture address
|
||||
CopyBinToField ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyBinToField
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyBinToField
|
||||
:srcptr equ tmp0
|
||||
:line_cnt equ tmp2
|
||||
@ -222,14 +214,6 @@ _CopyBinToField
|
||||
; X=high workd of pixture address
|
||||
;
|
||||
; Picture must be within one bank
|
||||
CopyPicToField ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyPicToField
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyPicToField
|
||||
:srcptr equ tmp0
|
||||
:line_cnt equ tmp2
|
||||
|
@ -9,14 +9,6 @@ _InitBG1
|
||||
; A=low word of picture address
|
||||
; X=high word of pixture address
|
||||
; Y=high word of BG1 bank
|
||||
CopyBinToBG1 ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyBinToBG1
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyBinToBG1
|
||||
:src_width equ tmp6
|
||||
:src_height equ tmp7
|
||||
@ -39,14 +31,6 @@ _CopyBinToBG1
|
||||
; A=low word of picture address
|
||||
; X=high word of pixture address
|
||||
; Y=high word of BG1 bank
|
||||
CopyPicToBG1 ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyPicToBG1
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyPicToBG1
|
||||
:src_width equ tmp6
|
||||
:src_height equ tmp7
|
||||
@ -221,6 +205,8 @@ _ApplyBG1YPos
|
||||
:draw_count equ tmp2
|
||||
:ytbl_idx equ tmp3
|
||||
|
||||
phb ; Save the bank
|
||||
|
||||
lda BG1StartY
|
||||
jsr Mod208
|
||||
sta BG1StartYMod208
|
||||
@ -277,7 +263,6 @@ _ApplyBG1YPos
|
||||
|
||||
jne :loop
|
||||
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
@ -369,16 +354,14 @@ CopyBG1YTableToBG1Addr2
|
||||
phx
|
||||
phb
|
||||
|
||||
phk ; restore access to this bank
|
||||
plb
|
||||
jsr _SetDataBank ; restore access to this bank
|
||||
ldy BG1OffsetIndex ; Get the offset and save the values
|
||||
jsr SaveBG1OffsetValues
|
||||
|
||||
plb
|
||||
plx ; x is used directly in this routine
|
||||
ply
|
||||
jsr ApplyBG1OffsetValues
|
||||
rts
|
||||
jmp ApplyBG1OffsetValues
|
||||
|
||||
SaveBG1OffsetValues
|
||||
jmp (:tbl,x)
|
||||
|
@ -33,10 +33,10 @@ _BltRange
|
||||
|
||||
sep #$20 ; 8-bit Acc
|
||||
lda BTableHigh,x ; patch in the bank
|
||||
sta blt_entry+3
|
||||
stal blt_entry+3
|
||||
|
||||
lda BTableLow+1,x ; patch in the page
|
||||
sta blt_entry+2
|
||||
stal blt_entry+2
|
||||
|
||||
; The way we patch the exit code is subtle, but very fast. The CODE_EXIT offset points to
|
||||
; an JMP/JML instruction that transitions to the next line after all of the code has been
|
||||
@ -74,6 +74,7 @@ _BltRange
|
||||
tsc ; save the stack pointer
|
||||
stal stk_save+1
|
||||
|
||||
bra blt_return
|
||||
blt_entry jml $000000 ; Jump into the blitter code $XX/YY00
|
||||
|
||||
blt_return _R0W0
|
||||
@ -88,5 +89,6 @@ stk_save lda #0000 ; load the stack
|
||||
sta [:exit_ptr],y
|
||||
rep #$20
|
||||
|
||||
blt_out
|
||||
plb ; restore the bank
|
||||
rts
|
||||
|
@ -21,6 +21,8 @@ _RestoreBG0Opcodes
|
||||
:draw_count_x2 equ tmp3
|
||||
:exit_offset equ tmp4
|
||||
|
||||
phb ; Save data bank
|
||||
|
||||
asl
|
||||
sta :virt_line_x2 ; Keep track of it
|
||||
|
||||
@ -75,7 +77,6 @@ _RestoreBG0Opcodes
|
||||
stz LastPatchOffset ; Clear the value once completed
|
||||
|
||||
:out
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
@ -279,6 +280,7 @@ _ApplyBG0XPos
|
||||
; 2. Writes the BRA instruction to exit the code field
|
||||
; 3. Writes the JMP entry point to enter the code field
|
||||
|
||||
phb ; Save the existing bank
|
||||
:loop
|
||||
lda :virt_line
|
||||
asl ; This will clear the carry bit
|
||||
@ -353,7 +355,7 @@ _ApplyBG0XPos
|
||||
ldx :draw_count_x2
|
||||
ldy :base_address ; Y-register is preserved, this can be removed
|
||||
pei :exit_address
|
||||
jmp :SaveHighOperand ; Only used once, so "inline" it
|
||||
jmp :SaveHighOperand ; Only used once, so "inline" it
|
||||
:save_high_op_rtn
|
||||
|
||||
:not_odd
|
||||
@ -374,7 +376,6 @@ _ApplyBG0XPos
|
||||
|
||||
jne :loop
|
||||
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
|
@ -15,13 +15,13 @@
|
||||
_PEISlam
|
||||
lda ScreenWidth
|
||||
dec
|
||||
sta :screen_width_1 ; save the width-1 outside of the direct page
|
||||
stal :screen_width_1 ; save the width-1 outside of the direct page
|
||||
|
||||
lda #:pei_end ; patch the PEI entry address
|
||||
and #$FFFE ; should always be even, but....
|
||||
sec
|
||||
sbc ScreenWidth
|
||||
sta :inner+1
|
||||
stal :inner+1
|
||||
|
||||
phx
|
||||
tya
|
||||
@ -43,7 +43,7 @@ _PEISlam
|
||||
tcd ; screen address to the direct page register
|
||||
|
||||
tsc
|
||||
sta :stk_save ; save the stack pointer to restore later
|
||||
stal :stk_save ; save the stack pointer to restore later
|
||||
|
||||
clc ; clear before the loop -- nothing in the loop affect the carry bit
|
||||
brl :outer ; hop into the entry point.
|
||||
@ -57,7 +57,7 @@ _PEISlam
|
||||
tdc ; Move to the next line
|
||||
adc #160
|
||||
tcd
|
||||
adc :screen_width_1
|
||||
adcl :screen_width_1
|
||||
tcs
|
||||
|
||||
dey ; decrement the total counter, if zero then we're done
|
||||
@ -79,7 +79,7 @@ _PEISlam
|
||||
:restore
|
||||
tsx ; save the current stack
|
||||
_R0W0 ; restore the execution environment and
|
||||
lda :stk_save ; give a few cycles to catch some interrupts
|
||||
ldal :stk_save ; give a few cycles to catch some interrupts
|
||||
tcs
|
||||
cli ; fall through here -- saves a BRA instruction
|
||||
|
||||
@ -92,7 +92,7 @@ _PEISlam
|
||||
|
||||
:exit
|
||||
_R0W0
|
||||
lda :stk_save
|
||||
ldal :stk_save
|
||||
tcs
|
||||
cli
|
||||
|
||||
|
@ -10,14 +10,6 @@
|
||||
; of the BG1 data buffer provides the "fill value".
|
||||
|
||||
ANGLEBNK ext
|
||||
ApplyBG1XPosAngle ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _ApplyBG1XPosAngle
|
||||
plb
|
||||
rtl
|
||||
|
||||
_ApplyBG1XPosAngle
|
||||
; phy
|
||||
|
||||
@ -62,14 +54,6 @@ _ApplyBG1XPosAngle
|
||||
pld
|
||||
rts
|
||||
|
||||
ApplyBG1YPosAngle ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _ApplyBG1YPosAngle
|
||||
plb
|
||||
rtl
|
||||
|
||||
_ApplyBG1YPosAngle
|
||||
:virt_line equ tmp0
|
||||
:lines_left equ tmp1
|
||||
@ -90,6 +74,7 @@ _ApplyBG1YPosAngle
|
||||
lda ScreenHeight
|
||||
sta :lines_left
|
||||
|
||||
phb
|
||||
:loop
|
||||
lda :virt_line
|
||||
asl
|
||||
@ -141,7 +126,6 @@ _ApplyBG1YPosAngle
|
||||
|
||||
jne :loop
|
||||
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
@ -155,14 +139,13 @@ CopyAngleYTableToBG1Addr
|
||||
phx
|
||||
phb
|
||||
|
||||
phk ; restore access to this bank
|
||||
plb
|
||||
|
||||
jsr _SetDataBank ; restore access to this bank
|
||||
jsr SaveBG1AngleValues
|
||||
|
||||
plb
|
||||
plx ; x is used directly in this routine
|
||||
jsr ApplyBG1OffsetValues
|
||||
rts
|
||||
jmp ApplyBG1OffsetValues
|
||||
|
||||
SaveBG1AngleValues
|
||||
jmp (:tbl,x)
|
||||
|
@ -9,15 +9,7 @@
|
||||
; on the SHR screen or the current value of StartY
|
||||
;
|
||||
; This could be made faster by forcing a SCB array to be copied into PEAs ahead of time, but this
|
||||
; is a bit more flexible
|
||||
BltSCB ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _BltSCB
|
||||
plb
|
||||
rtl
|
||||
|
||||
; is a bit more flexible
|
||||
_BltSCBOut
|
||||
rts
|
||||
_BltSCB
|
||||
|
@ -253,19 +253,6 @@ NextCol
|
||||
]step = ]step+2
|
||||
--^
|
||||
|
||||
; A double-sized table of lookup values. This is basically the cross-product of TileStoreYTable and
|
||||
; NextCol. If is double-width and double-height so that, if we know a tile's address position
|
||||
; of (X + 41*Y), then any relative tile store address can be looked up by adding a constant value.
|
||||
;
|
||||
; 50 rows by 80 columns + 2 extra rows and columns
|
||||
TS_LOOKUP_WIDTH equ 80
|
||||
TS_LOOKUP_HEIGHT equ 50
|
||||
TS_LOOKUP_SPAN equ {TS_LOOKUP_WIDTH+2}
|
||||
TS_LOOKUP_ROWS equ {TS_LOOKUP_HEIGHT+2}
|
||||
|
||||
TileStoreLookupYTable ds {TS_LOOKUP_HEIGHT*2}
|
||||
TileStoreLookup ds {TS_LOOKUP_SPAN*TS_LOOKUP_ROWS*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
|
||||
@ -305,6 +292,3 @@ BG1YTable lup 208
|
||||
BG1YOffsetTable lup 26
|
||||
dw 1,1,1,2,2,2,2,2,1,1,1,0,0,0,0,0
|
||||
--^
|
||||
|
||||
; Table of base VBUFF addresses for each sprite stamp slot
|
||||
VBuffAddrTable ds 2*VBUFF_SLOT_COUNT
|
@ -49,7 +49,7 @@ Counter equ tmp3
|
||||
tax ; NOTE: Try to rework to use new TileStore2DLookup array
|
||||
|
||||
lda OnScreenAddr
|
||||
stal TileStore+TS_SCREEN_ADDR,x
|
||||
sta TileStore+TS_SCREEN_ADDR,x
|
||||
|
||||
clc
|
||||
adc #4 ; Go to the next tile
|
||||
@ -278,6 +278,10 @@ BuildBank
|
||||
sta :target+2
|
||||
|
||||
:BuildLine2
|
||||
phb ; save bank and reset to the code bank because
|
||||
phk ; the template is part of this bank
|
||||
plb
|
||||
|
||||
lda #CODE_LEN ; round up to an even number of bytes
|
||||
inc
|
||||
and #$FFFE
|
||||
@ -315,6 +319,6 @@ BuildBank
|
||||
cpx #PagePatchNum
|
||||
bcc :dopage
|
||||
|
||||
:out
|
||||
rep #$20
|
||||
plb
|
||||
rts
|
@ -561,14 +561,6 @@ CopyTileMToDyn
|
||||
; A = Tile ID (0 - 511)
|
||||
; X = Tile column (0 - 40)
|
||||
; Y = Tile row (0 - 25)
|
||||
CopyBG0Tile ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyBG0Tile
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyBG0Tile
|
||||
phb ; save the current bank
|
||||
phx ; save the original x-value
|
||||
@ -614,14 +606,6 @@ _CopyBG0Tile
|
||||
; A = Tile ID (0 - 511)
|
||||
; X = Tile column (0 - 40)
|
||||
; Y = Tile row (0 - 25)
|
||||
CopyBG1Tile
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyBG1Tile
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyBG1Tile
|
||||
phb ; save the current bank
|
||||
phx ; save the original x-value
|
||||
|
@ -36,8 +36,24 @@ _TBSolidTile_VH
|
||||
;
|
||||
; 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.
|
||||
|
||||
|
||||
; This is called via a JMP (abs,x) with an extra byte on the stack that holds the bank
|
||||
; register value. This must be restored prior to returning
|
||||
_TBCopyDataFast
|
||||
tax
|
||||
]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
|
||||
--^
|
||||
plb
|
||||
rts
|
||||
|
||||
|
||||
_TBCopyData
|
||||
]line equ 0
|
||||
lup 8
|
||||
|
@ -45,6 +45,7 @@ _ApplyBG0YPos
|
||||
; and ~2,500 per secord. This is ~1% of our total CPU budget and is *just* enough cycles to be
|
||||
; interesting.... Another 8 cycles could be removed by doing all calculatinos pre-multiplied by 2
|
||||
; to avoid several 'asl' instructions
|
||||
phb
|
||||
:loop
|
||||
lda :virt_line
|
||||
asl
|
||||
@ -91,7 +92,6 @@ _ApplyBG0YPos
|
||||
|
||||
jne :loop
|
||||
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
|
@ -1,4 +1,378 @@
|
||||
; Bank of memory that holds the core sprite and tile store data structures
|
||||
TileStore ENT
|
||||
; ds 65535
|
||||
ds 65536
|
||||
|
||||
put ../Defs.s
|
||||
put TileStoreDefs.s
|
||||
put ../blitter/Template.s
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
; Buffer space
|
||||
|
||||
ds 256
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
|
||||
TileStore ENT
|
||||
ds {TILE_STORE_SIZE*17}
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
; A list of dirty tiles that need to be updated in a given frame
|
||||
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
DirtyTileCount ENT
|
||||
ds 2
|
||||
DirtyTiles ENT
|
||||
ds TILE_STORE_SIZE ; At most this many tiles can possibly be update at once
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
_Sprites ENT
|
||||
ds SPRITE_REC_SIZE*MAX_SPRITES
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
; A double-sized table of lookup values. It is double-width and double-height so that,
|
||||
; if we know a tile's address position of (X + 41*Y), then any relative tile store address
|
||||
; can be looked up by adding a constant value.
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
TileStoreLookupYTable ENT
|
||||
ds {TS_LOOKUP_HEIGHT*2}
|
||||
TileStoreLookup ENT
|
||||
ds {TS_LOOKUP_SPAN*TS_LOOKUP_ROWS*2}
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
; Other data tables
|
||||
|
||||
; Col2CodeOffset
|
||||
;
|
||||
; Takes a column number (0 - 81) and returns the offset into the blitter code
|
||||
; template.
|
||||
;
|
||||
; This is used for rendering tile data into the code field. For example, is we assume that
|
||||
; we are filling in the operands for a bunch of PEA values, we could do this
|
||||
;
|
||||
; ldy tileColumn*2
|
||||
; lda #DATA
|
||||
; ldx Col2CodeOffset,y
|
||||
; sta $0001,x
|
||||
;
|
||||
; The table values are pre-reversed so that loop can go in logical order 0, 2, 4, ...
|
||||
; and the resulting offsets will map to the code instructions in right-to-left order.
|
||||
;
|
||||
; Remember, because the data is pushed on to the stack, the last instruction, which is
|
||||
; in the highest memory location, pushed data that apepars on the left edge of the screen.
|
||||
|
||||
]step equ 0
|
||||
dw CODE_TOP ; There is a spot where we load Col2CodeOffet-2,x
|
||||
Col2CodeOffset ENT
|
||||
lup 82
|
||||
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
|
||||
]step equ ]step+1
|
||||
--^
|
||||
dw CODE_TOP+{81*PER_TILE_SIZE}
|
||||
|
||||
; A parallel table to Col2CodeOffset that holds the offset to the exception handler address for each column
|
||||
]step equ 0
|
||||
dw SNIPPET_BASE
|
||||
JTableOffset ENT
|
||||
lup 82
|
||||
dw SNIPPET_BASE+{{81-]step}*SNIPPET_SIZE}
|
||||
]step equ ]step+1
|
||||
--^
|
||||
dw SNIPPET_BASE+{81*SNIPPET_SIZE}
|
||||
|
||||
; Table of BRA instructions that are used to exit the code field. Separate tables for
|
||||
; even and odd aligned cases.
|
||||
;
|
||||
; The even exit point is closest to the code field. The odd exit point is 3 bytes further
|
||||
;
|
||||
; These tables are reversed to be parallel with the JTableOffset and Col2CodeOffset tables above. The
|
||||
; physical word index that each instruction is intended to be placed at is in the comment.
|
||||
CodeFieldEvenBRA ENT
|
||||
bra *+6 ; 81 -- need to skip over the JMP loop that passed control back
|
||||
bra *+9 ; 80
|
||||
bra *+12 ; 79
|
||||
bra *+15 ; 78
|
||||
bra *+18 ; 77
|
||||
bra *+21 ; 76
|
||||
bra *+24 ; 75
|
||||
bra *+27 ; 74
|
||||
bra *+30 ; 73
|
||||
bra *+33 ; 72
|
||||
bra *+36 ; 71
|
||||
bra *+39 ; 70
|
||||
bra *+42 ; 69
|
||||
bra *+45 ; 68
|
||||
bra *+48 ; 67
|
||||
bra *+51 ; 66
|
||||
bra *+54 ; 65
|
||||
bra *+57 ; 64
|
||||
bra *+60 ; 63
|
||||
bra *+63 ; 62
|
||||
bra *+66 ; 61
|
||||
bra *+69 ; 60
|
||||
bra *+72 ; 59
|
||||
bra *+75 ; 58
|
||||
bra *+78 ; 57
|
||||
bra *+81 ; 56
|
||||
bra *+84 ; 55
|
||||
bra *+87 ; 54
|
||||
bra *+90 ; 53
|
||||
bra *+93 ; 52
|
||||
bra *+96 ; 51
|
||||
bra *+99 ; 50
|
||||
bra *+102 ; 49
|
||||
bra *+105 ; 48
|
||||
bra *+108 ; 47
|
||||
bra *+111 ; 46
|
||||
bra *+114 ; 45
|
||||
bra *+117 ; 44
|
||||
bra *+120 ; 43
|
||||
bra *+123 ; 42
|
||||
bra *+126 ; 41
|
||||
bra *-123 ; 40
|
||||
bra *-120 ; 39
|
||||
bra *-117 ; 38
|
||||
bra *-114 ; 37
|
||||
bra *-111 ; 36
|
||||
bra *-108 ; 35
|
||||
bra *-105 ; 34
|
||||
bra *-102 ; 33
|
||||
bra *-99 ; 32
|
||||
bra *-96 ; 31
|
||||
bra *-93 ; 30
|
||||
bra *-90 ; 29
|
||||
bra *-87 ; 28
|
||||
bra *-84 ; 27
|
||||
bra *-81 ; 26
|
||||
bra *-78 ; 25
|
||||
bra *-75 ; 24
|
||||
bra *-72 ; 23
|
||||
bra *-69 ; 22
|
||||
bra *-66 ; 21
|
||||
bra *-63 ; 20
|
||||
bra *-60 ; 19
|
||||
bra *-57 ; 18
|
||||
bra *-54 ; 17
|
||||
bra *-51 ; 16
|
||||
bra *-48 ; 15
|
||||
bra *-45 ; 14
|
||||
bra *-42 ; 13
|
||||
bra *-39 ; 12
|
||||
bra *-36 ; 11
|
||||
bra *-33 ; 10
|
||||
bra *-30 ; 9
|
||||
bra *-27 ; 8
|
||||
bra *-24 ; 7
|
||||
bra *-21 ; 6
|
||||
bra *-18 ; 5
|
||||
bra *-15 ; 4
|
||||
bra *-12 ; 3
|
||||
bra *-9 ; 2
|
||||
bra *-6 ; 1
|
||||
bra *-3 ; 0
|
||||
|
||||
CodeFieldOddBRA ENT
|
||||
bra *+9 ; 81 -- need to skip over two JMP instructions
|
||||
bra *+12 ; 80
|
||||
bra *+15 ; 79
|
||||
bra *+18 ; 78
|
||||
bra *+21 ; 77
|
||||
bra *+24 ; 76
|
||||
bra *+27 ; 75
|
||||
bra *+30 ; 74
|
||||
bra *+33 ; 73
|
||||
bra *+36 ; 72
|
||||
bra *+39 ; 71
|
||||
bra *+42 ; 70
|
||||
bra *+45 ; 69
|
||||
bra *+48 ; 68
|
||||
bra *+51 ; 67
|
||||
bra *+54 ; 66
|
||||
bra *+57 ; 65
|
||||
bra *+60 ; 64
|
||||
bra *+63 ; 64
|
||||
bra *+66 ; 62
|
||||
bra *+69 ; 61
|
||||
bra *+72 ; 60
|
||||
bra *+75 ; 59
|
||||
bra *+78 ; 58
|
||||
bra *+81 ; 57
|
||||
bra *+84 ; 56
|
||||
bra *+87 ; 55
|
||||
bra *+90 ; 54
|
||||
bra *+93 ; 53
|
||||
bra *+96 ; 52
|
||||
bra *+99 ; 51
|
||||
bra *+102 ; 50
|
||||
bra *+105 ; 49
|
||||
bra *+108 ; 48
|
||||
bra *+111 ; 47
|
||||
bra *+114 ; 46
|
||||
bra *+117 ; 45
|
||||
bra *+120 ; 44
|
||||
bra *+123 ; 43
|
||||
bra *+126 ; 42
|
||||
bra *+129 ; 41
|
||||
bra *-126 ; 40
|
||||
bra *-123 ; 39
|
||||
bra *-120 ; 38
|
||||
bra *-117 ; 37
|
||||
bra *-114 ; 36
|
||||
bra *-111 ; 35
|
||||
bra *-108 ; 34
|
||||
bra *-105 ; 33
|
||||
bra *-102 ; 32
|
||||
bra *-99 ; 31
|
||||
bra *-96 ; 30
|
||||
bra *-93 ; 29
|
||||
bra *-90 ; 28
|
||||
bra *-87 ; 27
|
||||
bra *-84 ; 26
|
||||
bra *-81 ; 25
|
||||
bra *-78 ; 24
|
||||
bra *-75 ; 23
|
||||
bra *-72 ; 22
|
||||
bra *-69 ; 21
|
||||
bra *-66 ; 20
|
||||
bra *-63 ; 19
|
||||
bra *-60 ; 18
|
||||
bra *-57 ; 17
|
||||
bra *-54 ; 16
|
||||
bra *-51 ; 15
|
||||
bra *-48 ; 14
|
||||
bra *-45 ; 13
|
||||
bra *-42 ; 12
|
||||
bra *-39 ; 11
|
||||
bra *-36 ; 10
|
||||
bra *-33 ; 9
|
||||
bra *-30 ; 8
|
||||
bra *-27 ; 7
|
||||
bra *-24 ; 6
|
||||
bra *-21 ; 5
|
||||
bra *-18 ; 4
|
||||
bra *-15 ; 3
|
||||
bra *-12 ; 2
|
||||
bra *-9 ; 1
|
||||
bra *-6 ; 0 -- branch back 6 to skip the JMP even path
|
||||
|
||||
]step equ $2000
|
||||
ScreenAddr ENT
|
||||
lup 200
|
||||
dw ]step
|
||||
]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.
|
||||
;
|
||||
; This table is double-length to support accessing off the end modulo its legth
|
||||
TileStoreYTable ENT
|
||||
]step equ 0
|
||||
lup 26
|
||||
dw ]step
|
||||
]step = ]step+{41*2}
|
||||
--^
|
||||
]step equ 0
|
||||
lup 26
|
||||
dw ]step
|
||||
]step = ]step+{41*2}
|
||||
--^
|
||||
|
||||
; Create a table to look up the "next" column with modulo wraparound. Basically a[i] = i
|
||||
; and the table is double-length. Use constant offsets to pick an amount to advance
|
||||
NextCol ENT
|
||||
]step equ 0
|
||||
lup 41
|
||||
dw ]step
|
||||
]step = ]step+2
|
||||
--^
|
||||
]step equ 0
|
||||
lup 41
|
||||
dw ]step
|
||||
]step = ]step+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
|
||||
; playfield is less than 200 lines tall, then any values after 2 * PLAYFIELD_HEIGHT are undefined.
|
||||
RTable ENT
|
||||
ds 400
|
||||
ds 400
|
||||
|
||||
; Array of addresses for the banks that hold the blitter.
|
||||
BlitBuff ENT
|
||||
dw $5a5a
|
||||
ds 4*13
|
||||
|
||||
; The blitter table (BTable) is a double-length table that holds the full 4-byte address of each
|
||||
; line of the blit fields. We decompose arrays of pointers into separate high and low words so
|
||||
; that everything can use the same indexing offsets
|
||||
BTableHigh ENT
|
||||
ds 208*2*2
|
||||
BTableLow ENT
|
||||
ds 208*2*2
|
||||
|
||||
; A shorter table that just holds the blitter row addresses
|
||||
BRowTableHigh ENT
|
||||
ds 26*2*2
|
||||
BRowTableLow ENT
|
||||
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 center the buffer in the bank
|
||||
]step equ $1800
|
||||
BG1YTable ENT
|
||||
lup 208
|
||||
dw ]step
|
||||
]step = ]step+256
|
||||
--^
|
||||
]step equ 256
|
||||
lup 208
|
||||
dw ]step
|
||||
]step = ]step+256
|
||||
--^
|
||||
|
||||
; Repeat
|
||||
BG1YOffsetTable ENT
|
||||
lup 26
|
||||
dw 1,1,1,2,2,2,2,2,1,1,1,0,0,0,0,0
|
||||
--^
|
||||
|
||||
; Other Toolset variables
|
||||
OneSecondCounter ENT
|
||||
dw 0
|
||||
OldOneSecVec ENT
|
||||
ds 4
|
||||
Timers ENT
|
||||
ds TIMER_REC_SIZE*MAX_TIMERS
|
||||
DefaultPalette ENT
|
||||
dw $0000,$007F,$0090,$0FF0
|
||||
dw $000F,$0080,$0f70,$0FFF
|
||||
dw $0fa9,$0ff0,$00e0,$04DF
|
||||
dw $0d00,$078f,$0ccc,$0FFF
|
||||
|
||||
; 0. Full Screen : 40 x 25 320 x 200 (32,000 bytes (100.0%))
|
||||
; 1. Sword of Sodan : 34 x 24 272 x 192 (26,112 bytes ( 81.6%))
|
||||
; 2. ~NES : 32 x 25 256 x 200 (25,600 bytes ( 80.0%))
|
||||
; 3. Task Force : 32 x 22 256 x 176 (22,528 bytes ( 70.4%))
|
||||
; 4. Defender of the World : 35 x 20 280 x 160 (22,400 bytes ( 70.0%))
|
||||
; 5. Rastan : 32 x 20 256 x 160 (20,480 bytes ( 64.0%))
|
||||
; 6. Game Boy Advanced : 30 x 20 240 x 160 (19,200 bytes ( 60.0%))
|
||||
; 7. Ancient Land of Y's : 36 x 16 288 x 128 (18,432 bytes ( 57.6%))
|
||||
; 8. Game Boy Color : 20 x 18 160 x 144 (11,520 bytes ( 36.0%))
|
||||
; 9. Agony (Amiga) : 36 x 24 288 x 192 (27,648 bytes ( 86.4%))
|
||||
; 10. Atari Lynx : 20 x 13 160 x 102 (8,160 bytes ( 25.5%))
|
||||
ScreenModeWidth ENT
|
||||
dw 320,272,256,256,280,256,240,288,160,288,160,320
|
||||
ScreenModeHeight ENT
|
||||
dw 200,192,200,176,160,160,160,128,144,192,102,1
|
||||
|
||||
blt_return
|
||||
stk_save
|
116
src/static/TileStoreDefs.s
Normal file
116
src/static/TileStoreDefs.s
Normal file
@ -0,0 +1,116 @@
|
||||
; Tile storage parameters
|
||||
TILE_DATA_SPAN equ 4
|
||||
TILE_STORE_WIDTH equ 41
|
||||
TILE_STORE_HEIGHT equ 26
|
||||
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
|
||||
|
||||
TS_TILE_ID equ TILE_STORE_SIZE*0 ; tile descriptor for this location
|
||||
TS_DIRTY equ TILE_STORE_SIZE*1 ; Flag. Used to prevent a tile from being queued multiple times per frame
|
||||
TS_SPRITE_FLAG equ TILE_STORE_SIZE*2 ; Bitfield of all sprites that intersect this tile. 0 if no sprites.
|
||||
TS_TILE_ADDR equ TILE_STORE_SIZE*3 ; cached value, the address of the tiledata for this tile
|
||||
TS_CODE_ADDR_LOW equ TILE_STORE_SIZE*4 ; const value, address of this tile in the code fields
|
||||
TS_CODE_ADDR_HIGH equ TILE_STORE_SIZE*5
|
||||
TS_WORD_OFFSET equ TILE_STORE_SIZE*6 ; const value, word offset value for this tile if LDA (dp),y instructions re used
|
||||
TS_BASE_ADDR equ TILE_STORE_SIZE*7 ; const value, because there are two rows of tiles per bank, this is set to $0000 ot $8000.
|
||||
TS_SCREEN_ADDR equ TILE_STORE_SIZE*8 ; cached value of on-screen location of tile. Used for DirtyRender.
|
||||
;TS_VBUFF_ARRAY_ADDR equ TILE_STORE_SIZE*9 ; const value to an aligned 32-byte array starting at $8000 in TileStore bank
|
||||
|
||||
TS_BASE_TILE_COPY equ TILE_STORE_SIZE*9 ; derived from TS_TILE_ID to optimize tile copy to support sprite rendering
|
||||
TS_BASE_TILE_DISP equ TILE_STORE_SIZE*10 ; derived from TS_TILE_ID to optimize base (non-sprite) tile dispatch in the Render function
|
||||
TS_DIRTY_TILE_DISP equ TILE_STORE_SIZE*11 ; derived from TS_TILE_ID to optimize dirty tile dispatch in the Render function
|
||||
|
||||
; Hold values for up to 4 sprites per tile
|
||||
TS_VBUFF_ADDR_0 equ TILE_STORE_SIZE*12
|
||||
TS_VBUFF_ADDR_1 equ TILE_STORE_SIZE*13
|
||||
TS_VBUFF_ADDR_2 equ TILE_STORE_SIZE*14
|
||||
TS_VBUFF_ADDR_3 equ TILE_STORE_SIZE*15
|
||||
TS_VBUFF_ADDR_COUNT equ TILE_STORE_SIZE*16 ; replace usage of TS_VBUFF_ARRAY_ADDR with this later
|
||||
|
||||
; 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.
|
||||
|
||||
MAX_SPRITES equ 16
|
||||
SPRITE_REC_SIZE equ 52
|
||||
|
||||
; Mark each sprite as ADDED, UPDATED, MOVED, REMOVED depending on the actions applied to it
|
||||
; on this frame. Quick note, the same Sprite ID cannot be removed and added in the same frame.
|
||||
; A REMOVED sprite if removed from the sprite list during the Render call, so it's ID is not
|
||||
; available to the AddSprite function until the next frame.
|
||||
|
||||
SPRITE_STATUS_EMPTY equ $0000 ; If the status value is zero, this sprite slot is available
|
||||
SPRITE_STATUS_OCCUPIED equ $8000 ; Set the MSB to flag it as occupied
|
||||
SPRITE_STATUS_ADDED equ $0001 ; Sprite was just added (new sprite)
|
||||
SPRITE_STATUS_MOVED equ $0002 ; Sprite's position was changed
|
||||
SPRITE_STATUS_UPDATED equ $0004 ; Sprite's non-position attributes were changed
|
||||
SPRITE_STATUS_REMOVED equ $0008 ; Sprite has been removed.
|
||||
|
||||
SPRITE_STATUS equ {MAX_SPRITES*0}
|
||||
; TILE_DATA_OFFSET equ {MAX_SPRITES*2}
|
||||
VBUFF_ADDR equ {MAX_SPRITES*4} ; Base address of the sprite's stamp in the data/mask banks
|
||||
SPRITE_ID equ {MAX_SPRITES*6}
|
||||
SPRITE_X equ {MAX_SPRITES*8}
|
||||
SPRITE_Y equ {MAX_SPRITES*10}
|
||||
; TILE_STORE_ADDR_1 equ {MAX_SPRITES*12}
|
||||
TS_LOOKUP_INDEX equ {MAX_SPRITES*12} ; The index into the TileStoreLookup table corresponding to the top-left corner of the sprite
|
||||
; TILE_STORE_ADDR_2 equ {MAX_SPRITES*14}
|
||||
TS_COVERAGE_SIZE equ {MAX_SPRITES*14} ; Index into the lookup table of how many TileStore tiles are covered by this sprite
|
||||
;TILE_STORE_ADDR_3 equ {MAX_SPRITES*16}
|
||||
TS_VBUFF_BASE_ADDR equ {MAX_SPRITES*16} ; Fixed address of the TS_VBUFF_X memory locations
|
||||
;TILE_STORE_ADDR_4 equ {MAX_SPRITES*18}
|
||||
;TILE_STORE_ADDR_5 equ {MAX_SPRITES*20}
|
||||
;TILE_STORE_ADDR_6 equ {MAX_SPRITES*22}
|
||||
;TILE_STORE_ADDR_7 equ {MAX_SPRITES*24}
|
||||
;TILE_STORE_ADDR_8 equ {MAX_SPRITES*26}
|
||||
;TILE_STORE_ADDR_9 equ {MAX_SPRITES*28}
|
||||
;TILE_STORE_ADDR_10 equ {MAX_SPRITES*30}
|
||||
SPRITE_DISP equ {MAX_SPRITES*32} ; cached address of the specific stamp based on flags
|
||||
SPRITE_CLIP_LEFT equ {MAX_SPRITES*34}
|
||||
SPRITE_CLIP_RIGHT equ {MAX_SPRITES*36}
|
||||
SPRITE_CLIP_TOP equ {MAX_SPRITES*38}
|
||||
SPRITE_CLIP_BOTTOM equ {MAX_SPRITES*40}
|
||||
IS_OFF_SCREEN equ {MAX_SPRITES*42}
|
||||
SPRITE_WIDTH equ {MAX_SPRITES*44}
|
||||
SPRITE_HEIGHT equ {MAX_SPRITES*46}
|
||||
SPRITE_CLIP_WIDTH equ {MAX_SPRITES*48}
|
||||
SPRITE_CLIP_HEIGHT equ {MAX_SPRITES*50}
|
||||
|
||||
; 50 rows by 80 columns + 2 extra rows and columns
|
||||
TS_LOOKUP_WIDTH equ 80
|
||||
TS_LOOKUP_HEIGHT equ 50
|
||||
TS_LOOKUP_SPAN equ {TS_LOOKUP_WIDTH+2}
|
||||
TS_LOOKUP_ROWS equ {TS_LOOKUP_HEIGHT+2}
|
||||
|
||||
; Blitter template constancts
|
||||
PER_TILE_SIZE equ 3
|
||||
SNIPPET_SIZE equ 32
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
;
|
||||
; Timer implementation
|
||||
;
|
||||
; The engire provides four timer slot that can be used by one-shot or
|
||||
; recurring timers. Each timer is given an initial tick count, a
|
||||
; reset tick count (0 = one-shot), and an action to perform.
|
||||
;
|
||||
; The timers handle overflow, so if a recurring timer has a tick count of 3
|
||||
; and 7 VBL ticks have passed, then the timer will be fired twice and
|
||||
; a tick count of 2 will be set.
|
||||
;
|
||||
; As such, the timers are appropriate to drive physical and other game
|
||||
; behaviors at a frame-independent rate.
|
||||
;
|
||||
; A collection of 4 timers that are triggered when their countdown
|
||||
; goes below zero. Each timer takes up 16 bytes
|
||||
;
|
||||
; A timer can fire multiple times during a singular evaluation. For example, if the
|
||||
; timer delay is set to 1 and 3 VBL ticks happen, then the timer delta is -2, will fire,
|
||||
; have the delay added and get -1, fire again, increment to zero, first again and then
|
||||
; finally reset to 1.
|
||||
;
|
||||
; +0 counter decremented by the number of ticks since last run
|
||||
; +2 reset copied into counter when triggered. 0 turns off the timer.
|
||||
; +4 addr long address of timer routine
|
||||
; +8 user 8 bytes of user data space for timer state
|
||||
MAX_TIMERS equ 4
|
||||
TIMER_REC_SIZE equ 16
|
@ -1,8 +1,3 @@
|
||||
|
||||
; 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
|
||||
|
||||
_ClearDirtyTiles
|
||||
bra :hop
|
||||
:loop
|
||||
@ -62,3 +57,110 @@ _PopDirtyTile2 ; alternate entry point
|
||||
lda #$FFFF
|
||||
stal TileStore+TS_DIRTY,x ; clear the occupied backlink
|
||||
rts
|
||||
|
||||
; An optimized subroutine that runs through the dirty tile list and executes a callback function
|
||||
; for each dirty tile. This is an unrolled loop, so we avoid the need to track a register and
|
||||
; decrement on each iteration.
|
||||
;
|
||||
; Also, if we are handling less that 8 dirty tiles, we use a code path that does not
|
||||
; need to use an index register
|
||||
;
|
||||
; Bank = Tile Store
|
||||
; D = Page 2
|
||||
_PopDirtyTilesFast
|
||||
ldx DP2_DIRTY_TILE_COUNT ; This is pre-multiplied by 2
|
||||
bne pdtf_not_empty ; If there are no items, exit
|
||||
at_exit rts
|
||||
pdtf_not_empty
|
||||
cpx #16 ; If there are >= 8 elements, then
|
||||
bcs full_chunk ; do a full chunk
|
||||
|
||||
stz DP2_DIRTY_TILE_COUNT ; Otherwise, this pass will handle them all
|
||||
jmp (at_table,x)
|
||||
at_table da at_exit,at_one,at_two,at_three
|
||||
da at_four,at_five,at_six,at_seven
|
||||
|
||||
full_chunk txa
|
||||
sbc #16 ; carry set from branch
|
||||
sta DP2_DIRTY_TILE_COUNT ; fall through
|
||||
tay ; use the Y-register for the index
|
||||
|
||||
; Because all of the registers get used in the subroutine, we
|
||||
; push the values from the DirtyTiles array onto the stack and then pop off
|
||||
; the values as we go
|
||||
|
||||
ldx DirtyTiles+14,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+12,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+10,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+8,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+6,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+4,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+2,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+0,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
jmp _PopDirtyTilesFast
|
||||
|
||||
; These routines just handle between 1 and 7 dirty tiles
|
||||
at_seven
|
||||
ldx DirtyTiles+12
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
at_six
|
||||
ldx DirtyTiles+10
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
at_five
|
||||
ldx DirtyTiles+8
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
at_four
|
||||
ldx DirtyTiles+6
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
at_three
|
||||
ldx DirtyTiles+4
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
at_two
|
||||
ldx DirtyTiles+2
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTileFast
|
||||
|
||||
at_one
|
||||
ldx DirtyTiles+0
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jmp _RenderTileFast
|
||||
|
@ -6,20 +6,12 @@
|
||||
; If there are sprites, then the sprite data is flattened and stored into a direct page buffer
|
||||
; and then copied into the code field
|
||||
_RenderTileFast
|
||||
ldx TileStore+TS_VBUFF_ADDR_COUNT,y ; How many sprites are on this tile?
|
||||
beq NoSpritesFast ; This is faster if there are no sprites
|
||||
jmp (fast_dispatch,x) ; Dispatch to the other routines
|
||||
fast_dispatch
|
||||
da NoSpritesFast
|
||||
da OneSpriteFast
|
||||
da TwoSpritesFast
|
||||
da ThreeSpritesFast
|
||||
da FourSpritesFast
|
||||
; lda TileStore+TS_VBUFF_ADDR_COUNT,x ; How many sprites are on this tile?
|
||||
; bne SpriteDispatch ; This is faster if there are no sprites
|
||||
|
||||
NoSpritesFast
|
||||
tyx
|
||||
NoSpriteFast
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has addl bank in high byte.
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated)
|
||||
plb ; set the code field bank
|
||||
@ -27,7 +19,17 @@ NoSpritesFast
|
||||
|
||||
; The TS_BASE_TILE_DISP routines will come from this table when ENGINE_MODE_TWO_LAYER and
|
||||
; ENGINE_MODE_DYN_TILES are both off.
|
||||
FastTileProcs dw _TBCopyDataFast,_TBCopyDataFast,_TBCopyDataVFast,_TBCopyDataVFast
|
||||
FastTileProcs dw _TBCopyDataFast,_TBCopyDataFast,_TBCopyDataFast,_TBCopyDataFast
|
||||
; dw _TBCopyDataFast,_TBCopyDataFast,_TBCopyDataVFast,_TBCopyDataVFast
|
||||
|
||||
SpriteDispatch
|
||||
tax
|
||||
jmp (:,x) ; Dispatch to the other routines
|
||||
: da NoSpriteFast ; Placeholder
|
||||
da OneSpriteFast
|
||||
da TwoSpritesFast
|
||||
da ThreeSpritesFast
|
||||
da FourSpritesFast
|
||||
|
||||
; Pointers to sprite data and masks
|
||||
spritedata_0 equ tmp0
|
||||
|
Loading…
x
Reference in New Issue
Block a user