Merge branch 'dirty-tiles'

This commit is contained in:
Lucas Scharenbroich 2022-07-07 17:44:21 -05:00
commit 530cdbd07f
21 changed files with 985 additions and 803 deletions

View File

@ -3,15 +3,14 @@
REL REL
DSK MAINSEG DSK MAINSEG
use Load.Macs.s use Locator.Macs
use Locator.Macs.s use Load.Macs
use Misc.Macs.s use Mem.Macs
use EDS.GSOS.MACS.s use Misc.Macs
use Tool222.Macs.s use Tool222.Macs.s
use Util.Macs.s use Util.Macs
use CORE.MACS.s use EDS.GSOS.Macs
use ../../src/GTE.s use GTE.Macs
use ../../src/Defs.s
mx %00 mx %00
@ -25,20 +24,38 @@ RIGHT_ARROW equ $15
UP_ARROW equ $0B UP_ARROW equ $0B
DOWN_ARROW equ $0A DOWN_ARROW equ $0A
StartX equ 4
StartY equ 6
TSet EXT
; Typical init ; Typical init
phk phk
plb plb
jsl EngineStartUp stz StartX
stz StartY
lda #^MyPalette ; Fill Palette #0 with our colors
ldx #MyPalette
ldy #0
jsl SetPalette
ldx #256 ; 32 x 22 playfield (704 tiles, $580 tiles) sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program
ldy #176 _MTStartUp ; GTE requires the miscellaneous toolset to be running
jsl SetScreenMode
jsr GTEStartUp ; Load and install the GTE User Tool
; Load a tileset
pea #^TSet
pea #TSet
_GTELoadTileSet
pea $0000
pea #^MyPalette
pea #MyPalette
_GTESetPalette
pea #256
pea #176
_GTESetScreenMode
; Set up our level data ; Set up our level data
jsr BG0SetUp jsr BG0SetUp
@ -51,90 +68,117 @@ DOWN_ARROW equ $0A
stz MapScreenY stz MapScreenY
; Add a sprite to the engine and save its sprite ; Add a sprite to the engine and save its sprite
SPRITE_ID equ {SPRITE_16X16+1} HERO_DOWN_ID equ {SPRITE_16X16+1}
OKTOROK equ {SPRITE_16X16+79} HERO_DOWN_VBUFF equ VBUFF_SPRITE_START+0*VBUFF_SPRITE_STEP
HERO_SIDE_ID equ {SPRITE_16X16+5}
HERO_SIDE_VBUFF equ VBUFF_SPRITE_START+1*VBUFF_SPRITE_STEP
HERO_UP_ID equ {SPRITE_16X16+9}
HERO_UP_VBUFF equ VBUFF_SPRITE_START+2*VBUFF_SPRITE_STEP
lda PlayerX HERO_SLOT equ 0
xba OKTOROK_ID equ {SPRITE_16X16+79}
ora PlayerY OKTOROK_VBUFF equ VBUFF_SPRITE_START+3*VBUFF_SPRITE_STEP
tay ; (x, y) position OKTOROK_SLOT_1 equ 1
ldx #0 OKTOROK_SLOT_2 equ 2
lda #SPRITE_ID ; 16x16 sprite OKTOROK_SLOT_3 equ 3
jsl AddSprite OKTOROK_SLOT_4 equ 4
sta PlayerID
; Create the sprite stamps for this scene
pea HERO_DOWN_ID ; sprint id
pea HERO_DOWN_VBUFF ; vbuff address
_GTECreateSpriteStamp
pea HERO_SIDE_ID ; sprint id
pea HERO_SIDE_VBUFF ; vbuff address
_GTECreateSpriteStamp
pea HERO_UP_ID ; sprint id
pea HERO_UP_VBUFF ; vbuff address
_GTECreateSpriteStamp
pea OKTOROK_ID ; sprint id
pea OKTOROK_VBUFF ; vbuff address
_GTECreateSpriteStamp
pea HERO_DOWN_ID
lda PlayerX
pha
lda PlayerY
pha
pea HERO_SLOT
_GTEAddSprite
pea HERO_SLOT
pea $0000 ; with these flags (h/v flip)
pea HERO_DOWN_VBUFF ; and use this stamp
_GTEUpdateSprite
; Add 4 octoroks ; Add 4 octoroks
lda #OKTOROK pea OKTOROK_ID
ldx #1 lda OktorokX
ldy #{32*256}+48 pha
jsl AddSprite lda OktorokY
pha
pea OKTOROK_SLOT_1
_GTEAddSprite
lda #OKTOROK pea OKTOROK_SLOT_1
ldx #2 pea $0000 ; with these flags (h/v flip)
ldy #{32*256}+96 pea OKTOROK_VBUFF ; and use this stamp
jsl AddSprite _GTEUpdateSprite
lda #OKTOROK
ldx #3
ldy #{96*256}+56
jsl AddSprite
lda #OKTOROK
ldx #4
ldy #{96*256}+72
jsl AddSprite
; Draw the initial screen ; Draw the initial screen
lda #DIRTY_BIT_BG0_REFRESH ; Redraw all of the tiles on the next Render _GTERender
tsb DirtyBits
jsl Render
; Set up a very specific test. First, we draw a sprite into the sprite plane, and then ; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
; leave it alone. We are just testing the ability to merge sprite plane data into ; leave it alone. We are just testing the ability to merge sprite plane data into
; the play field tiles. ; the play field tiles.
EvtLoop EvtLoop
jsl ReadControl pha
_GTEReadControl
pla
; Check the buttons first ; Check the buttons first
pha pha
bit #$0100 bit #$0100
beq :no_sword beq :no_sword
:no_sword :no_sword
; Enable/disable v-sync ; Enable/disable v-sync
lda 1,s lda 1,s
bit #$0400 bit #PAD_KEY_DOWN
beq :no_key_down beq :no_key_down
and #$007F and #$007F
cmp #'v' cmp #'v'
bne :not_v bne :not_v
lda #$0001 lda #$0001
eor vsync eor vsync
sta vsync sta vsync
:not_v :not_v
:no_key_down :no_key_down
pla pla
and #$007F ; Ignore the buttons for now and #$007F ; Ignore the buttons for now
cmp #'q' cmp #'q'
bne :not_q bne :not_q
brl Exit brl Exit
:not_q :not_q
cmp #'d' cmp #'d'
bne :not_d bne :not_d
inc PlayerX inc PlayerX
lda PlayerX lda PlayerX
cmp #128-8 cmp #128-8
bcc *+5 bcc *+5
jsr TransitionRight jsr TransitionRight
lda PlayerID pea HERO_SLOT
ldx #SPRITE_16X16+5 pea $0000 ; no flags
jsl UpdateSprite pea HERO_SIDE_VBUFF ; and use this stamp
_GTEUpdateSprite
bra :do_render bra :do_render
:not_d :not_d
@ -145,9 +189,10 @@ EvtLoop
bpl *+5 bpl *+5
jsr TransitionLeft jsr TransitionLeft
lda PlayerID pea HERO_SLOT
ldx #SPRITE_16X16+SPRITE_HFLIP+5 pea SPRITE_HFLIP
jsl UpdateSprite pea HERO_SIDE_VBUFF
_GTEUpdateSprite
bra :do_render bra :do_render
:not_a :not_a
@ -155,79 +200,84 @@ EvtLoop
cmp #'s' cmp #'s'
bne :not_s bne :not_s
inc PlayerY inc PlayerY
lda PlayerID
ldx #SPRITE_16X16+1 pea HERO_SLOT
jsl UpdateSprite pea $0000
pea HERO_DOWN_VBUFF
_GTEUpdateSprite
bra :do_render bra :do_render
:not_s :not_s
cmp #'w' cmp #'w'
bne :not_w bne :not_w
dec PlayerY dec PlayerY
lda PlayerID pea HERO_SLOT
ldx #SPRITE_16X16+9 pea $0000
jsl UpdateSprite pea HERO_UP_VBUFF
_GTEUpdateSprite
bra :do_render bra :do_render
:not_w :not_w
:do_render :do_render
lda PlayerID pea HERO_SLOT
ldx PlayerX lda PlayerX
ldy PlayerY pha
jsl MoveSprite ; Move the sprite to the current position lda PlayerY
pha
_GTEMoveSprite
; Based on the frame count, move an oktorok ; Based on the frame count, move an oktorok
jsl GetVBLTicks
pha
and #$0003
asl
tax
pla ; jsr _GetVBLTicks
and #$007C ; pha
lsr ; and #$0003
tay ; asl
; tax
lda OktorokX,x ; pla
clc ; and #$007C
adc OktorokDelta,y ; lsr
; tay
phx ; lda OktorokX,x
; clc
; adc OktorokDelta,y
ldy OktorokY,x ; phx
tax
pla ; ldy OktorokY,x
inc ; tax
inc ; pla
jsl MoveSprite ; inc
; inc
; jsl MoveSprite
; Let's see what it looks like! ; Let's see what it looks like!
lda vsync lda vsync
beq :no_vsync beq :no_vsync
:vsyncloop jsl GetVerticalCounter ; 8-bit value :vsyncloop jsr _GetVBL ; 8-bit value
cmp ScreenY0 cmp #12
bcc :vsyncloop bcc :vsyncloop
sec cmp #16
sbc ScreenY0 bcs :vsyncloop ; Wait until we're within the top 4 scanlines
cmp #4
bcs :vsyncloop ; Wait until we're within the top 8 scanlines
lda #1 lda #1
jsl SetBorderColor jsr _SetBorderColor
:no_vsync :no_vsync
jsl RenderDirty _GTERenderDirty
lda vsync lda vsync
beq :no_vsync2 beq :no_vsync2
lda #0 lda #0
jsl SetBorderColor jsr _SetBorderColor
:no_vsync2 :no_vsync2
brl EvtLoop brl EvtLoop
; Exit code ; Exit code
Exit Exit
jsl EngineShutDown _GTEShutDown
_QuitGS qtRec _QuitGS qtRec
@ -249,7 +299,10 @@ TransitionRight
bcs :out bcs :out
clc clc
adc #4 adc #4
jsl SetBG0XPos sta StartX
pha
pei StartY
_GTESetBG0Origin
lda PlayerX lda PlayerX
sec sec
@ -257,18 +310,18 @@ TransitionRight
bmi :nosprite bmi :nosprite
sta PlayerX sta PlayerX
lda PlayerID pea HERO_SLOT
ldx PlayerX lda PlayerX
ldy PlayerY pha
jsl MoveSprite lda PlayerY
pha
_GTEMoveSprite
:nosprite :nosprite
jsl Render ; Do full renders since the playfield is scrolling _GTERender ; Do full renders since the playfield is scrolling
bra :loop bra :loop
:out :out
lda #0 ; Move the player back to the left edge
sta PlayerX
inc MapScreenX ; Move the index to the next screen inc MapScreenX ; Move the index to the next screen
:done :done
rts rts
@ -289,7 +342,10 @@ TransitionLeft
beq :out beq :out
sec sec
sbc #4 sbc #4
jsl SetBG0XPos sta StartX
pha
pei StartY
_GTESetBG0Origin
lda PlayerX lda PlayerX
clc clc
@ -298,22 +354,24 @@ TransitionLeft
bcs :nosprite bcs :nosprite
sta PlayerX sta PlayerX
lda PlayerID pea HERO_SLOT
ldx PlayerX lda PlayerX
ldy PlayerY pha
jsl MoveSprite lda PlayerY
pha
_GTEMoveSprite
:nosprite :nosprite
jsl Render _GTERender
bra :loop bra :loop
:out :out
; lda #128-8 ; Move the player back to the right edge
; sta PlayerX
dec MapScreenX ; Move the index to the next screen dec MapScreenX ; Move the index to the next screen
:done :done
rts rts
ToolPath str '1/Tool160'
MyUserId ds 2
; Color palette ; Color palette
;MyPalette dw $068F,$0EDA,$0000,$0000,$0BF1,$00A0,$0EEE,$0456,$0FA4,$0F59,$0E30,$01CE,$02E3,$0870,$0F93,$0FD7
MyPalette dw $0FDA,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$023E,$01CE,$02E3,$0870,$0F93,$0FD7 MyPalette dw $0FDA,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$023E,$01CE,$02E3,$0870,$0F93,$0FD7
MapScreenX ds 2 MapScreenX ds 2
@ -337,6 +395,84 @@ qtRec adrl $0000
vsync dw $8000 vsync dw $8000
PUT gen/App.TileMapBG0.s _GetVBLTicks
PushLong #0
_GetTick
pla
plx
rts
ANGLEBNK ENT ; Load the GTE User Tool and install it
GTEStartUp
pea $0000
_LoaderStatus
pla
pea $0000
pea $0000
pea $0000
pea $0000
pea $0000 ; result space
lda MyUserId
pha
pea #^ToolPath
pea #ToolPath
pea $0001 ; do not load into special memory
_InitialLoad
bcc :ok1
brk $01
:ok1
ply
pla ; Address of the loaded tool
plx
ply
ply
pea $8000 ; User toolset
pea $00A0 ; Set the tool set number
phx
pha ; Address of function pointer table
_SetTSPtr
bcc :ok2
brk $02
:ok2
clc ; Give GTE a page of direct page memory
tdc
adc #$0100
pha
pea #0 ; Fast Mode
lda MyUserId ; Pass the userId for memory allocation
pha
_GTEStartUp
bcc :ok3
brk $03
:ok3
rts
BORDER_REG equ $E0C034 ; 0-3 = border, 4-7 Text color
VBL_VERT_REG equ $E0C02E
VBL_HORZ_REG equ $E0C02F
_GetVBL
sep #$20
ldal VBL_HORZ_REG
asl
ldal VBL_VERT_REG
rol ; put V5 into carry bit, if needed. See TN #39 for details.
rep #$20
and #$00FF
rts
_SetBorderColor sep #$20 ; ACC = $X_Y, REG = $W_Z
eorl BORDER_REG ; ACC = $(X^Y)_(Y^Z)
and #$0F ; ACC = $0_(Y^Z)
eorl BORDER_REG ; ACC = $W_(Y^Z^Z) = $W_Y
stal BORDER_REG
rep #$20
rts
PUT gen/App.TileMapBG0.s

