Checkpoint of work

This commit is contained in:
Lucas Scharenbroich 2022-01-19 20:58:57 -06:00
parent 3848c98a21
commit 027f9746ec
7 changed files with 346 additions and 7 deletions

View File

@ -166,7 +166,7 @@ There are four subroutines that are available to provide sprite support in GTE:
# Rendering a Frame
There is a single `Render` subroutine that applies all of the frame changes and efficiently renders to the super hires screen. It bear repeating here that most of the GTE functions operate in a deferred manner; any expensive operation that involved updating internal data structures is delayed until the `Render` function in called.
There is a single `Render` subroutine that applies all of the frame changes and efficiently renders to the super hires screen. It bears repeating here that most of the GTE functions operate in a deferred manner; any expensive operation that involved updating internal data structures is delayed until the `Render` function in called.
```asm
jsl Render
@ -185,4 +185,5 @@ GTE provides the following capabilities
* [Apple IIgs Graphics and Sound College](https://www.kansasfest.org/wp-content/uploads/1992-heineman-gs.pdf)
* [Adaptive Tile Refresh](https://en.wikipedia.org/wiki/Adaptive_tile_refresh)
* [A Guide to the Graphics of the Sega Mega Drive / Genesis](https://rasterscroll.com/mdgraphics/)
* [Jon Burton / Traveller's Tales / Coding Secrets](https://ttjontt.wixsite.com/gamehut/coding-secrets)
* [Jon Burton / Traveller's Tales / Coding Secrets](https://ttjontt.wixsite.com/gamehut/coding-secrets)
* [Lou's Pseudo 3d Page](http://www.extentofthejam.com/pseudo/)

View File

@ -158,3 +158,4 @@ TS_CODE_ADDR_HIGH equ TILE_STORE_SIZE*5 ; const value
TS_WORD_OFFSET equ TILE_STORE_SIZE*6
TS_BASE_ADDR equ TILE_STORE_SIZE*7
TS_SPRITE_ADDR equ TILE_STORE_SIZE*8
TS_SCREEN_ADDR equ TILE_STORE_SIZE*9

View File

@ -48,6 +48,7 @@ StopScript EXT
AddSprite EXT
MoveSprite EXT ; Set an existing sprite's position
UpdateSprite EXT ; Change an existing sprite's flags
RemoveSprite EXT
; Direct access to internals
DoScriptSeq EXT
@ -60,6 +61,8 @@ RenderTile EXT ; Y = address from GetTileStoreOffset
GetTileStoreOffset EXT ; X = column, Y = row
TileStore EXT ; Tile store internal data structure
RenderDirty EXT ; Render only dirty tiles + sprites directly to the SHR screen
GetSpriteVBuffAddr EXT ; X = x-coordinate (0 - 159), Y = y-coordinate (0 - 199). Return in Acc.
; Allocate a full 64K bank

View File

@ -140,3 +140,141 @@ _Render
stz DirtyBits
rts
; This is a specialized redner function that only updated the dirty tiles *and* draws them
; directly onto the SHR graphics buffer. The playfield is not used at all. In some way, this
; ignores almost all of the capabilities of GTE, but it does provide a convenient way to use
; the sprite subsystem + tile attributes for single-screen games which should be able to run
; close to 60 fps.
RenderDirty ENT
phb
phk
plb
jsr _RenderDirty
plb
rtl
; In this renderer, we assume that thwere is no scrolling, so no need to update any information about
; the BG0/BG1 positions
_RenderDirty
jsr _RenderSprites
jsr _ApplyDirtyTiles
rts
_ApplyDirtyTiles
bra :begin
:loop
; Retrieve the offset of the next dirty Tile Store items in the Y-register
jsr _PopDirtyTile2
; Call the generic dispatch with the Tile Store record pointer at by the Y-register.
phb
jsr _RenderDirtyTile
plb
; Loop again until the list of dirty tiles is empty
:begin ldx DirtyTileCount
bne :loop
rts
; Only render solid tiles and sprites
_RenderDirtyTile
lda TileStore+TS_TILE_ID,y ; build the finalized tile descriptor
and #TILE_VFLIP_BIT+TILE_HFLIP_BIT ; get the lookup value
xba
ldx TileStore+TS_SPRITE_FLAG,y ; This is a bitfield of all the sprites that intersect this tile, only care if non-zero or not
beq :nosprite
ldx TileStore+TS_SPRITE_ADDR,y
stx _SPR_X_REG
tax
lda DirtyTileSpriteProcs,x
sta :tiledisp+1
bra :sprite
:nosprite
tax
lda DirtyTileProcs,x ; load and patch in the appropriate subroutine
sta :tiledisp+1
:sprite
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
lda TileStore+TS_SCREEN_ADDR,y ; Get the on-screen address of this tile
pha
lda TileStore+TS_WORD_OFFSET,y
ply
pea $0101
plb
plb ; set the bank
; B is set to Bank 01
; 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 SHR screen
; X is set to the address of the tile data
:tiledisp jmp $0000 ; render the tile
DirtyTileProcs dw _TBDirtyTile_00,_TBDirtyTile_0H,_TBDirtyTile_V0,_TBDirtyTile_VH
DirtyTileSpriteProcs dw _TBDirtySpriteTile_00,_TBDirtySpriteTile_0H,_TBDirtySpriteTile_V0,_TBDirtySpriteTile_VH
; Blit tiles directly to the screen.
_TBDirtyTile_00
_TBDirtyTile_0H
]line equ 0
lup 8
ldal tiledata+{]line*4},x
sta: $0000+{]line*160},y
ldal tiledata+{]line*4}+2,x
sta: $0002+{]line*160},y
]line equ ]line+1
--^
rts
_TBDirtyTile_V0
_TBDirtyTile_VH
]src equ 7
]dest equ 0
lup 8
ldal tiledata+{]src*4},x
sta: $0000+{]dest*160},y
ldal tiledata+{]src*4}+2,x
sta: $0002+{]dest*160},y
]src equ ]src-1
]dest equ ]dest+1
--^
rts
_TBDirtySpriteTile_00
_TBDirtySpriteTile_0H
jsr _TBCopyTileDataToCBuff ; Copy the tile into the compositing buffer (using correct x-register)
jmp _TBApplyDirtySpriteData ; Overlay the data from the sprite plane (and copy into the code field)
_TBDirtySpriteTile_V0
_TBDirtySpriteTile_VH
jsr _TBCopyTileDataToCBuffV
jmp _TBApplyDirtySpriteData
_TBApplyDirtySpriteData
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: $0000+{]line*160},y
lda blttmp+{]line*4}+2
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
sta: $0002+{]line*160},y
]line equ ]line+1
--^
rts

View File

@ -177,7 +177,8 @@ _RenderSprites
ora forceSpriteFlag
and #SPRITE_STATUS_DIRTY ; If the dirty flag is set, do the things....
bne :render
:next iny
:next
iny
iny
bra :loop
:out rts
@ -312,7 +313,8 @@ erase_16x8
erase_16x16
clc
ldx _Sprites+OLD_VBUFF_ADDR,y
jsr _EraseTileSprite
jmp _EraseTileSprite16x16
; jsr _EraseTileSprite
txa
adc #4
@ -449,7 +451,9 @@ draw_16x16
ldx _Sprites+VBUFF_ADDR,y
lda _Sprites+TILE_DATA_OFFSET,y
tay
jsr _DrawTile8x8
jmp _DrawTile16x16
; jsr _DrawTile8x8
txa
adc #4
tax
@ -605,6 +609,102 @@ _DrawTile8x8
plb
rts
; X = sprite vbuff address
; Y = tile data pointer
_DrawTile16x16
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
and: tiledata+32+{]line*4},y
ora: tiledata+{]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
and: tiledata+32+{]line*4}+2,y
ora: tiledata+{]line*4}+2,y
stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
lda: tiledata+32+128+{]line*4},y
andl spritemask+{]line*SPRITE_PLANE_SPAN}+4,x
stal spritemask+{]line*SPRITE_PLANE_SPAN}+4,x
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+4,x
and: tiledata+32+128+{]line*4},y
ora: tiledata+128+{]line*4},y
stal spritedata+{]line*SPRITE_PLANE_SPAN}+4,x
lda: tiledata+32+128+{]line*4}+2,y
andl spritemask+{]line*SPRITE_PLANE_SPAN}+6,x
stal spritemask+{]line*SPRITE_PLANE_SPAN}+6,x
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+6,x
and: tiledata+32+128+{]line*4}+2,y
ora: tiledata+128+{]line*4}+2,y
stal spritedata+{]line*SPRITE_PLANE_SPAN}+6,x
]line equ ]line+1
--^
TILE_ROW_STRIDE equ 32*128
SPRITE_ROW_STRIDE equ 8*SPRITE_PLANE_SPAN
]line equ 0
lup 8
lda: tiledata+TILE_ROW_STRIDE+32+{]line*4},y
andl spritemask+SPRITE_ROW_STRIDE+{]line*256},x
stal spritemask+SPRITE_ROW_STRIDE+{]line*256},x
ldal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN},x
and: tiledata+TILE_ROW_STRIDE+32+{]line*4},y
ora: tiledata+TILE_ROW_STRIDE+{]line*4},y
stal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN},x
lda: tiledata+TILE_ROW_STRIDE+32+{]line*4}+2,y
andl spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+2,x
stal spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+2,x
ldal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+2,x
and: tiledata+TILE_ROW_STRIDE+32+{]line*4}+2,y
ora: tiledata+TILE_ROW_STRIDE+{]line*4}+2,y
stal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+2,x
lda: tiledata+TILE_ROW_STRIDE+32+128+{]line*4},y
andl spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+4,x
stal spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+4,x
ldal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+4,x
and: tiledata+TILE_ROW_STRIDE+32+128+{]line*4},y
ora: tiledata+TILE_ROW_STRIDE+128+{]line*4},y
stal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+4,x
lda: tiledata+TILE_ROW_STRIDE+32+128+{]line*4}+2,y
andl spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+6,x
stal spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+6,x
ldal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+6,x
and: tiledata+TILE_ROW_STRIDE+128+32+{]line*4}+2,y
ora: tiledata+TILE_ROW_STRIDE+128+{]line*4}+2,y
stal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+6,x
]line equ ]line+1
--^
plb ; pop extra byte
plb
rts
; X = sprite vbuff address
; Y = tile data pointer
;
@ -695,6 +795,38 @@ _EraseTileSprite
plb
rts
_EraseTileSprite16x16
phb ; Save the bank to switch to the sprite plane
pea #^spritedata
plb
lda #0
]line equ 0
lup 16
sta: {]line*SPRITE_PLANE_SPAN}+0,x
sta: {]line*SPRITE_PLANE_SPAN}+2,x
sta: {]line*SPRITE_PLANE_SPAN}+4,x
sta: {]line*SPRITE_PLANE_SPAN}+6,x
]line equ ]line+1
--^
pea #^spritemask
plb
lda #$FFFF
]line equ 0
lup 16
sta: {]line*SPRITE_PLANE_SPAN}+0,x
sta: {]line*SPRITE_PLANE_SPAN}+2,x
sta: {]line*SPRITE_PLANE_SPAN}+4,x
sta: {]line*SPRITE_PLANE_SPAN}+6,x
]line equ ]line+1
--^
pla
plb
rts
; Add a new sprite to the rendering pipeline
;
; The tile id ithe range 0 - 511. The top 7 bits are used as sprite control bits
@ -785,6 +917,36 @@ _GetSpriteVBuffAddr
pla
rts
; Remove a sprite from the list. Just mark its STATUS as FREE and it will be
; picked up in the next AddSprite. We have to be carful not to set it to zero
; as that will truncate the sprite list
;
; A = Sprite ID
RemoveSprite ENT
phb
phk
plb
jsr _RemoveSprite
plb
rtl
_RemoveSprite
cmp #MAX_SPRITES*2 ; Make sure we're in bounds
bcc :ok
rts
:ok
lda #SPRITE_STATUS_FREE
sta _Sprites+SPRITE_STATUS,x
lda tmp0 ; Update the Tile ID
sta _Sprites+SPRITE_ID,x ; Keep a copy of the full descriptor
jsr _GetTileAddr ; This applies the TILE_ID_MASK
sta _Sprites+TILE_DATA_OFFSET,x
rts
; Update the sprite's flags. We do not allow the size fo a sprite to be changed. That required
; the sprite to be removed and re-added.
;
@ -878,6 +1040,7 @@ SPRITE_REC_SIZE equ 34
SPRITE_STATUS_EMPTY equ 0
SPRITE_STATUS_CLEAN equ 1
SPRITE_STATUS_DIRTY equ 2
SPRITE_STATUS_FREE equ 4
SPRITE_STATUS equ {MAX_SPRITES*0}
TILE_DATA_OFFSET equ {MAX_SPRITES*2}

View File

@ -124,6 +124,38 @@ SetScreenRect sty ScreenHeight ; Save the screen height and
inx
dey
bne :loop
; Calculate the screen locations for each tile cornder
lda ScreenY0 ; Calculate the address of the first byte
asl ; of the right side of the playfield
tax
lda ScreenAddr,x ; This is the address for the left edge of the physical screen
clc
adc ScreenX0
ldx #0
ldy #0
:tsloop
sta TileStore+TS_SCREEN_ADDR,X
clc
adc #4 ; Go to the next tile
iny
cpy #41 ; If we've done 41 columns, move to the next line
bcc :nohop
ldy #0
clc
adc #{8*160}-{4*41}
:nohop
inx
inx
cpx #TILE_STORE_SIZE-2
bcc :tsloop
; Return
rts
; Clear the SHR screen and then infill the defined field
@ -725,7 +757,7 @@ snippets lup 82
bcs :byte ; if C = 0, just push the data and return
pha ; 1 byte
jmp loop+3+{3*]index}-base ; 3 bytes : use relative branch for convenience
jmp loop+3+{3*]index}-base ; 3 bytes
:byte jmp jmp_rtn-base ; 3 bytes
]index equ ]index+1
--^

View File

@ -505,9 +505,10 @@ _CopyBG1Tile
; 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+TS_BASE_ADDR : Copy of BTableAddrLow
; TileStore+TS_SCREEN_ADDR : Address ont he physical screen corresponding to this tile (for direct rendering)
TileStore ENT
ds TILE_STORE_SIZE*10
ds TILE_STORE_SIZE*11
; A list of dirty tiles that need to be updated in a given frame
DirtyTileCount ds 2