Fix left-edge sprite rendering glitch; was an issue with not erasing sprites when they transition to IS_OFFSCREEN status

This commit is contained in:
Lucas Scharenbroich 2022-06-08 14:25:52 -05:00
parent 1de4c0bc7f
commit 388470c133
4 changed files with 124 additions and 251 deletions

View File

@ -64,29 +64,6 @@ NEXT_TO_LAST_COL equ {{TILE_STORE_WIDTH-2}*2}
ldx #NEXT_TO_LAST_ROW+NEXT_TO_LAST_COL ; Next-to-Last row, Next-to-Last column
jsr _SetVBuffValues
; Set the VBuff array addresses for each sprite, since they're static
;
; NOTE: Can remove later
; ldx #0
; lda #VBuffArray
;:loop3 sta _Sprites+VBUFF_ARRAY_ADDR,x
; clc
; adc #4*2 ; skip ahead 4 tiles
; inx
; inx
; cpx #8*2
; bcc :loop3
; Now do the second set of sprites
; lda #VBuffArray+{3*{TILE_STORE_WIDTH*2}}
;:loop4 sta _Sprites+VBUFF_ARRAY_ADDR,x
; clc
; adc #4*2 ; skip ahead 4 tiles
; inx
; inx
; cpx #16*2
; bcc :loop4
; Initialize the Page 2 pointers
ldx #$100
lda #^spritemask
@ -231,13 +208,9 @@ _RenderSprites
; Implement the logic for updating sprite and tile rendering information. Each iteration of the
; ActiveSpriteCount will call this routine with the Y-register set to the sprite index
tmpY equ tmp15
tmpA equ tmp14
_DoPhase1
lda _Sprites+SPRITE_STATUS,y
ora ForceSpriteFlag
sta tmpA
sty tmpY
; First step, if a sprite is being removed, then we just have to clear its old tile information
; and mark the tiles it overlapped as dirty.
@ -251,21 +224,15 @@ _DoPhase1
lda #SPRITE_STATUS_EMPTY ; Mark as empty so no error if we try to Add a sprite here again
sta _Sprites+SPRITE_STATUS,y
lda _Sprites+TS_COVERAGE_SIZE,y ; Manually copy current value to old
sta _Sprites+OLD_TS_COVERAGE_SIZE,y
lda _Sprites+TS_LOOKUP_INDEX,y
sta _Sprites+OLD_TS_LOOKUP_INDEX,y
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.
; sprites, so we do it unconditionally, but we do need to mark the current sprite for erasure if
; needed
:no_clear
jsr _CalcDirtySprite
; If the sprite is marked as ADDED, then it does not need to have its old tile locations cleared
lda tmpA
bit #SPRITE_STATUS_ADDED
bne :no_move
@ -275,12 +242,15 @@ _DoPhase1
bit #SPRITE_STATUS_MOVED
beq :no_move
phy
jsr _ClearSpriteFromTileStore
ldy tmpY
ply
; Anything else (MOVED, UPDATED, ADDED) will need to have the VBUFF information updated and the
; current tiles marked for update
:no_move
jsr _CalcDirtySprite ; This function preserves Y
lda #SPRITE_STATUS_OCCUPIED ; Clear the dirty bits (ADDED, UPDATED, MOVED)
sta _Sprites+SPRITE_STATUS,y
@ -384,7 +354,7 @@ _CreateSpriteStamp
; the vertical tiles are taken from tileId + 32. This is why tile sheets should be saved
; with a width of 256 pixels.
;
; A = tileId + flags
; A = vbuffAddress
; Y = High Byte = x-pos, Low Byte = y-pos
; X = Sprite Slot (0 - 15)
_AddSprite
@ -458,7 +428,7 @@ next
_ClearSpriteFromTileStore
lda _SpriteBitsNot,y ; Cache this value in a direct page location
sta tmp0
ldx _Sprites+OLD_TS_COVERAGE_SIZE,y
ldx _Sprites+TS_COVERAGE_SIZE,y
jmp (csfts_tbl,x)
csfts_tbl dw csfts_1x1,csfts_1x2,csfts_1x3,csfts_out
dw csfts_2x1,csfts_2x2,csfts_2x3,csfts_out
@ -467,7 +437,7 @@ csfts_tbl dw csfts_1x1,csfts_1x2,csfts_1x3,csfts_out
csfts_out rts
csfts_3x3 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_3x3 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
TSClearSprite 2
TSClearSprite 4
@ -479,7 +449,7 @@ csfts_3x3 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+4
rts
csfts_3x2 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_3x2 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
TSClearSprite 2
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
@ -488,13 +458,13 @@ csfts_3x2 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+2
rts
csfts_3x1 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_3x1 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+0
rts
csfts_2x3 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_2x3 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
TSClearSprite 2
TSClearSprite 4
@ -503,30 +473,30 @@ csfts_2x3 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+4
rts
csfts_2x2 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_2x2 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
TSClearSprite 2
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+2
rts
csfts_2x1 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_2x1 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
rts
csfts_1x3 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_1x3 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
TSClearSprite 2
TSClearSprite 4
rts
csfts_1x2 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_1x2 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
TSClearSprite 2
rts
csfts_1x1 ldx _Sprites+OLD_TS_LOOKUP_INDEX,y
csfts_1x1 ldx _Sprites+TS_LOOKUP_INDEX,y
TSClearSprite 0
rts
@ -638,37 +608,6 @@ _CacheSpriteBanks
rts
; A = x coordinate
; Y = y coordinate
;GetSpriteVBuffAddr ENT
; jsr _GetSpriteVBuffAddr
; rtl
; A = x coordinate
; Y = y coordinate
;_GetSpriteVBuffAddr
; pha
; tya
; clc
; adc #NUM_BUFF_LINES ; The virtual buffer has 24 lines of off-screen space
; xba ; Each virtual scan line is 256 bytes wide for overdraw space
; clc
; adc 1,s
; sta 1,s
; pla
; rts
; Version that uses temporary space (tmp15)
;_GetSpriteVBuffAddrTmp
; sta tmp15
; tya
; clc
; adc #NUM_BUFF_LINES ; The virtual buffer has 24 lines of off-screen space
; xba ; Each virtual scan line is 256 bytes wide for overdraw space
; clc
; adc tmp15
; rts
; Precalculate some cached values for a sprite. These are *only* to make other part of code,
; specifically the draw/erase routines more efficient.
;