View File

@ -7,37 +7,9 @@
; Segment #1 -- Main execution block ; Segment #1 -- Main execution block
ASM App.Main.s ASM App.Main.s
DS 0 ; Number of bytes of 0's to add at the end of the Segment
KND #$1100 ; Type and Attributes ($11=Static+Bank Relative,$00=Code)
ALI None ; Boundary Alignment (None)
SNA Main SNA Main
; Segment #2 -- Core GTE Code ; Segment #2 -- Tileset
ASM ..\..\src\Core.s
SNA Core
; Segment #3 -- 64KB Tile Memory
ASM gen\App.TileSet.s ASM gen\App.TileSet.s
DS 0 SNA TSET
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
SNA Tiles
; Segment #4 -- 64KB Sprite Plane Data
ASM SprData.s
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
SNA SPRDATA
; Segment #5 -- 64KB Sprite Mask Data
ASM SprMask.s
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
SNA SPRMASK
; Segment #6 -- 64KB Tile Store
ASM TileStore.s
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
SNA TSTORE

View File

@ -14,5 +14,6 @@ REM Cadius does not overwrite files, so clear the root folder first
REM Now copy files and folders as needed REM Now copy files and folders as needed
%CADIUS% ADDFILE %IMAGE% %FOLDER% .\GTEZelda %CADIUS% ADDFILE %IMAGE% %FOLDER% .\GTEZelda
%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\src\Tool160
REM Copy in the image assets REM Copy in the image assets

View File

@ -5,14 +5,19 @@
BG0SetUp BG0SetUp
lda #64 pea #64
sta TileMapWidth pea #44
lda #44 pea #^Tile_Layer_1
sta TileMapHeight pea #Tile_Layer_1
lda #Tile_Layer_1 _GTESetBG0TileMapInfo
sta TileMapPtr ; lda #64
lda #^Tile_Layer_1 ; sta TileMapWidth
sta TileMapPtr+2 ; lda #44
; sta TileMapHeight
; lda #Tile_Layer_1
; sta TileMapPtr
; lda #^Tile_Layer_1
; sta TileMapPtr+2
rts rts
Tile_Layer_1 Tile_Layer_1

View File

@ -2,7 +2,7 @@
; Palette: ; Palette:
; $0F0F,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$023E ; $0F0F,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$023E
; Converting to BG0 format... ; Converting to BG0 format...
tiledata ENT TSet ENT
; Reserved space (tile 0 is special... ; Reserved space (tile 0 is special...
ds 128 ds 128

View File

@ -15,9 +15,11 @@
"scripts": { "scripts": {
"test": "npm run build && build-image.bat %npm_package_config_cadius% && %npm_package_config_gsport%", "test": "npm run build && build-image.bat %npm_package_config_cadius% && %npm_package_config_gsport%",
"debug": "%npm_package_config_crossrunner% GTEZelda -Source GTEZelda_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer", "debug": "%npm_package_config_crossrunner% GTEZelda -Source GTEZelda_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
"build": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s", "build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
"build:map": "node %npm_package_config_tiled2iigs% ./assets/overworld.json --no-gen-tiles --output-dir ./gen", "build:map": "node %npm_package_config_tiled2iigs% ./assets/overworld.json --no-gen-tiles --output-dir ./gen",
"build:tiles": "node %npm_package_config_png2iigs% ./assets/sprites-256x128.png --max-tiles 256 --as-tile-data --transparent-color FF00FF > ./gen/App.TileSet.s" "build:tiles": "node %npm_package_config_png2iigs% ./assets/sprites-256x128.png --max-tiles 256 --as-tile-data --transparent-color FF00FF > ./gen/App.TileSet.s",
"build": "npm run build:tool && npm run build:sys16",
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../src/Master.s"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -111,6 +111,9 @@ _GTEFillTileStore MAC
_GTERefresh MAC _GTERefresh MAC
UserTool $2600+GTEToolNum UserTool $2600+GTEToolNum
<<< <<<
_GTERenderDirty MAC
UserTool $2700+GTEToolNum
<<<
; EngineMode definitions ; EngineMode definitions
; Script definition ; Script definition
@ -123,9 +126,9 @@ SET_DYN_TILE equ $0006
CALLBACK equ $0010 CALLBACK equ $0010
; ReadControl return value bits ; ReadControl return value bits
PAD_BUTTON_B equ $01 PAD_BUTTON_B equ $0100
PAD_BUTTON_A equ $02 PAD_BUTTON_A equ $0200
PAD_KEY_DOWN equ $04 PAD_KEY_DOWN equ $0400
ENGINE_MODE_TWO_LAYER equ $0001 ENGINE_MODE_TWO_LAYER equ $0001
ENGINE_MODE_DYN_TILES equ $0002 ENGINE_MODE_DYN_TILES equ $0002
ENGINE_MODE_BNK0_BUFF equ $0004 ENGINE_MODE_BNK0_BUFF equ $0004

View File

@ -190,7 +190,7 @@ EngineReset
; stz EngineMode ; stz EngineMode
stz DirtyBits stz DirtyBits
stz LastRender stz LastRender ; Initialize as is a full render was performed
stz LastPatchOffset stz LastPatchOffset
stz BG1StartX stz BG1StartX
stz BG1StartXMod164 stz BG1StartXMod164
@ -271,7 +271,7 @@ _ReadControl pea $0000 ; low byte = key code, high byte
and #$80 and #$80
beq :BNotDown beq :BNotDown
lda #PAD_BUTTON_B lda #>PAD_BUTTON_B
ora 2,s ora 2,s
sta 2,s sta 2,s
@ -280,7 +280,7 @@ _ReadControl pea $0000 ; low byte = key code, high byte
and #$80 and #$80
beq :ANotDown beq :ANotDown
lda #PAD_BUTTON_A lda #>PAD_BUTTON_A
ora 2,s ora 2,s
sta 2,s sta 2,s
@ -296,7 +296,7 @@ _ReadControl pea $0000 ; low byte = key code, high byte
beq :KbdDown beq :KbdDown
sta LastKey sta LastKey
lda #PAD_KEY_DOWN ; set the keydown flag lda #>PAD_KEY_DOWN ; set the keydown flag
ora 2,s ora 2,s
sta 2,s sta 2,s
bra :KbdDown bra :KbdDown

View File

@ -19,6 +19,7 @@ SHADOW_SCREEN_PALETTES equ $019E00
SHR_SCREEN equ $E12000 SHR_SCREEN equ $E12000
SHR_SCB equ $E19D00 SHR_SCB equ $E19D00
SHR_PALETTES equ $E19E00 SHR_PALETTES equ $E19E00
SHR_LINE_WIDTH equ 160
; Direct page locations used by the engine ; Direct page locations used by the engine
ScreenHeight equ 0 ; Height of the playfield in scan lines ScreenHeight equ 0 ; Height of the playfield in scan lines
@ -152,9 +153,10 @@ DP2_DIRTY_TILE_COUNT equ 160 ; Local copy of dirty tile count to avo
DP2_DIRTY_TILE_CALLBACK equ 162 DP2_DIRTY_TILE_CALLBACK equ 162
; Some pre-defined bank values ; Some pre-defined bank values
DP2_TILEDATA_AND_TILESTORE_BANKS equ 164 DP2_TILEDATA_AND_TILESTORE_BANKS equ 164
DP2_SPRITEDATA_AND_TILESTORE_BANKS equ 166 DP2_SPRITEDATA_AND_TILESTORE_BANKS equ 166
DP2_TILEDATA_AND_SPRITEDATA_BANKS equ 168 DP2_TILEDATA_AND_SPRITEDATA_BANKS equ 168
DP2_BANK01_AND_TILESTORE_BANKS equ 170
SPRITE_VBUFF_PTR equ 224 ; 32 bytes of adjusted pointers to VBuffArray addresses SPRITE_VBUFF_PTR equ 224 ; 32 bytes of adjusted pointers to VBuffArray addresses
; End direct page values ; End direct page values

View File

@ -1,73 +0,0 @@
; Collection of the EXTernal labels exported by GTE. This is the closest thing
; we have to an API definition.
EngineStartUp EXT
EngineShutDown EXT
SetScreenMode EXT
ReadControl EXT
; Low-Level Functions
SetPalette EXT
GetVBLTicks EXT
GetVerticalCounter EXT
SetBorderColor EXT
; Tilemap functions
SetBG0XPos EXT
SetBG0YPos EXT
SetBG1XPos EXT
SetBG1YPos EXT
CopyBG0Tile EXT
CopyBG1Tile EXT
; SCB/Palette binding (high bit of array point indicates whether to bind to BG0 Y position (0)
; or BG1 Y position (1).
; SetSCBArray EXT
BltSCB EXT
; Rotation
ApplyBG1XPosAngle EXT
ApplyBG1YPosAngle EXT
CopyPicToField EXT
CopyBinToField EXT
CopyPicToBG1 EXT
CopyBinToBG1 EXT
AddTimer EXT
RemoveTimer EXT
DoTimers EXT
StartScript EXT
StopScript EXT
; Sprite functions
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
GetTileAddr EXT
PushDirtyTile EXT ; A = address from GetTileStoreOffset, marks as dirty (will not mark the same tile more than once)
PopDirtyTile EXT ; No args, returns Y with tile store offset of the dirty tile
ApplyTiles EXT ; Drain the dirty tile queue and call RenderTile on each
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
AllocBank EXT
; Data references
;
; Super Hires line address lookup table for convenience
ScreenAddr EXT
OneSecondCounter EXT
BlitBuff EXT

View File

@ -174,9 +174,6 @@ _ShadowOff
rep #$20 rep #$20
rts rts
GetVerticalCounter ENT
jsr _GetVBL
rtl
_GetVBL _GetVBL
sep #$20 sep #$20
ldal VBL_HORZ_REG ldal VBL_HORZ_REG

View File

@ -20,7 +20,13 @@
; It's important to do _ApplyBG0YPos first because it calculates the value of StartY % 208 which is ; It's important to do _ApplyBG0YPos first because it calculates the value of StartY % 208 which is
; used in all of the other loops ; used in all of the other loops
_Render _Render
jsr _DoTimers ; Run any pending timer tasks lda LastRender ; Check to see what kind of rendering was done on the last frame. If
beq :no_change ; it was not this renderer,
jsr _ResetToNormalTileProcs
jsr _Refresh
:no_change
jsr _DoTimers ; Run any pending timer tasks
stz SpriteRemovedFlag ; If we remove a sprite, then we need to flag a rebuild for the next frame stz SpriteRemovedFlag ; If we remove a sprite, then we need to flag a rebuild for the next frame
@ -37,7 +43,7 @@ _Render
jsr _UpdateBG0TileMap ; and the tile maps. These subroutines build up a list of tiles 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 _UpdateBG1TileMap ; that need to be updated in the code field
jsr _ApplyTilesFast ; This function actually draws the new tiles into the code field jsr _ApplyTiles ; This function actually draws the new tiles into the code field
jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode 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
@ -129,10 +135,11 @@ _DoOverlay
:disp jsl $000000 :disp jsl $000000
rts rts
; The _ApplyTilesFast is the same as _ApplyTiles, but we use the _RenderTileFast subroutine ; Run through all of the tiles on the DirtyTile list and render them
_ApplyTilesFast _ApplyTiles
ldx DirtyTileCount ldx DirtyTileCount
phd ; sve the current direct page
tdc tdc
clc clc
adc #$100 ; move to the next page adc #$100 ; move to the next page
@ -141,48 +148,10 @@ _ApplyTilesFast
stx DP2_DIRTY_TILE_COUNT ; Cache the dirty tile count stx DP2_DIRTY_TILE_COUNT ; Cache the dirty tile count
jsr _PopDirtyTilesFast jsr _PopDirtyTilesFast
tdc ; Move back to the original direct page pld ; Move back to the original direct page
sec
sbc #$100
tcd
stz DirtyTileCount ; Reset the dirty tile count stz DirtyTileCount ; Reset the dirty tile count
rts rts
; The _ApplyTiles function is responsible for rendering all of the dirty tiles into the code
; field. In this function we switch to the second direct page which holds the temporary
; working buffers for tile rendering.
;
_ApplyTiles
tdc
clc
adc #$100 ; move to the next page
tcd
bra :begin
:loop
; Retrieve the offset of the next dirty Tile Store items in the X-register
jsr _PopDirtyTile2
; Call the generic dispatch with the Tile Store record pointer at by the X-register.
phb
; jsr _RenderTile2
plb
; Loop again until the list of dirty tiles is empty
:begin ldy DirtyTileCount
bne :loop
tdc ; Move back to the original direct page
sec
sbc #$100
tcd
rts
; This is a specialized render function that only updates the dirty tiles *and* draws them ; This is a specialized render function that only updates the dirty tiles *and* draws them
; directly onto the SHR graphics buffer. The playfield is not used at all. In some way, this ; 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 ; ignores almost all of the capabilities of GTE, but it does provide a convenient way to use
@ -192,20 +161,26 @@ _ApplyTiles
; In this renderer, we assume that there is no scrolling, so no need to update any information about ; In this renderer, we assume that there is no scrolling, so no need to update any information about
; the BG0/BG1 positions ; the BG0/BG1 positions
_RenderDirty _RenderDirty
lda LastRender ; If the full renderer was last called, we assume that lda LastRender ; If the full renderer was last called, we assume that
bne :norecalc ; the scroll positions have likely changed, so recalculate bne :norecalc ; the scroll positions have likely changed, so recalculate
jsr _RecalcTileScreenAddrs ; them to make sure sprites draw at the correct screen address jsr _RecalcTileScreenAddrs ; them to make sure sprites draw at the correct screen address
jsr _ResetToDirtyTileProcs ; Switch the tile procs to the dirty tile rendering functions
; jsr _ClearSpritesFromCodeField ; Restore the tiles to their non-sprite versions ; jsr _ClearSpritesFromCodeField ; Restore the tiles to their non-sprite versions
:norecalc :norecalc
jsr _RenderSprites
; jsr _RenderSprites jsr _ApplyDirtyTiles
; jsr _ApplyDirtyTiles
lda #1 lda #1
sta LastRender sta LastRender
rts rts
_ApplyDirtyTiles _ApplyDirtyTiles
phd ; save the current direct page
tdc
clc
adc #$100 ; move to the next page
tcd
bra :begin bra :begin
:loop :loop
@ -215,341 +190,14 @@ _ApplyDirtyTiles
; Call the generic dispatch with the Tile Store record pointer at by the Y-register. ; Call the generic dispatch with the Tile Store record pointer at by the Y-register.
phb
jsr _RenderDirtyTile jsr _RenderDirtyTile
plb
; Loop again until the list of dirty tiles is empty ; Loop again until the list of dirty tiles is empty
:begin ldy DirtyTileCount :begin ldy DirtyTileCount
bne :loop bne :loop
pld ; Move back to the original direct page
stz DirtyTileCount ; Reset the dirty tile count
rts rts
; Only render solid tiles and sprites
_RenderDirtyTile
lda TileStore+TS_SPRITE_FLAG,y
beq NoSpritesDirty ; This is faster if there are no sprites
; TODO: handle sprite drawing
; The rest of this function handles that non-sprite blit, which is super fast since it blits directly from the
; tile data store to the graphics screen with no masking. The only extra work is selecting a blit function
; based on the tile flip flags.
;
; B is set to Bank 01
; Y is set to the top-left address of the tile in SHR screen
; A is set to the address of the tile data
NoSpritesDirty
; lda TileStore+TS_DIRTY_TILE_DISP,y
; stal :nsd+1
ldx TileStore+TS_SCREEN_ADDR,y ; Get the on-screen address of this tile
lda TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
plb ; set the code field bank
:nsd jmp $0000
; Use some temporary space for the spriteIdx array (maximum of 4 entries)
stkSave equ tmp9
screenAddr equ tmp10
tileAddr equ tmp11
spriteIdx equ tmp12
; If there are two or more sprites at a tile, we can still be fast, but need to do extra work because
; the VBUFF values need to be read from the direct page. Thus, the direct page cannot be mapped onto
; the graphics screen. We use the stack instead, but have to do extra work to save and restore the
; stack value.
FourSpritesDirty
ThreeSpritesDirty
TwoSpritesDirty
sta tileAddr
stx screenAddr
plb
tsc
sta stkSave ; Save the stack on the direct page
sei
clc
ldy tileAddr
lda screenAddr ; Saved in direct page locations
tcs
_R0W1
lda tiledata+{0*TILE_DATA_SPAN},y
ldx spriteIdx+2
andl spritemask+{0*SPRITE_PLANE_SPAN},x
oral spritedata+{0*SPRITE_PLANE_SPAN},x
ldx spriteIdx
andl spritemask+{0*SPRITE_PLANE_SPAN},x
oral spritedata+{0*SPRITE_PLANE_SPAN},x
sta $00,s
lda tiledata+{0*TILE_DATA_SPAN}+2,y
ldx spriteIdx+2
andl spritemask+{0*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{0*SPRITE_PLANE_SPAN}+2,x
ldx spriteIdx
andl spritemask+{0*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{0*SPRITE_PLANE_SPAN}+2,x
sta $02,s
lda tiledata+{1*TILE_DATA_SPAN},y
ldx spriteIdx+2
andl spritemask+{1*SPRITE_PLANE_SPAN},x
oral spritedata+{1*SPRITE_PLANE_SPAN},x
ldx spriteIdx
andl spritemask+{1*SPRITE_PLANE_SPAN},x
oral spritedata+{1*SPRITE_PLANE_SPAN},x
sta $A0,s
lda tiledata+{1*TILE_DATA_SPAN}+2,y
ldx spriteIdx+2
andl spritemask+{1*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{1*SPRITE_PLANE_SPAN}+2,x
ldx spriteIdx
andl spritemask+{1*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{1*SPRITE_PLANE_SPAN}+2,x
sta $A2,s
tsc
adc #320
tcs
lda tiledata+{2*TILE_DATA_SPAN},y
ldx spriteIdx+2
andl spritemask+{2*SPRITE_PLANE_SPAN},x
oral spritedata+{2*SPRITE_PLANE_SPAN},x
ldx spriteIdx
andl spritemask+{2*SPRITE_PLANE_SPAN},x
oral spritedata+{2*SPRITE_PLANE_SPAN},x
sta $00,s
lda tiledata+{2*TILE_DATA_SPAN}+2,y
ldx spriteIdx+2
andl spritemask+{2*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{2*SPRITE_PLANE_SPAN}+2,x
ldx spriteIdx
andl spritemask+{2*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{2*SPRITE_PLANE_SPAN}+2,x
sta $02,s
lda tiledata+{3*TILE_DATA_SPAN},y
ldx spriteIdx+2
andl spritemask+{3*SPRITE_PLANE_SPAN},x
oral spritedata+{3*SPRITE_PLANE_SPAN},x
ldx spriteIdx
andl spritemask+{3*SPRITE_PLANE_SPAN},x
oral spritedata+{3*SPRITE_PLANE_SPAN},x
sta $A0,s
lda tiledata+{3*TILE_DATA_SPAN}+2,y
ldx spriteIdx+2
andl spritemask+{3*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{3*SPRITE_PLANE_SPAN}+2,x
ldx spriteIdx
andl spritemask+{3*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{3*SPRITE_PLANE_SPAN}+2,x
sta $A2,s
tsc
adc #320
tcs
lda tiledata+{4*TILE_DATA_SPAN},y
ldx spriteIdx+2
andl spritemask+{4*SPRITE_PLANE_SPAN},x
oral spritedata+{4*SPRITE_PLANE_SPAN},x
ldx spriteIdx
andl spritemask+{4*SPRITE_PLANE_SPAN},x
oral spritedata+{4*SPRITE_PLANE_SPAN},x
sta $00,s
lda tiledata+{4*TILE_DATA_SPAN}+2,y
ldx spriteIdx+2
andl spritemask+{4*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{4*SPRITE_PLANE_SPAN}+2,x
ldx spriteIdx
andl spritemask+{4*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{4*SPRITE_PLANE_SPAN}+2,x
sta $02,s
lda tiledata+{5*TILE_DATA_SPAN},y
ldx spriteIdx+2
andl spritemask+{5*SPRITE_PLANE_SPAN},x
oral spritedata+{5*SPRITE_PLANE_SPAN},x
ldx spriteIdx
andl spritemask+{5*SPRITE_PLANE_SPAN},x
oral spritedata+{5*SPRITE_PLANE_SPAN},x
sta $A0,s
lda tiledata+{5*TILE_DATA_SPAN}+2,y
ldx spriteIdx+2
andl spritemask+{5*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{5*SPRITE_PLANE_SPAN}+2,x
ldx spriteIdx
andl spritemask+{5*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{5*SPRITE_PLANE_SPAN}+2,x
sta $A2,s
tsc
adc #320
tcs
lda tiledata+{6*TILE_DATA_SPAN},y
ldx spriteIdx+2
andl spritemask+{6*SPRITE_PLANE_SPAN},x
oral spritedata+{6*SPRITE_PLANE_SPAN},x
ldx spriteIdx
andl spritemask+{6*SPRITE_PLANE_SPAN},x
oral spritedata+{6*SPRITE_PLANE_SPAN},x
sta $00,s
lda tiledata+{6*TILE_DATA_SPAN}+2,y
ldx spriteIdx+2
andl spritemask+{6*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{6*SPRITE_PLANE_SPAN}+2,x
ldx spriteIdx
andl spritemask+{6*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{6*SPRITE_PLANE_SPAN}+2,x
sta $02,s
lda tiledata+{7*TILE_DATA_SPAN},y
ldx spriteIdx+2
andl spritemask+{7*SPRITE_PLANE_SPAN},x
oral spritedata+{7*SPRITE_PLANE_SPAN},x
ldx spriteIdx
andl spritemask+{7*SPRITE_PLANE_SPAN},x
oral spritedata+{7*SPRITE_PLANE_SPAN},x
sta $A0,s
lda tiledata+{7*TILE_DATA_SPAN}+2,y
ldx spriteIdx+2
andl spritemask+{7*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{7*SPRITE_PLANE_SPAN}+2,x
ldx spriteIdx
andl spritemask+{7*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{7*SPRITE_PLANE_SPAN}+2,x
sta $A2,s
_R0W0
lda stkSave
tcs
cli
rts
; There is only one sprite at this tile, so do a fast blit that directly combines a tile with a single
; sprite and renders directly to the screen
;
; NOTE: Expect X-register to already have been set to the correct VBUFF address
OneSpriteDirty
ldy tileAddr ; load the address of this tile's data
lda screenAddr ; Get the on-screen address of this tile
plb
phd
sei
clc
tcd
_R0W1
lda tiledata+{0*TILE_DATA_SPAN},y
andl spritemask+{0*SPRITE_PLANE_SPAN},x
oral spritedata+{0*SPRITE_PLANE_SPAN},x
sta $00
lda tiledata+{0*TILE_DATA_SPAN}+2,y
andl spritemask+{0*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{0*SPRITE_PLANE_SPAN}+2,x
sta $02
lda tiledata+{1*TILE_DATA_SPAN},y
andl spritemask+{1*SPRITE_PLANE_SPAN},x
oral spritedata+{1*SPRITE_PLANE_SPAN},x
sta $A0
lda tiledata+{1*TILE_DATA_SPAN}+2,y
andl spritemask+{1*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{1*SPRITE_PLANE_SPAN}+2,x
sta $A2
tdc
adc #320
tcd
lda tiledata+{2*TILE_DATA_SPAN},y
andl spritemask+{2*SPRITE_PLANE_SPAN},x
oral spritedata+{2*SPRITE_PLANE_SPAN},x
sta $00
lda tiledata+{2*TILE_DATA_SPAN}+2,y
andl spritemask+{2*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{2*SPRITE_PLANE_SPAN}+2,x
sta $02
lda tiledata+{3*TILE_DATA_SPAN},y
andl spritemask+{3*SPRITE_PLANE_SPAN},x
oral spritedata+{3*SPRITE_PLANE_SPAN},x
sta $A0
lda tiledata+{3*TILE_DATA_SPAN}+2,y
andl spritemask+{3*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{3*SPRITE_PLANE_SPAN}+2,x
sta $A2
tdc
adc #320
tcd
lda tiledata+{4*TILE_DATA_SPAN},y
andl spritemask+{4*SPRITE_PLANE_SPAN},x
oral spritedata+{4*SPRITE_PLANE_SPAN},x
sta $00
lda tiledata+{4*TILE_DATA_SPAN}+2,y
andl spritemask+{4*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{4*SPRITE_PLANE_SPAN}+2,x
sta $02
lda tiledata+{5*TILE_DATA_SPAN},y
andl spritemask+{5*SPRITE_PLANE_SPAN},x
oral spritedata+{5*SPRITE_PLANE_SPAN},x
sta $A0
lda tiledata+{5*TILE_DATA_SPAN}+2,y
andl spritemask+{5*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{5*SPRITE_PLANE_SPAN}+2,x
sta $A2
tdc
adc #320
tcd
lda tiledata+{6*TILE_DATA_SPAN},y
andl spritemask+{6*SPRITE_PLANE_SPAN},x
oral spritedata+{6*SPRITE_PLANE_SPAN},x
sta $00
lda tiledata+{6*TILE_DATA_SPAN}+2,y
andl spritemask+{6*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{6*SPRITE_PLANE_SPAN}+2,x
sta $02
lda tiledata+{7*TILE_DATA_SPAN},y
andl spritemask+{7*SPRITE_PLANE_SPAN},x
oral spritedata+{7*SPRITE_PLANE_SPAN},x
sta $A0
lda tiledata+{7*TILE_DATA_SPAN}+2,y
andl spritemask+{7*SPRITE_PLANE_SPAN}+2,x
oral spritedata+{7*SPRITE_PLANE_SPAN}+2,x
sta $A2
_R0W0
cli
pld
rts

View File

@ -223,32 +223,44 @@ _DoPhase1
trb SpriteMap trb SpriteMap
lda #SPRITE_STATUS_EMPTY ; Mark as empty so no error if we try to Add a sprite here again lda #SPRITE_STATUS_EMPTY ; Mark as empty so no error if we try to Add a sprite here again
sta _Sprites+SPRITE_STATUS,y sta _Sprites+SPRITE_STATUS,y
:hidden
jmp _ClearSpriteFromTileStore ; Clear the tile flags, add to the dirty tile list and done jmp _ClearSpriteFromTileStore ; Clear the tile flags, add to the dirty tile list and done
; Need to calculate new VBUFF information. The could be required for UPDATED, ADDED or MOVED
; sprites, so we do it unconditionally, but we do need to mark the current sprite for erasure if
; needed
:no_clear :no_clear
; If the sprite is hidden, then treat it like it's offscreen and clear it from the tile store. Because
; the hidden flag must be changed via the UpdateSprite function, if it's toggled, the SPRITE_STATUS_UPDATED
; flag will be set, too.
bit #SPRITE_STATUS_HIDDEN
bne :hidden
; If the sprite is marked as ADDED, then it does not need to have its old tile locations cleared ; If the sprite is marked as ADDED, then it does not need to have its old tile locations cleared
bit #SPRITE_STATUS_ADDED bit #SPRITE_STATUS_ADDED
bne :no_move bne :added
; If the sprite was not ADDED and also not MOVED, then there is no reason to erase the old tiles ; If the sprite was not ADDED and also not MOVED, then there is no reason to erase the old tiles
; because they will be overwritten anyway. ; because they will be overwritten anyway.
bit #SPRITE_STATUS_MOVED bit #SPRITE_STATUS_MOVED
beq :no_move bne :moved
; Finally, see if it was updated. If not, return early
bit #SPRITE_STATUS_UPDATED
bne :updated
rts
:moved
phy phy
jsr _ClearSpriteFromTileStore jsr _ClearSpriteFromTileStore
ply ply
; Anything else (MOVED, UPDATED, ADDED) will need to have the VBUFF information updated and the ; Anything else (MOVED, UPDATED, ADDED) will need to have the VBUFF information updated and the
; current tiles marked for update ; current tiles marked for update
:no_move :added
:updated
jsr _CalcDirtySprite ; This function preserves Y jsr _CalcDirtySprite ; This function preserves Y
lda #SPRITE_STATUS_OCCUPIED ; Clear the dirty bits (ADDED, UPDATED, MOVED) lda #SPRITE_STATUS_OCCUPIED ; Clear the dirty bits (ADDED, UPDATED, MOVED)
@ -605,6 +617,9 @@ _CacheSpriteBanks
xba xba
ldx #$100 ldx #$100
sta DP2_TILEDATA_AND_TILESTORE_BANKS,x ; put a reversed copy in the second direct page sta DP2_TILEDATA_AND_TILESTORE_BANKS,x ; put a reversed copy in the second direct page
and #$FF00
ora #$0001
sta DP2_BANK01_AND_TILESTORE_BANKS,x ; put a value with bank 01 and the tile store
lda #>spritedata lda #>spritedata
and #$FF00 and #$FF00

View File

@ -129,7 +129,7 @@ _CalcDirtySprite
adc StartYMod208 adc StartYMod208
bpl :y_ok bpl :y_ok
clc clc
adc #208 ; Wrap the actual coordinat around adc #208 ; Wrap the actual coordinate around
:y_ok and #$FFF8 ; mask first to ensure LSR will clear the carry :y_ok and #$FFF8 ; mask first to ensure LSR will clear the carry
lsr lsr
lsr lsr
@ -218,10 +218,6 @@ tmp_out
mdsOut rts mdsOut rts
; NOTE: The VBuffArray table is set up so that each sprite's vbuff address is stored in a
; parallel structure to the Tile Store. This allows up to use the same TileStoreLookup
; offset to index into the array of 16 sprite VBUFF addresses that are bound to a given tile
_MarkDirtySpriteTiles _MarkDirtySpriteTiles
lda _SpriteBits,y lda _SpriteBits,y
sta SpriteBit sta SpriteBit

View File

@ -124,13 +124,6 @@ InitTiles
:out :out
; lda DirtyTileProcs ; Fill in with the first dispatch address
; stal TileStore+TS_DIRTY_TILE_DISP,x
;
; lda TileProcs ; Same for non-dirty, non-sprite base case
; stal TileStore+TS_BASE_TILE_DISP,x
; The next set of values are constants that are simply used as cached parameters to avoid needing to ; The next set of values are constants that are simply used as cached parameters to avoid needing to
; calculate any of these values during tile rendering ; calculate any of these values during tile rendering
@ -144,7 +137,6 @@ InitTiles
lda BRowTableLow,y lda BRowTableLow,y
sta :base sta :base
; sta TileStore+TS_BASE_ADDR,x ; May not be needed later if we can figure out the right constant...
lda :col ; Set the offset values based on the column lda :col ; Set the offset values based on the column
asl ; of this tile asl ; of this tile
@ -155,7 +147,6 @@ InitTiles
lda Col2CodeOffset+2,y lda Col2CodeOffset+2,y
clc clc
adc :base adc :base
; adc TileStore+TS_BASE_ADDR,x
sta TileStore+TS_CODE_ADDR_LOW,x ; Low word of the tile address in the code field sta TileStore+TS_CODE_ADDR_LOW,x ; Low word of the tile address in the code field
lda JTableOffset,y lda JTableOffset,y
@ -175,6 +166,148 @@ InitTiles
bpl :loop bpl :loop
rts rts
; Put everything on the dirty tile list
_Refresh
ldx #TILE_STORE_SIZE-2
:loop jsr _PushDirtyTileX
dex
dex
bpl :loop
rts
; Reset all of the tile proc values in the playfield.
_ResetToDirtyTileProcs
ldx #TILE_STORE_SIZE-2
:loop
lda TileStore+TS_TILE_ID,x
jsr _SetDirtyTileProcs
dex
dex
bpl :loop
rts
_ResetToNormalTileProcs
ldx #TILE_STORE_SIZE-2
:loop
lda TileStore+TS_TILE_ID,x
jsr _SetNormalTileProcs
dex
dex
bpl :loop
rts
; A = tileID
; X = tile store index
_SetDirtyTileProcs
jsr _CalcTileProcIndex
ldy #DirtyProcs
jmp _SetTileProcs
; A = tileID
; X = tile store index
_SetNormalTileProcs
pha ; extra space
pha ; save the tile ID
jsr _CalcTileProcIndex
sta 3,s ; save for later
lda EngineMode
bit #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER
beq :setTileFast
bit #ENGINE_MODE_TWO_LAYER
beq :setTileDyn
pla ; restore newTileID
bit #TILE_DYN_BIT
beq :pickTwoLyrProc
ldy #TwoLyrDynProcs
brl :pickDynProc
:pickTwoLyrProc ldy #TwoLyrProcs
pla ; pull of the proc index
jmp _SetTileProcs
; Specialized check for when the engine is in "Fast" mode. If is a simple decision tree based on whether
; the tile priority bit is set, and whether this is the special tile 0 or not.
:setTileFast
pla ; Throw away tile ID copy
ldy #FastProcs
pla
jmp _SetTileProcs
; Specialized check for when the engine has enabled dynamic tiles. In this case we are no longer
; guaranteed that the opcodes in a tile are PEA instructions.
:setTileDyn
pla ; get the cached tile ID
bit #TILE_DYN_BIT
beq :pickSlowProc ; If the Dynamic bit is not set, select a tile proc that sets opcodes
ldy #DynProcs ; use this table
:pickDynProc
and #TILE_PRIORITY_BIT
beq :pickZeroDynProc ; If the Priority bit is not set, pick the first entry
pla
lda #1 ; If the Priority bit is set, pick the other one
jmp _SetTileProcs
:pickZeroDynProc pla
lda #0
jmp _SetTileProcs
:pickSlowProc ldy #SlowProcs
pla
jmp _SetTileProcs
; Helper method to calculate the index into the tile proc table given a TileID
; Calculate the base tile proc selector from the tile Id
_CalcTileProcIndex
bit #TILE_PRIORITY_BIT ; 4 if !0, 0 otherwise
beq :low_priority
bit #TILE_ID_MASK ; 2 if !0, 0 otherwise
beq :is_zero_a
bit #TILE_VFLIP_BIT ; 1 if !0, 0 otherwise
beq :no_flip_a
lda #7
rts
:no_flip_a lda #6
rts
:is_zero_a bit #TILE_VFLIP_BIT
beq :no_flip_b
lda #5
rts
:no_flip_b lda #4
rts
:low_priority bit #TILE_ID_MASK ; 2 if !0, 0 otherwise
beq :is_zero_b
bit #TILE_VFLIP_BIT ; 1 if !0, 0 otherwise
beq :no_flip_c
lda #3
rts
:no_flip_c lda #2
rts
:is_zero_b bit #TILE_VFLIP_BIT
beq :no_flip_d
lda #1
rts
:no_flip_d lda #0
rts
; Set a tile value in the tile backing store. Mark dirty if the value changes ; Set a tile value in the tile backing store. Mark dirty if the value changes
; ;
; A = tile id ; A = tile id
@ -216,79 +349,10 @@ _SetTile
; functionality. Sometimes it is simple, but in cases of the sprites overlapping Dynamic Tiles and other cases ; functionality. Sometimes it is simple, but in cases of the sprites overlapping Dynamic Tiles and other cases
; it can be more involved. ; it can be more involved.
; Calculate the base tile proc selector from the tile Id ; Calculate the base tile proc selector from the tile Id (need X-register set to tile store index)
stz procIdx
lda #TILE_PRIORITY_BIT lda newTileId
bit newTileId jsr _SetNormalTileProcs
beq :low_priority
lda #4
sta procIdx
:low_priority
lda #TILE_ID_MASK
bit newTileId
beq :is_zero
lda #2
tsb procIdx
:is_zero
lda #TILE_VFLIP_BIT
bit newTileId
beq :no_vflip
lda #1
tsb procIdx
:no_vflip
; Now integrate with the engine mode indicator
lda EngineMode
bit #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER
beq :setTileFast
bit #ENGINE_MODE_TWO_LAYER
bne :not_dyn
brl :setTileDyn
:not_dyn
lda #TILE_DYN_BIT
bit newTileId
beq :pickTwoLyrProc
ldy #TwoLyrDynProcs
brl :pickDynProc
:pickTwoLyrProc ldy #TwoLyrProcs
lda procIdx
jsr _SetTileProcs
jmp _PushDirtyTileX
; Specialized check for when the engine is in "Fast" mode. If is a simple decision tree based on whether
; the tile priority bit is set, and whether this is the special tile 0 or not.
:setTileFast
ldy #FastProcs
lda procIdx
jsr _SetTileProcs
jmp _PushDirtyTileX
; Specialized check for when the engine has enabled dynamic tiles. In this case we are no longer
; guaranteed that the opcodes in a tile are PEA instructions.
:setTileDyn
lda #TILE_DYN_BIT
bit newTileId
beq :pickSlowProc ; If the Dynamic bit is not set, select a tile proc that sets opcodes
ldy #DynProcs ; use this table
:pickDynProc
lda newTileId ; Otherwise chose one of the two dynamic tuples
and #TILE_PRIORITY_BIT
beq *+5 ; If the Priority bit is not set, pick the first entry
lda #1 ; If the Priority bit is set, pick the other one
jsr _SetTileProcs
jmp _PushDirtyTileX
:pickSlowProc ldy #SlowProcs
lda procIdx
jsr _SetTileProcs
jmp _PushDirtyTileX jmp _PushDirtyTileX
; X = Tile Store offset ; X = Tile Store offset
@ -415,6 +479,17 @@ TwoLyrDynProcs
TwoLyrDynOver dw CopyDynamicTileTwoLyr,DynamicOverTwoLyr,OneSpriteDynamicOverTwoLyr TwoLyrDynOver dw CopyDynamicTileTwoLyr,DynamicOverTwoLyr,OneSpriteDynamicOverTwoLyr
TwoLyrDynUnder dw CopyDynamicTileTwoLyr,DynamicUnderTwoLyr,OneSpriteDynamicUnderTwoLyr TwoLyrDynUnder dw CopyDynamicTileTwoLyr,DynamicUnderTwoLyr,OneSpriteDynamicUnderTwoLyr
; "Dirty" procs that are for dirty tile direct rendering. No moving background.
DirtyProcs
DirtyOverZA dw ConstTile0Dirty,SpriteOver0Dirty,OneSpriteDirtyOver0
DirtyOverZV dw ConstTile0Dirty,SpriteOver0Dirty,OneSpriteDirtyOver0
DirtyOverNA dw CopyTileADirty,SpriteOverADirty,OneSpriteDirtyOverA
DirtyOverNV dw CopyTileVDirty,SpriteOverVDirty,OneSpriteDirtyOverV
DirtyUnderZA dw ConstTile0Dirty,SpriteUnder0Dirty,SpriteUnder0Dirty
DirtyUnderZV dw ConstTile0Dirty,SpriteUnder0Dirty,SpriteUnder0Dirty
DirtyUnderNA dw CopyTileADirty,SpriteUnderADirty,OneSpriteDirtyUnderA
DirtyUnderNV dw CopyTileVDirty,SpriteUnderVDirty,OneSpriteDirtyUnderV
; SetBG0XPos ; SetBG0XPos
; ;
; Set the virtual horizontal position of the primary background layer. In addition to ; Set the virtual horizontal position of the primary background layer. In addition to

View File

@ -90,6 +90,7 @@ _CallTable
adrl _TSGetTileDataAddr-1 adrl _TSGetTileDataAddr-1
adrl _TSFillTileStore-1 adrl _TSFillTileStore-1
adrl _TSRefresh-1 adrl _TSRefresh-1
adrl _TSRenderDirty-1
_CTEnd _CTEnd
_GTEAddSprite MAC _GTEAddSprite MAC
UserTool $1000+GTEToolNum UserTool $1000+GTEToolNum
@ -282,6 +283,13 @@ _TSRender
jsr _Render jsr _Render
_TSExit #0;#0 _TSExit #0;#0
; RenderDirty()
_TSRenderDirty
_TSEntry
jsr _RenderDirty
_TSExit #0;#0
; LoadTileSet(Pointer) ; LoadTileSet(Pointer)
_TSLoadTileSet _TSLoadTileSet
TSPtr equ FirstParam TSPtr equ FirstParam
@ -697,13 +705,7 @@ _TSFillTileStore
; _TSRefresh() ; _TSRefresh()
_TSRefresh _TSRefresh
_TSEntry _TSEntry
jsr _Refresh
ldx #TILE_STORE_SIZE-2
:loop jsr _PushDirtyTileX
dex
dex
bpl :loop
_TSExit #0;#0 _TSExit #0;#0
; Insert the GTE code ; Insert the GTE code
@ -725,6 +727,7 @@ _TSRefresh
put render/Slow.s put render/Slow.s
put render/Dynamic.s put render/Dynamic.s
put render/TwoLayer.s put render/TwoLayer.s
put render/Dirty.s
put render/Sprite1.s put render/Sprite1.s
put render/Sprite2.s put render/Sprite2.s
put tiles/DirtyTileQueue.s put tiles/DirtyTileQueue.s

View File

@ -46,10 +46,10 @@ Counter equ tmp3
lda (NextColPtr),y ; Need to recalculate each time since the wrap-around could lda (NextColPtr),y ; Need to recalculate each time since the wrap-around could
clc ; happen anywhere clc ; happen anywhere
adc (RowAddrPtr) ; adc (RowAddrPtr) ;
tax ; NOTE: Try to rework to use new TileStore2DLookup array tax ; NOTE: Try to rework to use new TileStoreLookup array
lda OnScreenAddr lda OnScreenAddr
sta TileStore+TS_SCREEN_ADDR,x sta TileStore+TS_SCREEN_ADDR,x
clc clc
adc #4 ; Go to the next tile adc #4 ; Go to the next tile

438
src/render/Dirty.s Normal file
View File

@ -0,0 +1,438 @@
; Special routines for the dirty tile renderer that draws directly to the graphics screen
; A = tile address
; Y = screen address
SpriteUnder0Dirty
ConstTile0Dirty
lda TileStore+TS_SCREEN_ADDR,x ; Get the on-screen address of this tile
tax
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]line equ 0
lup 8
stz: {]line*SHR_LINE_WIDTH}+0,x
stz: {]line*SHR_LINE_WIDTH}+2,x
]line equ ]line+1
--^
plb
rts
; Sprite over a zero tile
OneSpriteDirtyOver0
ldy TileStore+TS_SCREEN_ADDR,x
tax
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]line equ 0
lup 8
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+0,x
sta: {]line*SHR_LINE_WIDTH}+0,y
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
sta: {]line*SHR_LINE_WIDTH}+2,y
]line equ ]line+1
--^
plb
rts
; Multiple sprites (copied to direct page temp space)
SpriteOver0Dirty
ldy TileStore+TS_SCREEN_ADDR,x
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]line equ 0
lup 8
lda tmp_sprite_data+{]line*4}+0
sta: {]line*SHR_LINE_WIDTH}+0,y
lda tmp_sprite_data+{]line*4}+2
sta: {]line*SHR_LINE_WIDTH}+2,y
]line equ ]line+1
--^
plb
rts
CopyTileADirty
ldy TileStore+TS_SCREEN_ADDR,x ; Get the on-screen address of this tile
lda TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated)
tax
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]line equ 0
lup 8
ldal tiledata+{]line*4}+0,x
sta: {]line*SHR_LINE_WIDTH}+0,y
ldal tiledata+{]line*4}+2,x
sta: {]line*SHR_LINE_WIDTH}+2,y
]line equ ]line+1
--^
plb
rts
CopyTileVDirty
ldy TileStore+TS_SCREEN_ADDR,x ; Get the on-screen address of this tile
lda TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated)
tax
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]src equ 7
]dest equ 0
lup 8
ldal tiledata+{]src*4}+0,x
sta: {]line*SHR_LINE_WIDTH}+0,y
ldal tiledata+{]src*4}+2,x
sta: {]line*SHR_LINE_WIDTH}+2,y
]src equ ]src-1
]dest equ ]dest+1
--^
plb
rts
; DirtySpriteLine srcLine,destLine,dpAddr,offset
DirtySpriteOver mac
lda: tiledata+{]1*TILE_DATA_SPAN}+]4,y
andl spritemask+{]2*SPRITE_PLANE_SPAN}+]4,x
oral spritedata+{]2*SPRITE_PLANE_SPAN}+]4,x
sta ]3+]4
<<<
DirtySpriteUnder mac
ldal spritedata+{]2*SPRITE_PLANE_SPAN}+]4,x
and tiledata+{]1*TILE_DATA_SPAN}+32+]4,y
ora tiledata+{]1*TILE_DATA_SPAN}+]4,y
sta ]3+]4
<<<
; Special routine for a single sprite
OneSpriteDirtyOverA
ldy TileStore+TS_TILE_ADDR,x
lda TileStore+TS_SCREEN_ADDR,x
ldx sprite_ptr0
phd
pei DP2_TILEDATA_AND_TILESTORE_BANKS
plb
sei
clc
tcd
_R0W1
DirtySpriteOver 0;0;$00;0
DirtySpriteOver 0;0;$00;2
DirtySpriteOver 1;1;$A0;0
DirtySpriteOver 1;1;$A0;2
tdc
adc #320
tcd
DirtySpriteOver 2;2;$00;0
DirtySpriteOver 2;2;$00;2
DirtySpriteOver 3;3;$A0;0
DirtySpriteOver 3;3;$A0;2
tdc
adc #320
tcd
DirtySpriteOver 4;4;$00;0
DirtySpriteOver 4;4;$00;2
DirtySpriteOver 5;5;$A0;0
DirtySpriteOver 5;5;$A0;2
tdc
adc #320
tcd
DirtySpriteOver 6;6;$00;0
DirtySpriteOver 6;6;$00;2
DirtySpriteOver 7;7;$A0;0
DirtySpriteOver 7;7;$A0;2
_R0W0
cli
plb
pld
rts
OneSpriteDirtyUnderA
ldy TileStore+TS_TILE_ADDR,x
lda TileStore+TS_SCREEN_ADDR,x
ldx sprite_ptr0
phd
pei DP2_TILEDATA_AND_TILESTORE_BANKS
plb
sei
clc
tcd
_R0W1
DirtySpriteUnder 0;0;$00;0
DirtySpriteUnder 0;0;$00;2
DirtySpriteUnder 1;1;$A0;0
DirtySpriteUnder 1;1;$A0;2
tdc
adc #320
tcd
DirtySpriteUnder 2;2;$00;0
DirtySpriteUnder 2;2;$00;2
DirtySpriteUnder 3;3;$A0;0
DirtySpriteUnder 3;3;$A0;2
tdc
adc #320
tcd
DirtySpriteUnder 4;4;$00;0
DirtySpriteUnder 4;4;$00;2
DirtySpriteUnder 5;5;$A0;0
DirtySpriteUnder 5;5;$A0;2
tdc
adc #320
tcd
DirtySpriteUnder 6;6;$00;0
DirtySpriteUnder 6;6;$00;2
DirtySpriteOver 7;7;$A0;0
DirtySpriteUnder 7;7;$A0;2
_R0W0
cli
plb
pld
rts
OneSpriteDirtyOverV
ldy TileStore+TS_TILE_ADDR,x
lda TileStore+TS_SCREEN_ADDR,x
ldx sprite_ptr0
phd
pei DP2_TILEDATA_AND_TILESTORE_BANKS
plb
sei
clc
tcd
_R0W1
DirtySpriteOver 7;0;$00;0
DirtySpriteOver 7;0;$00;2
DirtySpriteOver 6;1;$A0;0
DirtySpriteOver 6;1;$A0;2
tdc
adc #320
tcd
DirtySpriteOver 5;2;$00;0
DirtySpriteOver 5;2;$00;2
DirtySpriteOver 4;3;$A0;0
DirtySpriteOver 4;3;$A0;2
tdc
adc #320
tcd
DirtySpriteOver 3;4;$00;0
DirtySpriteOver 3;4;$00;2
DirtySpriteOver 2;5;$A0;0
DirtySpriteOver 2;5;$A0;2
tdc
adc #320
tcd
DirtySpriteOver 1;6;$00;0
DirtySpriteOver 1;6;$00;2
DirtySpriteOver 0;7;$A0;0
DirtySpriteOver 0;7;$A0;2
_R0W0
cli
plb
pld
rts
OneSpriteDirtyUnderV
ldy TileStore+TS_TILE_ADDR,x
lda TileStore+TS_SCREEN_ADDR,x
ldx sprite_ptr0
phd
pei DP2_TILEDATA_AND_TILESTORE_BANKS
plb
sei
clc
tcd
_R0W1
DirtySpriteUnder 7;0;$00;0
DirtySpriteUnder 7;0;$00;2
DirtySpriteUnder 6;1;$A0;0
DirtySpriteUnder 6;1;$A0;2
tdc
adc #320
tcd
DirtySpriteUnder 5;2;$00;0
DirtySpriteUnder 5;2;$00;2
DirtySpriteUnder 4;3;$A0;0
DirtySpriteUnder 4;3;$A0;2
tdc
adc #320
tcd
DirtySpriteUnder 3;4;$00;0
DirtySpriteUnder 3;4;$00;2
DirtySpriteUnder 2;5;$A0;0
DirtySpriteUnder 2;5;$A0;2
tdc
adc #320
tcd
DirtySpriteUnder 1;6;$00;0
DirtySpriteUnder 1;6;$00;2
DirtySpriteUnder 0;7;$A0;0
DirtySpriteUnder 0;7;$A0;2
_R0W0
cli
plb
pld
rts
; Generic routine for multiple sprites -- expect sprites to be in tmp_sprite_data and tmp_sprite_mask
SpriteOverADirty
ldy TileStore+TS_SCREEN_ADDR,x
lda TileStore+TS_TILE_ADDR,x
tax
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]line equ 0
lup 8
ldal tiledata+{]line*TILE_DATA_SPAN}+0,x
and tmp_sprite_mask+{]line*4}+0
ora tmp_sprite_data+{]line*4}+0
sta: {]line*SHR_LINE_WIDTH}+0,y
; brk $00
ldal tiledata+{]line*TILE_DATA_SPAN}+2,x
and tmp_sprite_mask+{]line*4}+2
ora tmp_sprite_data+{]line*4}+2
sta: {]line*SHR_LINE_WIDTH}+2,y
]line equ ]line+1
--^
plb
rts
SpriteUnderADirty
ldy TileStore+TS_SCREEN_ADDR,x
lda TileStore+TS_TILE_ADDR,x
tax
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]line equ 0
lup 8
lda tmp_sprite_data+{]line*4}+0
andl tiledata+{]line*TILE_DATA_SPAN}+32,x
oral tiledata+{]line*TILE_DATA_SPAN}+0,x
sta: {]line*SHR_LINE_WIDTH}+0,y
lda tmp_sprite_data+{]line*4}+2
andl tiledata+{]line*TILE_DATA_SPAN}+32+2,x
oral tiledata+{]line*TILE_DATA_SPAN}+2,x
sta: {]line*SHR_LINE_WIDTH}+2,y
]line equ ]line+1
--^
plb
rts
SpriteOverVDirty
ldy TileStore+TS_SCREEN_ADDR,x
lda TileStore+TS_TILE_ADDR,x
tax
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]src equ 7
]dest equ 0
lup 8
ldal tiledata+{]src*TILE_DATA_SPAN}+0,x
and tmp_sprite_mask+{]dest*4}+0
ora tmp_sprite_data+{]dest*4}+0
sta: {]dest*SHR_LINE_WIDTH}+0,y
ldal tiledata+{]src*TILE_DATA_SPAN}+2,x
and tmp_sprite_mask+{]dest*4}+2
ora tmp_sprite_data+{]dest*4}+2
sta: {]dest*SHR_LINE_WIDTH}+2,y
]src equ ]src-1
]dest equ ]dest+1
--^
plb
rts
SpriteUnderVDirty
ldy TileStore+TS_SCREEN_ADDR,x
lda TileStore+TS_TILE_ADDR,x
tax
pei DP2_BANK01_AND_TILESTORE_BANKS
plb
]src equ 7
]dest equ 0
lup 8
lda tmp_sprite_data+{]dest*4}+0
andl tiledata+{]src*TILE_DATA_SPAN}+32,x
oral tiledata+{]src*TILE_DATA_SPAN}+0,x
sta: {]dest*SHR_LINE_WIDTH}+0,y
lda tmp_sprite_data+{]dest*4}+2
andl tiledata+{]src*TILE_DATA_SPAN}+32+2,x
oral tiledata+{]src*TILE_DATA_SPAN}+2,x
sta: {]dest*SHR_LINE_WIDTH}+2,y
]src equ ]src-1
]dest equ ]dest+1
--^
plb
rts