View File

@ -1,20 +1,9 @@
; Scratch space to lay out idealized _MakeDirtySprite
; On input, X register = Sprite Array Index
;Left equ tmp1
;Right equ tmp2
;Top equ tmp3
;Bottom equ tmp4
;Origin equ tmp4
;TileTop equ tmp5
RowTop equ tmp6
AreaIndex equ tmp7
;TileLeft equ tmp8
;ColLeft equ tmp9
SpriteBit equ tmp10 ; set the bit of the value that if the current sprite index
; VBuffOrigin equ tmp11
SpriteBit equ tmp8 ; set the bit of the value that if the current sprite index
; Table of pre-multiplied vbuff strides
vbuff_mul
@ -48,7 +37,7 @@ vbuff_mul
; 8 10 2 8
; ...
;
; For the Y-coordinate, we just use "mod 8" instead of "mod 4"
; For the Y-coordinate, we use "mod 8" instead of "mod 4"
;
; When this subroutine is completed, the following values will be calculated
;
@ -68,12 +57,14 @@ _CalcDirtySprite
lda _Sprites+IS_OFF_SCREEN,y ; Check if the sprite is visible in the playfield
bne mdsOut2
; Copy the current values into the old value slots
lda _Sprites+TS_COVERAGE_SIZE,y
sta _Sprites+OLD_TS_COVERAGE_SIZE,y
lda _Sprites+TS_LOOKUP_INDEX,y
sta _Sprites+OLD_TS_LOOKUP_INDEX,y
; Part 1: Calculate the visible tiles that the sprite covers. If the sprite is partially
; off-screen, then the visible tiles may be different than the set of tiles
; covered by the sprite. In particular, the upper-left corner tile which defines
; relative offset values will change.
;
; So, we do some calculations with the CLIPPED values and some with the actual
; sprite values. There is an optimization opportunity here to share calculations
; when the x or y position of the sprite is positive.
; Add the first visible row of the sprite to the Y-scroll offset to find the first line in the
; code field that needs to be drawn. The range of values is 0 to 199+207 = [0, 406]. This
@ -113,7 +104,6 @@ _CalcDirtySprite
pha
and #$FFFC
lsr ; Even numbers from [0, 160] (81 elements)
sta tmp3
adc RowTop
sta _Sprites+TS_LOOKUP_INDEX,y ; This is the index into the TileStoreLookup table
@ -131,15 +121,39 @@ _CalcDirtySprite
sta _Sprites+TS_COVERAGE_SIZE,y ; Save this value as a key to the coverage size of the sprite
; Calculate the VBUFF offset based on the actual (signed) sprite position
; Part 2: Redo some calculation with the actual (signed) sprite positions that take into
; account negative coordinates to set the VBuff offset values.
clc
lda _Sprites+SPRITE_Y,y
adc StartYMod208
bpl :y_ok
clc
adc #208 ; Wrap the actual coordinat around
:y_ok and #$FFF8 ; mask first to ensure LSR will clear the carry
lsr
lsr
tax ; Tile store lookup index
lda _Sprites+SPRITE_X,y
adc StartXMod164
bpl :x_ok
clc
adc #164
:x_ok and #$FFFC
lsr ; Even numbers from [0, 160] (81 elements)
sta tmp3
adc TileStoreLookupYTable,x
pha ; will be PLX later
clc ; Carry should still be clear here....
lda StartYMod208
and #$0007
adc _Sprites+SPRITE_Y,y
bmi :neg_y
bpl :pos_y
clc
adc #208
:pos_y
and #$0007
:neg_y
asl ; Multiply by 48. Would be nice to use a
asl ; table lookup, but the values can be negative
asl ; so do the calculation
@ -158,11 +172,12 @@ _CalcDirtySprite
clc
lda StartXMod164
and #$0003
adc _Sprites+SPRITE_X,y
bmi :neg_x
bpl :pos_x
clc
adc #164
:pos_x
and #$0003
:neg_x
clc
adc tmp0 ; add to the vertical offset
@ -185,7 +200,8 @@ _CalcDirtySprite
adc VBuffHorzTableSelect,x ; A bunch of 0, 4 or 8 values
clc
adc #VBuffArray
ldx _Sprites+TS_LOOKUP_INDEX,y
plx
; ldx _Sprites+TS_LOOKUP_INDEX,y
sec
sbc TileStoreLookup,x
sta tmp1 ; Spill this value to direct page temp space
@ -193,6 +209,7 @@ _CalcDirtySprite
; Last task. Since we don't need to use the X-register to cache values; load the direct page 2
; offset for the SPRITE_VBUFF_PTR and save it
tmp_out
tya
ora #$100
tax
@ -254,35 +271,17 @@ ROW equ TILE_STORE_WIDTH*2 ; This many bytes to the nex
COL equ 2 ; This many bytes for each element
:mark1x1
; ldx _Sprites+VBUFF_ARRAY_ADDR,y ; get the address of this sprite's vbuff values
; lda _Sprites+TS_VBUFF_BASE,y ; get the starting vbuff address
; sta: {0*ROW}+{0*COL},x ; Put in the vbuff address
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}
rts
:mark1x2
; ldx _Sprites+VBUFF_ARRAY_ADDR,y
; lda _Sprites+TS_VBUFF_BASE,y
; sta: {0*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{1*COL},x
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
rts
:mark1x3
; ldx _Sprites+VBUFF_ARRAY_ADDR,y
; lda _Sprites+TS_VBUFF_BASE,y
; sta: {0*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{1*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{2*COL},x
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
@ -290,28 +289,12 @@ COL equ 2 ; This many bytes for each e
rts
:mark2x1
; ldx _Sprites+VBUFF_ARRAY_ADDR,y
; lda _Sprites+TS_VBUFF_BASE,y
; sta: {0*ROW}+{0*COL},x
; adc #VBUFF_TILE_ROW_BYTES
; sta: {1*ROW}+{0*COL},x
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+0
rts
:mark2x2
; ldx _Sprites+VBUFF_ARRAY_ADDR,y
; lda _Sprites+TS_VBUFF_BASE,y
; sta: {0*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{1*COL},x
; adc #VBUFF_TILE_ROW_BYTES-VBUFF_TILE_COL_BYTES
; sta: {1*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {1*ROW}+{1*COL},x
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
@ -320,20 +303,6 @@ COL equ 2 ; This many bytes for each e
rts
:mark2x3
; ldx _Sprites+VBUFF_ARRAY_ADDR,y
; lda _Sprites+TS_VBUFF_BASE,y
; sta: {0*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{1*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{2*COL},x
; adc #VBUFF_TILE_ROW_BYTES-{2*VBUFF_TILE_COL_BYTES}
; sta: {1*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {1*ROW}+{1*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {1*ROW}+{2*COL},x
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
@ -344,14 +313,6 @@ COL equ 2 ; This many bytes for each e
rts
:mark3x1
; ldx _Sprites+VBUFF_ARRAY_ADDR,y
; lda _Sprites+TS_VBUFF_BASE,y
; sta: {0*ROW}+{0*COL},x
; adc #VBUFF_TILE_ROW_BYTES
; sta: {1*ROW}+{0*COL},x
; adc #VBUFF_TILE_ROW_BYTES
; sta: {2*ROW}+{0*COL},x
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+0
@ -359,20 +320,6 @@ COL equ 2 ; This many bytes for each e
rts
:mark3x2
; ldx _Sprites+VBUFF_ARRAY_ADDR,y
; lda _Sprites+TS_VBUFF_BASE,y
; sta: {0*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{1*COL},x
; adc #VBUFF_TILE_ROW_BYTES-VBUFF_TILE_COL_BYTES
; sta: {1*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {1*ROW}+{1*COL},x
; adc #VBUFF_TILE_ROW_BYTES-VBUFF_TILE_COL_BYTES
; sta: {2*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {2*ROW}+{1*COL},x
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
@ -383,26 +330,6 @@ COL equ 2 ; This many bytes for each e
rts
:mark3x3
; ldx _Sprites+VBUFF_ARRAY_ADDR,y
; lda _Sprites+TS_VBUFF_BASE,y
; sta: {0*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{1*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {0*ROW}+{2*COL},x
; adc #VBUFF_TILE_ROW_BYTES-{2*VBUFF_TILE_COL_BYTES}
; sta: {1*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {1*ROW}+{1*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {1*ROW}+{2*COL},x
; adc #VBUFF_TILE_ROW_BYTES-{2*VBUFF_TILE_COL_BYTES}
; sta: {2*ROW}+{0*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {2*ROW}+{1*COL},x
; adc #VBUFF_TILE_COL_BYTES
; sta: {2*ROW}+{2*COL},x
ldx _Sprites+TS_LOOKUP_INDEX,y
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2

View File

@ -50,32 +50,18 @@ VBUFF_ADDR equ {MAX_SPRITES*8} ; Base address of the sprite's
; These values are cached / calculated during the rendering process
TS_LOOKUP_INDEX equ {MAX_SPRITES*10} ; The index from the TileStoreLookup table that corresponds to the top-left corner of the sprite
TS_COVERAGE_SIZE equ {MAX_SPRITES*12} ; Representation of how many TileStore tiles (NxM) are covered by this sprite
OLD_TS_LOOKUP_INDEX equ {MAX_SPRITES*14} ; Copy of the values to support diffing
OLD_TS_COVERAGE_SIZE equ {MAX_SPRITES*16}
SPRITE_DISP equ {MAX_SPRITES*18} ; Cached address of the specific stamp based on sprite flags
SPRITE_CLIP_LEFT equ {MAX_SPRITES*20}
SPRITE_CLIP_RIGHT equ {MAX_SPRITES*22}
SPRITE_CLIP_TOP equ {MAX_SPRITES*24}
SPRITE_CLIP_BOTTOM equ {MAX_SPRITES*26}
IS_OFF_SCREEN equ {MAX_SPRITES*28}
SPRITE_WIDTH equ {MAX_SPRITES*30}
SPRITE_HEIGHT equ {MAX_SPRITES*32}
SPRITE_CLIP_WIDTH equ {MAX_SPRITES*34}
SPRITE_CLIP_HEIGHT equ {MAX_SPRITES*36}
TS_VBUFF_BASE equ {MAX_SPRITES*38} ; Finalized VBUFF address based on the sprite position and tile offsets
VBUFF_ARRAY_ADDR equ {MAX_SPRITES*40} ; Fixed address where this sprite's VBUFF addresses are stores. The array is the same shape as TileStore, but much smaller
;TILE_DATA_OFFSET equ {MAX_SPRITES*2}
;TILE_STORE_ADDR_1 equ {MAX_SPRITES*12}
;TILE_STORE_ADDR_2 equ {MAX_SPRITES*14}
;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*14} ; Cached address of the specific stamp based on sprite flags
SPRITE_CLIP_LEFT equ {MAX_SPRITES*16}
SPRITE_CLIP_RIGHT equ {MAX_SPRITES*18}
SPRITE_CLIP_TOP equ {MAX_SPRITES*20}
SPRITE_CLIP_BOTTOM equ {MAX_SPRITES*22}
IS_OFF_SCREEN equ {MAX_SPRITES*24}
SPRITE_WIDTH equ {MAX_SPRITES*26}
SPRITE_HEIGHT equ {MAX_SPRITES*28}
SPRITE_CLIP_WIDTH equ {MAX_SPRITES*30}
SPRITE_CLIP_HEIGHT equ {MAX_SPRITES*32}
TS_VBUFF_BASE equ {MAX_SPRITES*34} ; Finalized VBUFF address based on the sprite position and tile offsets
VBUFF_ARRAY_ADDR equ {MAX_SPRITES*36} ; Fixed address where this sprite's VBUFF addresses are stores. The array is the same shape as TileStore, but much smaller
; 52 rows by 82 columns + 2 extra rows and columns for sprite sizes
;

View File

@ -38,7 +38,7 @@ FastTileProcs dw _TBCopyDataFast,_TBCopyDataFast,_TBCopyDataFast,_TBCopyDataFa
SpriteDispatch
txy
SpriteBitsToVBuffAddrs OneSpriteFast;TwoSpritesFast;ThreeSpritesFast;ThreeSpritesFast
SpriteBitsToVBuffAddrs OneSpriteFast;TwoSpritesFast;ThreeSpritesFast;FourSpritesFast
; Where there are sprites involved, the first step is to call a routine to copy the
; tile data into a temporary buffer. Then the sprite data is merged and placed into
@ -177,37 +177,58 @@ ThreeSpritesFast
plb ; Reset to the bank in the top byte of CODE_ADDR_HIGH
rts
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
; lda TileStore+TS_TILE_ADDR,y
; per :-1
; jmp (TileStore+TS_BASE_TILE_COPY,x) ; Copy the tile data to the temporary buffer
;:
; lda TileStore+TS_VBUFF_ADDR_0,y ; address of the sprite data
; sta spritedata_0
; sta spritemask_0
; lda TileStore+TS_VBUFF_ADDR_1,y
; sta spritedata_1
; sta spritemask_1
; lda TileStore+TS_VBUFF_ADDR_2,y
; sta spritedata_2
; sta spritemask_2
ldx TileStore+TS_TILE_ADDR,y
lda TileStore+TS_CODE_ADDR_HIGH,y ; load the bank of the target code field line
pha ; and put on the stack for later.
lda TileStore+TS_CODE_ADDR_LOW,y
tay
plb ; set the code field bank
pha ; and put on the stack for later. Has TileStore bank in high byte.
lda TileStore+TS_CODE_ADDR_LOW,y ; load the address of the code field
pha ; Need to pop it later....
; ThreeSpritesToCodeField 0
; ThreeSpritesToCodeField 1
; ThreeSpritesToCodeField 2
; ThreeSpritesToCodeField 3
; ThreeSpritesToCodeField 4
; ThreeSpritesToCodeField 5
; ThreeSpritesToCodeField 6
; ThreeSpritesToCodeField 7
sep #$20 ; set the sprite data bank
lda #^spritedata
pha
plb
rep #$20
]line equ 0
lup 8
ldy #{]line*SPRITE_PLANE_SPAN}
ldal tiledata+{]line*4},x
FourSpriteLine
sta tmp_tile_data+{]line*4}
ldy #{]line*SPRITE_PLANE_SPAN}+2
ldal tiledata+{]line*4}+2,x
FourSpriteLine
sta tmp_tile_data+{]line*4}+2
]line equ ]line+1
--^
ply ; Pop off CODE_ADDR_LOW
plb ; Set the CODE_ADDR_HIGH bank
]line equ 0
lup 8
lda tmp_tile_data+{]line*4}
sta: $0004+{]line*$1000},y
lda tmp_tile_data+{]line*4}+2
sta: $0001+{]line*$1000},y
]line equ ]line+1
--^
plb ; Reset to the bank in the top byte of CODE_ADDR_HIGH
rts