View File

@ -1,8 +1,8 @@
; If there are no sprites, then we copy the tile data into the code field as fast as possible. ; If there are no sprites, then we copy the tile data into the code field as fast as possible.
; If there are sprites, then additional work is required ; If there are sprites, then additional work is required
_RenderTile _RenderTile
lda TileStore+TS_SPRITE_FLAG,x ; any sprites on this line? lda TileStore+TS_SPRITE_FLAG,x ; any sprites on this tile?
bne :sprites bne _HasSprites
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line 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 TileStore bank in high byte. pha ; and put on the stack for later. Has TileStore bank in high byte.
@ -11,11 +11,24 @@ _RenderTile
plb ; set the code field bank plb ; set the code field bank
jmp (K_TS_BASE_TILE_DISP,x) ; go to the tile copy routine jmp (K_TS_BASE_TILE_DISP,x) ; go to the tile copy routine
; This is the specialized rederer for the dirty tile rendering mode. The difference is that
; it is assumed that the screen is static and the tiles are aligned with the graphics screen.
; The engine must be in "Fast" tile mode for dirty tile rendering to work. It is possible
; to switch the engine into this mode by rendering a full screen of solid tiles and then
; doing a dirty tile rendering.
;
; The main result is that this renderer skips copying tile data into the play field and
; just draws to the screen directly.
_RenderDirtyTile
lda TileStore+TS_SPRITE_FLAG,x ; any sprites on this tile?
bne _HasSprites
jmp (K_TS_BASE_TILE_DISP,x) ; This is just to select between H/V flips
; Execute the sprite tree. If there is only one sprite, control will immediately be passed to ; Execute the sprite tree. If there is only one sprite, control will immediately be passed to
; the routine at K_TS_ONE_SPRITE. Otherwise, the control passed to the routines with a different ; the routine at K_TS_ONE_SPRITE. Otherwise, the control passed to the routines with a different
; number of sprites. These routines need to copy the flattened sprite data and mask into the ; number of sprites. These routines need to copy the flattened sprite data and mask into the
; direct page workspace to be used by the K_TS_SPRITE_TILE_DISP routine ; direct page workspace to be used by the K_TS_SPRITE_TILE_DISP routine
:sprites txy _HasSprites txy
SpriteBitsToVBuffAddrs $0000;TwoSprites;ThreeSprites;FourSprites SpriteBitsToVBuffAddrs $0000;TwoSprites;ThreeSprites;FourSprites
; Dispatch vectors for the two, three and four sprite functions. These just ; Dispatch vectors for the two, three and four sprite functions. These just
@ -33,54 +46,3 @@ ThreeSprites tyx
FourSprites tyx FourSprites tyx
jmp CopyFourSpritesDataAndMaskToDP jmp CopyFourSpritesDataAndMaskToDP
; Now, implement the generic Two, Three and Four sprite routines for both Over and Under rendering. These
; are fairly involved, so we try to only have a single implementation of them for now without excessve
; specialization.
FourSpriteLine mac
; and [sprite_ptr3],y
db $37,sprite_ptr3
ora (sprite_ptr3),y
; and [sprite_ptr2],y
db $37,sprite_ptr2
ora (sprite_ptr2),y
; and [sprite_ptr1],y
db $37,sprite_ptr1
ora (sprite_ptr1),y
; and [sprite_ptr0],y
db $37,sprite_ptr0
ora (sprite_ptr0),y
<<<
FourSpritesFast
tyx ; save for after compositing the sprites
ldy TileStore+TS_TILE_ADDR,x
pei DP2_TILEDATA_AND_TILESTORE_BANKS
plb
jsr (K_TS_COPY_TILE_DATA,x)
plb
pei DP2_SPRITEDATA_AND_TILESTORE_BANKS
plb ; set the sprite data bank
]line equ 0
lup 8
ldy #{]line*SPRITE_PLANE_SPAN}
lda tmp_tile_data+{]line*4}
FourSpriteLine
sta tmp_tile_data+{]line*4}
ldy #{]line*SPRITE_PLANE_SPAN}+2
lda tmp_tile_data+{]line*4}+2
FourSpriteLine
sta tmp_tile_data+{]line*4}+2
]line equ ]line+1
--^
plb
jmp (K_TS_APPLY_TILE_DATA,x)

View File

@ -40,6 +40,7 @@ SPRITE_STATUS_ADDED equ $0001 ; Sprite was just added (new sprite)
SPRITE_STATUS_MOVED equ $0002 ; Sprite's position was changed SPRITE_STATUS_MOVED equ $0002 ; Sprite's position was changed
SPRITE_STATUS_UPDATED equ $0004 ; Sprite's non-position attributes were changed SPRITE_STATUS_UPDATED equ $0004 ; Sprite's non-position attributes were changed
SPRITE_STATUS_REMOVED equ $0008 ; Sprite has been removed. SPRITE_STATUS_REMOVED equ $0008 ; Sprite has been removed.
SPRITE_STATUS_HIDDEN equ $0010 ; Sprite is in a hidden state
; These values are set by the user ; These values are set by the user
SPRITE_STATUS equ {MAX_SPRITES*0} SPRITE_STATUS equ {MAX_SPRITES*0}

View File

@ -70,8 +70,7 @@ _PopDirtyTile2 ; alternate entry point
sty DirtyTileCount ; remove last item from the list sty DirtyTileCount ; remove last item from the list
ldx DirtyTiles,y ; load the offset into the Tile Store ldx DirtyTiles,y ; load the offset into the Tile Store
lda #$FFFF stz TileStore+TS_DIRTY,x ; clear the occupied backlink
stal TileStore+TS_DIRTY,x ; clear the occupied backlink
rts rts
; An optimized subroutine that runs through the dirty tile list and executes a callback function ; An optimized subroutine that runs through the dirty tile list and executes a callback function