2022-02-03 14:50:11 +00:00
|
|
|
; Functions for sprite handling. Mostly maintains the sprite list and provides
|
2021-10-21 13:50:07 +00:00
|
|
|
; utility functions to calculate sprite/tile intersections
|
2021-08-25 14:38:02 +00:00
|
|
|
;
|
2022-02-18 18:12:32 +00:00
|
|
|
; Initialize the sprite data and mask banks (all data = $0000, all masks = $FFFF)
|
2021-10-24 03:31:38 +00:00
|
|
|
InitSprites
|
2021-10-21 13:50:07 +00:00
|
|
|
ldx #$FFFE
|
|
|
|
lda #0
|
2021-10-24 03:31:38 +00:00
|
|
|
:loop1 stal spritedata,x
|
2021-10-21 13:50:07 +00:00
|
|
|
dex
|
|
|
|
dex
|
2021-10-29 02:52:48 +00:00
|
|
|
cpx #$FFFE
|
|
|
|
bne :loop1
|
2021-10-21 13:50:07 +00:00
|
|
|
|
|
|
|
ldx #$FFFE
|
|
|
|
lda #$FFFF
|
2021-10-24 03:31:38 +00:00
|
|
|
:loop2 stal spritemask,x
|
2021-10-21 13:50:07 +00:00
|
|
|
dex
|
|
|
|
dex
|
2021-10-29 02:52:48 +00:00
|
|
|
cpx #$FFFE
|
|
|
|
bne :loop2
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
; Initialize the VBuff offset values for the different cases. These are locations in
|
|
|
|
; the TileStoreLookup table, which has different dimensions than the underlying TileStore
|
|
|
|
; array
|
2022-06-06 16:23:00 +00:00
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
LAST_ROW equ {2*TS_LOOKUP_SPAN*{TILE_STORE_HEIGHT-1}}
|
|
|
|
NEXT_TO_LAST_ROW equ {2*TS_LOOKUP_SPAN*{TILE_STORE_HEIGHT-2}}
|
|
|
|
LAST_COL equ {{TILE_STORE_WIDTH-1}*2}
|
|
|
|
NEXT_TO_LAST_COL equ {{TILE_STORE_WIDTH-2}*2}
|
2022-06-06 16:23:00 +00:00
|
|
|
|
|
|
|
lda #0 ; Normal row, Normal column
|
|
|
|
ldx #0
|
|
|
|
jsr _SetVBuffValues
|
|
|
|
|
|
|
|
lda #8
|
|
|
|
ldx #LAST_COL ; Normal row, Last column
|
|
|
|
jsr _SetVBuffValues
|
|
|
|
|
|
|
|
lda #16
|
|
|
|
ldx #NEXT_TO_LAST_COL ; Normal row, Next-to-Last column
|
|
|
|
jsr _SetVBuffValues
|
|
|
|
|
|
|
|
lda #24 ; Last row, normal column
|
|
|
|
ldx #LAST_ROW
|
|
|
|
jsr _SetVBuffValues
|
2022-05-31 13:43:26 +00:00
|
|
|
|
2022-06-06 16:23:00 +00:00
|
|
|
lda #32
|
|
|
|
ldx #LAST_ROW+LAST_COL ; Last row, Last column
|
|
|
|
jsr _SetVBuffValues
|
|
|
|
|
|
|
|
lda #40
|
|
|
|
ldx #LAST_ROW+NEXT_TO_LAST_COL ; Last row, Next-to-Last column
|
|
|
|
jsr _SetVBuffValues
|
|
|
|
|
|
|
|
lda #48 ; Next-to-Last row, normal column
|
|
|
|
ldx #NEXT_TO_LAST_ROW
|
|
|
|
jsr _SetVBuffValues
|
|
|
|
|
|
|
|
lda #56
|
|
|
|
ldx #NEXT_TO_LAST_ROW+LAST_COL ; Next-to-Last row, Last column
|
|
|
|
jsr _SetVBuffValues
|
|
|
|
|
|
|
|
lda #64
|
|
|
|
ldx #NEXT_TO_LAST_ROW+NEXT_TO_LAST_COL ; Next-to-Last row, Next-to-Last column
|
|
|
|
jsr _SetVBuffValues
|
|
|
|
|
2022-06-02 18:59:15 +00:00
|
|
|
; Initialize the Page 2 pointers
|
|
|
|
ldx #$100
|
|
|
|
lda #^spritemask
|
|
|
|
sta sprite_ptr0+2,x
|
|
|
|
sta sprite_ptr1+2,x
|
|
|
|
sta sprite_ptr2+2,x
|
|
|
|
sta sprite_ptr3+2,x
|
|
|
|
|
2022-02-02 16:21:31 +00:00
|
|
|
; Precalculate some bank values
|
2022-06-02 18:06:26 +00:00
|
|
|
jsr _CacheSpriteBanks
|
|
|
|
rts
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
; Call with X-register set to TileStore tile and A set to the VBuff slot offset
|
2022-06-06 16:23:00 +00:00
|
|
|
_SetVBuffValues
|
|
|
|
COL_BYTES equ 4 ; VBUFF_TILE_COL_BYTES
|
|
|
|
ROW_BYTES equ 384 ; VBUFF_TILE_ROW_BYTES
|
|
|
|
|
|
|
|
clc
|
|
|
|
adc #VBuffArray
|
|
|
|
sec
|
|
|
|
sbc TileStoreLookup,x
|
|
|
|
sta tmp0
|
|
|
|
|
|
|
|
ldy TileStoreLookup,x
|
|
|
|
lda #{0*COL_BYTES}+{0*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
|
|
|
|
ldy TileStoreLookup+2,x
|
|
|
|
lda #{1*COL_BYTES}+{0*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
|
|
|
|
ldy TileStoreLookup+4,x
|
|
|
|
lda #{2*COL_BYTES}+{0*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
ldy TileStoreLookup+{1*{TS_LOOKUP_SPAN*2}},x
|
2022-06-06 16:23:00 +00:00
|
|
|
lda #{0*COL_BYTES}+{1*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
ldy TileStoreLookup+{1*{TS_LOOKUP_SPAN*2}}+2,x
|
2022-06-06 16:23:00 +00:00
|
|
|
lda #{1*COL_BYTES}+{1*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
ldy TileStoreLookup+{1*{TS_LOOKUP_SPAN*2}}+4,x
|
2022-06-06 16:23:00 +00:00
|
|
|
lda #{2*COL_BYTES}+{1*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
ldy TileStoreLookup+{2*{TS_LOOKUP_SPAN*2}},x
|
2022-06-06 16:23:00 +00:00
|
|
|
lda #{0*COL_BYTES}+{2*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
ldy TileStoreLookup+{2*{TS_LOOKUP_SPAN*2}}+2,x
|
2022-06-06 16:23:00 +00:00
|
|
|
lda #{1*COL_BYTES}+{2*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
|
2022-06-07 01:10:15 +00:00
|
|
|
ldy TileStoreLookup+{2*{TS_LOOKUP_SPAN*2}}+4,x
|
2022-06-06 16:23:00 +00:00
|
|
|
lda #{2*COL_BYTES}+{2*ROW_BYTES}
|
|
|
|
sta (tmp0),y
|
|
|
|
rts
|
2022-05-27 00:36:40 +00:00
|
|
|
; _RenderSprites
|
|
|
|
;
|
|
|
|
; The function is responsible for updating all of the rendering information based on any changes
|
|
|
|
; that occured to the sprites on this frame. Sprite handling is one of the most expensive and
|
|
|
|
; complicated pieces of the rendering pipeline, so these functions are aggressively simplified and
|
|
|
|
; optimized.
|
|
|
|
;
|
|
|
|
; The sprite rendering pipeline is:
|
|
|
|
;
|
|
|
|
; 0. Check if any new sprites have been added by testing the DIRTY_BIT_SPRITE_ARRAY. If so, then
|
|
|
|
; the activeSpriteList (a 32-byte array on the direct page) is rebuilt from the SpriteBits bitmap
|
|
|
|
; word.
|
|
|
|
;
|
|
|
|
; Next, the activeSpriteList is scanned for changes to specific sprites. If the screen has been
|
|
|
|
; scrolled, then every sprite is considered to have the SPRITE_STATUS_MOVED flag set.
|
|
|
|
;
|
|
|
|
; 1. If a sprite is marked as (SPRITE_STATUS_MOVED or SPRITE_STATUS_UPDATED or SPRITE_STATUS_ADDED) and not SPRITE_STATUS_REMOVED
|
|
|
|
; A. Calculate the TS_COVERAGE_SIZE, TS_LOOKUP_INDEX, and TS_VBUFF_BASE for the sprite
|
|
|
|
; B. For each tile the sprite overlaps with:
|
|
|
|
; i. Set its bit in the TileStore's TS_SPRITE_FLAG
|
|
|
|
; ii. Add the tile to the DirtyTile list
|
|
|
|
; iii. Set the VBUFF address for the sprite block
|
|
|
|
; C. If the sprite is not marked as SPRITE_STATUS_ADDED
|
|
|
|
; i. For each old tile the sprite overlaps with
|
|
|
|
; a. If it is not marked in the DirtyTile list
|
|
|
|
; * Clear its bit from the TileStore's TS_SPRITE_FLAG
|
|
|
|
; * Add the tile to the DirtyTile list
|
2023-01-08 07:30:51 +00:00
|
|
|
;
|
2022-05-27 00:36:40 +00:00
|
|
|
; 2. If a sprite is marked as SPRITE_STATUS_REMOVED, then
|
|
|
|
; A. Clear its bit from the SpriteBits bitmap
|
|
|
|
; B. For each tile the sprite overlaps with:
|
|
|
|
; i. Clear its bit from the TileStore's TS_SPRITE_FLAG
|
|
|
|
; ii. Add the tile to the DirtyTile list
|
|
|
|
; C. Clear the SPRITE_STATUS flags (work complete)
|
|
|
|
;
|
|
|
|
; 3. For each tile on the Dirty Tile list
|
|
|
|
; A. Place the sprite VBUFF addresses in TS_VBUFF_ADDR_0 through TS_VBUFF_ADDR_3 and set TS_VBUFF_ADDR_COUNT
|
|
|
|
;
|
|
|
|
; It is important that this work is done *prior* to any tile map updates so that we can interate over the
|
|
|
|
; DirtyTile list and *know* that it only contains tiles that are impacted by sprite changes.
|
|
|
|
_RenderSprites
|
|
|
|
|
|
|
|
; Check to see if any sprites have been added or removed. If so, then we regenerate the active
|
|
|
|
; sprite list. Since adding and removing sprites is rare, this is a worthwhile tradeoff, because
|
|
|
|
; there are several places where we want to iterate over the all of the sprites, and having a list
|
|
|
|
; and not have to constantly load and test the SPRITE_STATUS just to skip unused slots can help
|
|
|
|
; streamline the code.
|
|
|
|
|
|
|
|
lda #DIRTY_BIT_SPRITE_ARRAY
|
|
|
|
trb DirtyBits ; clears the flag, if it was set
|
|
|
|
beq :no_rebuild
|
|
|
|
jsr RebuildSpriteArray
|
|
|
|
|
|
|
|
:no_rebuild
|
|
|
|
|
|
|
|
; First step is to look at the StartX and StartY values. If the screen has scrolled, then it has
|
|
|
|
; the same effect as moving all of the sprites.
|
|
|
|
;
|
|
|
|
; OPTIMIZATION NOTE: Should check that the sprite actually changes position. If the screen scrolls
|
|
|
|
; by +X, but the sprite moves by -X (so it's relative position is unchanged), then
|
|
|
|
; it does NOT need to be marked as dirty.
|
|
|
|
|
|
|
|
stz ForceSpriteFlag
|
|
|
|
lda StartX
|
|
|
|
cmp OldStartX
|
|
|
|
bne :force_update
|
|
|
|
|
|
|
|
lda StartY
|
|
|
|
cmp OldStartY
|
|
|
|
beq :no_change
|
|
|
|
|
|
|
|
:force_update
|
|
|
|
lda #SPRITE_STATUS_MOVED
|
|
|
|
sta ForceSpriteFlag
|
|
|
|
:no_change
|
|
|
|
|
|
|
|
; Dispatch to the update process for sprites. By pre-building the list, we know exactly
|
|
|
|
; how many sprite to process and they are in a contiguous array. So we don't have to keep
|
|
|
|
; track of an iteration variable
|
|
|
|
|
|
|
|
ldx ActiveSpriteCount
|
|
|
|
jmp (phase1,x)
|
|
|
|
|
|
|
|
; 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
|
|
|
|
_DoPhase1
|
|
|
|
lda _Sprites+SPRITE_STATUS,y
|
|
|
|
ora ForceSpriteFlag
|
|
|
|
|
|
|
|
; 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.
|
|
|
|
|
|
|
|
bit #SPRITE_STATUS_REMOVED
|
|
|
|
beq :no_clear
|
|
|
|
|
|
|
|
lda _SpriteBits,y ; Clear from the sprite bitmap
|
|
|
|
sta SpriteRemovedFlag ; Stick a non-zero value here
|
|
|
|
trb SpriteMap
|
2022-05-31 13:43:26 +00:00
|
|
|
lda #SPRITE_STATUS_EMPTY ; Mark as empty so no error if we try to Add a sprite here again
|
|
|
|
sta _Sprites+SPRITE_STATUS,y
|
2023-01-02 17:04:26 +00:00
|
|
|
tyx
|
|
|
|
jsr _DeleteSprite ; Remove sprite from linked list
|
|
|
|
txy ; Restore y-register
|
2022-07-08 17:35:49 +00:00
|
|
|
:hidden
|
2023-01-02 17:04:26 +00:00
|
|
|
jmp _ClearSpriteFromTileStore ; Clear the tile flags, add to the dirty tile list and done
|
2022-07-08 17:35:49 +00:00
|
|
|
|
2022-05-27 00:36:40 +00:00
|
|
|
:no_clear
|
|
|
|
|
2022-07-07 22:22:44 +00:00
|
|
|
; 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
|
|
|
|
|
2022-05-27 00:36:40 +00:00
|
|
|
; If the sprite is marked as ADDED, then it does not need to have its old tile locations cleared
|
2022-06-01 12:50:19 +00:00
|
|
|
|
2022-05-27 00:36:40 +00:00
|
|
|
bit #SPRITE_STATUS_ADDED
|
2022-07-07 22:22:44 +00:00
|
|
|
bne :added
|
2022-06-01 12:50:19 +00:00
|
|
|
|
|
|
|
; 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.
|
|
|
|
|
|
|
|
bit #SPRITE_STATUS_MOVED
|
2022-07-07 22:22:44 +00:00
|
|
|
bne :moved
|
|
|
|
|
|
|
|
; Finally, see if it was updated. If not, return early
|
|
|
|
|
|
|
|
bit #SPRITE_STATUS_UPDATED
|
|
|
|
bne :updated
|
|
|
|
rts
|
2022-06-01 12:50:19 +00:00
|
|
|
|
2022-07-07 22:22:44 +00:00
|
|
|
:moved
|
2022-06-08 19:25:52 +00:00
|
|
|
phy
|
2022-06-01 18:55:04 +00:00
|
|
|
jsr _ClearSpriteFromTileStore
|
2022-06-08 19:25:52 +00:00
|
|
|
ply
|
2022-05-27 00:36:40 +00:00
|
|
|
|
|
|
|
; Anything else (MOVED, UPDATED, ADDED) will need to have the VBUFF information updated and the
|
|
|
|
; current tiles marked for update
|
2022-07-07 22:22:44 +00:00
|
|
|
:added
|
|
|
|
:updated
|
2022-06-08 19:25:52 +00:00
|
|
|
jsr _CalcDirtySprite ; This function preserves Y
|
|
|
|
|
2022-07-08 17:35:49 +00:00
|
|
|
lda #$FFFF!{SPRITE_STATUS_ADDED.SPRITE_STATUS_UPDATED.SPRITE_STATUS_MOVED}
|
|
|
|
and _Sprites+SPRITE_STATUS,y
|
|
|
|
sta _Sprites+SPRITE_STATUS,y ; Clear the dirty bits (ADDED, UPDATED, MOVED)
|
2022-06-01 12:50:19 +00:00
|
|
|
|
2022-05-27 00:36:40 +00:00
|
|
|
jmp _MarkDirtySpriteTiles
|
|
|
|
|
|
|
|
; Dispatch table. It's unintersting, so it's tucked out of the way
|
|
|
|
phase1 dw :phase1_0
|
|
|
|
dw :phase1_1,:phase1_2,:phase1_3,:phase1_4
|
|
|
|
dw :phase1_5,:phase1_6,:phase1_7,:phase1_8
|
|
|
|
dw :phase1_9,:phase1_10,:phase1_11,:phase1_12
|
|
|
|
dw :phase1_13,:phase1_14,:phase1_15,:phase1_16
|
|
|
|
:phase1_16 ldy activeSpriteList+30
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_15 ldy activeSpriteList+28
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_14 ldy activeSpriteList+26
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_13 ldy activeSpriteList+24
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_12 ldy activeSpriteList+22
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_11 ldy activeSpriteList+20
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_10 ldy activeSpriteList+18
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_9 ldy activeSpriteList+16
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_8 ldy activeSpriteList+14
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_7 ldy activeSpriteList+12
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_6 ldy activeSpriteList+10
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_5 ldy activeSpriteList+8
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_4 ldy activeSpriteList+6
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_3 ldy activeSpriteList+4
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_2 ldy activeSpriteList+2
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_1 ldy activeSpriteList
|
2022-05-31 13:43:26 +00:00
|
|
|
jmp _DoPhase1
|
|
|
|
:phase1_0 rts
|
2022-05-27 00:36:40 +00:00
|
|
|
|
2022-04-20 12:43:16 +00:00
|
|
|
; Utility function to calculate the difference in tile positions between a sprite's current
|
|
|
|
; position and it's previous position. This gets interesting because the number of tiles
|
|
|
|
; that a sprite covers can change based on the relative alignemen of the sprite with the
|
|
|
|
; background.
|
|
|
|
;
|
|
|
|
; Ideally, we would be able to quickly calculate exactly which new background tiles a sprite
|
|
|
|
; intersects with and which ones it has left to minimize the number of TileStore entries
|
|
|
|
; that need to be updated.
|
|
|
|
;
|
|
|
|
; In the short-term, we just do an equality test which lets us know if the sprite is
|
|
|
|
; covering the exact same tiles.
|
|
|
|
|
|
|
|
|
2022-04-23 05:47:13 +00:00
|
|
|
; Render a sprite stamp into the sprite buffer. Stamps exist independent of the sprites
|
2022-04-20 12:43:16 +00:00
|
|
|
; and sprite reference a specific stamp. This is necessary because it's common for a
|
2022-04-23 05:47:13 +00:00
|
|
|
; sprite to change its graphic as its animating, but it is too costly to have to set up
|
2022-04-20 12:43:16 +00:00
|
|
|
; the stamp every time. So this allows users to create stamps in advance and then
|
|
|
|
; assign them to the sprites as needed.
|
|
|
|
;
|
2023-03-01 19:18:37 +00:00
|
|
|
; Note that the user has full freedom to create a stamp at any VBUFF address, however,
|
2022-05-19 02:00:06 +00:00
|
|
|
; 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.
|
2022-04-20 12:43:16 +00:00
|
|
|
;
|
|
|
|
; Input:
|
|
|
|
; A = sprite descriptor
|
2022-05-19 02:00:06 +00:00
|
|
|
; 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.
|
2022-04-20 12:43:16 +00:00
|
|
|
_CreateSpriteStamp
|
|
|
|
pha ; Save the descriptor
|
|
|
|
jsr _GetBaseTileAddr ; Get the address of the tile data
|
|
|
|
|
2022-05-19 02:00:06 +00:00
|
|
|
tax ; Tile data address
|
2022-04-20 12:43:16 +00:00
|
|
|
pla ; Pop the sprite ID
|
2022-05-19 02:00:06 +00:00
|
|
|
jmp _DrawSpriteStamp ; Render the sprite data and create a stamp
|
2022-02-19 02:43:55 +00:00
|
|
|
|
|
|
|
; Add a new sprite to the rendering pipeline
|
|
|
|
;
|
|
|
|
; The tile id in the range 0 - 511. The top 7 bits are used as sprite control bits
|
|
|
|
;
|
|
|
|
; Bit 9 : Horizontal flip.
|
|
|
|
; Bit 10 : Vertical flip.
|
|
|
|
; Bits 11 - 12 : Sprite Size Selector
|
|
|
|
; 00 - 8x8 (1x1 tile)
|
|
|
|
; 01 - 8x16 (1x2 tiles)
|
|
|
|
; 10 - 16x8 (2x1 tiles)
|
|
|
|
; 11 - 16x16 (2x2 tiles)
|
2023-03-01 19:18:37 +00:00
|
|
|
; Bit 13 : Show/Hide sprite during rendering
|
|
|
|
; Bit 14 : Mark sprite as a compile sprite. SPRITE_DISP is treated as a compilation token.
|
2022-07-03 16:13:07 +00:00
|
|
|
; Bit 15 : Reserved. Must be zero.
|
|
|
|
; TBD: Bit 15 : Low Sprite priority. Draws behind high priority tiles.
|
2022-02-19 02:43:55 +00:00
|
|
|
;
|
|
|
|
; When a sprite has a size > 8x8, the horizontal tiles are taken from the next tile index and
|
|
|
|
; the vertical tiles are taken from tileId + 32. This is why tile sheets should be saved
|
|
|
|
; with a width of 256 pixels.
|
|
|
|
;
|
2023-03-01 19:18:37 +00:00
|
|
|
; A = Sprite ID / Flags
|
2022-02-25 23:05:32 +00:00
|
|
|
; Y = High Byte = x-pos, Low Byte = y-pos
|
|
|
|
; X = Sprite Slot (0 - 15)
|
2022-02-19 02:43:55 +00:00
|
|
|
_AddSprite
|
2022-02-25 23:05:32 +00:00
|
|
|
pha
|
|
|
|
txa
|
|
|
|
and #$000F
|
|
|
|
asl
|
|
|
|
tax
|
|
|
|
pla
|
2022-02-19 02:43:55 +00:00
|
|
|
|
|
|
|
sta _Sprites+SPRITE_ID,x ; Keep a copy of the full descriptor
|
|
|
|
|
2023-01-08 07:30:51 +00:00
|
|
|
lda #SPRITE_STATUS_ADDED ; Used to initialize the SPRITE_STATUS
|
2022-02-19 02:43:55 +00:00
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
|
|
|
|
2023-03-01 19:18:37 +00:00
|
|
|
lda #$FFFF
|
|
|
|
sta _Sprites+VBUFF_ADDR,x ; Clear the VBUFF address, just to initialize it
|
2022-04-20 12:43:16 +00:00
|
|
|
|
2022-02-25 23:05:32 +00:00
|
|
|
phy
|
2022-02-19 02:43:55 +00:00
|
|
|
tya
|
2022-02-25 23:05:32 +00:00
|
|
|
and #$00FF
|
2022-02-19 02:43:55 +00:00
|
|
|
sta _Sprites+SPRITE_Y,x ; Y coordinate
|
2022-02-25 23:05:32 +00:00
|
|
|
pla
|
|
|
|
xba
|
|
|
|
and #$00FF
|
|
|
|
sta _Sprites+SPRITE_X,x ; X coordinate
|
2022-02-19 02:43:55 +00:00
|
|
|
|
|
|
|
; Mark the dirty bit to indicate that the active sprite list needs to be rebuilt in the next
|
|
|
|
; render call
|
|
|
|
|
|
|
|
lda #DIRTY_BIT_SPRITE_ARRAY
|
|
|
|
tsb DirtyBits
|
|
|
|
|
|
|
|
lda _SpriteBits,x ; Get the bit flag for this sprite slot
|
|
|
|
tsb SpriteMap ; Mark it in the sprite map bit field
|
|
|
|
|
2023-01-08 07:30:51 +00:00
|
|
|
jsr _PrecalcSpriteSize ; Cache sprite property values
|
|
|
|
jsr _PrecalcSpriteBounds
|
|
|
|
|
2023-03-09 02:09:57 +00:00
|
|
|
jsr _InsertSprite ; Insert it into the sorted list
|
|
|
|
jmp _Validate
|
2022-09-09 02:51:00 +00:00
|
|
|
|
|
|
|
; _SortSprite
|
|
|
|
;
|
|
|
|
; Given a sprite's index, i, update the sprite permutation array such that p[j] = i where
|
|
|
|
; the sprite is the j.th sprite ordered by the SPRITE_CLIP_TOP value. It is important to
|
|
|
|
; note that the sorted sprite order does not impact rendering order (that is determined by
|
|
|
|
; the sprite index position), but is only used to calculate region of the screen to update
|
|
|
|
; and, in the future, may be useful for isometric perspectives where sorting order *is*
|
|
|
|
; determined by y-position
|
|
|
|
;
|
|
|
|
; X = current sprite index
|
|
|
|
;
|
2023-01-02 17:04:26 +00:00
|
|
|
; The sorting strategy is to
|
2022-09-09 02:51:00 +00:00
|
|
|
;
|
2023-01-02 17:04:26 +00:00
|
|
|
; a) check if the current slot's y-pos is greater than the next item. If yes, then search forward
|
2022-09-09 02:51:00 +00:00
|
|
|
; b) check if the current slot's y-pos is less than the prev item. If yes, then search in reverse
|
|
|
|
; c) sprite is in the correct location
|
|
|
|
;
|
|
|
|
; The heuristic in play here is that, usually sprites will only move one position in the sorted order
|
|
|
|
; between frames, if at all.
|
|
|
|
_SortSprite
|
|
|
|
lda _Sprites+SPRITE_CLIP_TOP,x
|
|
|
|
|
|
|
|
ldy _Sprites+SORTED_PREV,x
|
|
|
|
bmi :chk_fwd
|
|
|
|
cmp _Sprites+SPRITE_CLIP_TOP,y
|
2023-03-08 22:29:12 +00:00
|
|
|
bcc :scan_bkwd ; The current node needs to move to an lower position
|
2022-09-09 02:51:00 +00:00
|
|
|
|
|
|
|
:chk_fwd
|
|
|
|
ldy _Sprites+SORTED_NEXT,x ; If there is nothing ahead of the current node, we're done
|
|
|
|
bmi :early_out
|
|
|
|
cmp _Sprites+SPRITE_CLIP_TOP,y ; If the current node is <= the next node, we're done
|
|
|
|
bcc :early_out
|
|
|
|
bne :scan_fwd
|
|
|
|
|
|
|
|
:early_out
|
|
|
|
rts
|
|
|
|
|
|
|
|
; Look to move the sprite into a later position
|
|
|
|
:scan_fwd
|
|
|
|
lda _Sprites+SORTED_NEXT,y ; Need to step forward; if we're at the end, then insert here
|
|
|
|
bmi :insert_end
|
|
|
|
tay
|
|
|
|
lda _Sprites+SPRITE_CLIP_TOP,y ; Check against the next node. If it's less that current, keep going
|
|
|
|
cmp _Sprites+SPRITE_CLIP_TOP,x
|
|
|
|
bcc :scan_fwd
|
|
|
|
|
|
|
|
; Put X before Y
|
|
|
|
;
|
|
|
|
; Change
|
|
|
|
; a <=> x <=> b
|
|
|
|
; c <=> y <=> d
|
|
|
|
;
|
|
|
|
; Into
|
|
|
|
; a <=> b and c <=> x <=> y <=> d
|
|
|
|
:insert_before
|
2023-03-09 02:09:57 +00:00
|
|
|
jsr _ReleaseNode
|
2022-09-09 02:51:00 +00:00
|
|
|
|
|
|
|
tya
|
|
|
|
sta _Sprites+SORTED_NEXT,x ; Link X to Y
|
|
|
|
|
|
|
|
lda _Sprites+SORTED_PREV,y
|
|
|
|
sta _Sprites+SORTED_PREV,x ; Link X to C
|
|
|
|
|
|
|
|
txa ; Link Y to X
|
|
|
|
sta _Sprites+SORTED_PREV,y
|
|
|
|
|
|
|
|
ldy _Sprites+SORTED_PREV,x ; Link C to X
|
|
|
|
sta _Sprites+SORTED_NEXT,y
|
|
|
|
rts
|
|
|
|
|
|
|
|
; Move X to the end of the list. Y point to the last element
|
|
|
|
;
|
|
|
|
; ; Change
|
|
|
|
; a <=> x <=> b
|
|
|
|
; y -> nil
|
|
|
|
;
|
|
|
|
; Into
|
|
|
|
; a <=> b and y <=> x -> nil
|
|
|
|
:insert_end
|
2023-03-09 02:09:57 +00:00
|
|
|
jsr _ReleaseNode
|
2022-09-09 02:51:00 +00:00
|
|
|
|
|
|
|
lda #$FFFF
|
|
|
|
sta _Sprites+SORTED_NEXT,x
|
|
|
|
tya
|
|
|
|
sta _Sprites+SORTED_PREV,x
|
|
|
|
txa
|
|
|
|
sta _Sprites+SORTED_NEXT,y
|
|
|
|
rts
|
|
|
|
|
|
|
|
; Look to move the sprite into an earlier position
|
|
|
|
:scan_bkwd
|
|
|
|
lda _Sprites+SORTED_PREV,y ; Need to step backward; if we're at the beginning, then insert here
|
|
|
|
bmi :insert_front
|
|
|
|
tay
|
|
|
|
lda _Sprites+SPRITE_CLIP_TOP,x ; Check against the next node. If it's less that current, keep going
|
|
|
|
cmp _Sprites+SPRITE_CLIP_TOP,y
|
|
|
|
bcc :scan_bkwd
|
|
|
|
|
|
|
|
; Put X after Y
|
|
|
|
;
|
|
|
|
; Change
|
|
|
|
; a <=> x <=> b
|
|
|
|
; c <=> y <=> d
|
|
|
|
;
|
|
|
|
; Into
|
|
|
|
; a <=> b and c <=> y <=> x <=> d
|
|
|
|
:insert_after
|
2023-03-09 02:09:57 +00:00
|
|
|
jsr _ReleaseNode
|
2022-09-09 02:51:00 +00:00
|
|
|
|
|
|
|
tya
|
2023-03-08 22:29:12 +00:00
|
|
|
sta _Sprites+SORTED_PREV,x ; c <=> y <-- x --- d
|
2022-09-09 02:51:00 +00:00
|
|
|
|
2023-03-08 22:29:12 +00:00
|
|
|
lda _Sprites+SORTED_NEXT,y ; c <=> y <-- x --> d
|
|
|
|
sta _Sprites+SORTED_NEXT,x
|
2022-09-09 02:51:00 +00:00
|
|
|
|
2023-03-08 22:29:12 +00:00
|
|
|
txa
|
|
|
|
ldx _Sprites+SORTED_NEXT,y
|
|
|
|
sta _Sprites+SORTED_NEXT,y ; c <=> y <=> x --> d
|
2022-09-09 02:51:00 +00:00
|
|
|
|
2023-03-08 22:29:12 +00:00
|
|
|
sta _Sprites+SORTED_PREV,x ; c <=> y <=> x <=> d
|
2022-09-09 02:51:00 +00:00
|
|
|
rts
|
|
|
|
|
|
|
|
; Move X to the front of the list. Y points to the first element
|
|
|
|
;
|
|
|
|
; ; Change
|
|
|
|
; a <=> x <=> b
|
|
|
|
; head -> y
|
|
|
|
;
|
|
|
|
; Into
|
|
|
|
; a <=> b and head -> x <=> y
|
|
|
|
:insert_front
|
2023-03-09 02:09:57 +00:00
|
|
|
jsr _ReleaseNode
|
2022-09-09 02:51:00 +00:00
|
|
|
|
|
|
|
stx _SortedHead
|
|
|
|
txa
|
|
|
|
sta _Sprites+SORTED_PREV,y
|
|
|
|
lda #$FFFF
|
|
|
|
sta _Sprites+SORTED_PREV,x
|
|
|
|
tya
|
|
|
|
sta _Sprites+SORTED_NEXT,x
|
|
|
|
|
|
|
|
:done
|
|
|
|
rts
|
|
|
|
|
2023-03-09 02:09:57 +00:00
|
|
|
; Take the node pointed at X and remove it from the doubly-linked list.
|
|
|
|
_ReleaseNode
|
2022-09-09 02:51:00 +00:00
|
|
|
phy
|
2023-03-09 02:09:57 +00:00
|
|
|
jsr _DeleteSprite
|
2022-09-09 02:51:00 +00:00
|
|
|
ply
|
|
|
|
rts
|
|
|
|
|
|
|
|
; Add a new sprite into the sorted double-linked list
|
|
|
|
_InsertSprite
|
|
|
|
lda _SortedHead ; If the list is empty, just insert the sprite index
|
|
|
|
bmi :empty
|
|
|
|
|
|
|
|
tay ; Check the first item
|
|
|
|
lda _Sprites+SPRITE_CLIP_TOP,x
|
|
|
|
cmp _Sprites+SPRITE_CLIP_TOP,y
|
|
|
|
bcc :insert_head
|
|
|
|
|
|
|
|
:next
|
|
|
|
lda _Sprites+SORTED_NEXT,y
|
|
|
|
bmi :insert_tail
|
|
|
|
|
|
|
|
tay
|
|
|
|
lda _Sprites+SPRITE_CLIP_TOP,x
|
|
|
|
cmp _Sprites+SPRITE_CLIP_TOP,y
|
|
|
|
bcs :next
|
|
|
|
|
|
|
|
lda _Sprites+SORTED_PREV,y
|
|
|
|
sta _Sprites+SORTED_PREV,x ; [p] <-- [c] [n]
|
|
|
|
|
|
|
|
tya
|
|
|
|
sta _Sprites+SORTED_NEXT,x ; [p] <-- [c] --> [n]
|
|
|
|
|
|
|
|
txa
|
2023-03-08 22:29:12 +00:00
|
|
|
ldx _Sprites+SORTED_PREV,y ; get ref to the [p]revious node
|
2022-09-09 02:51:00 +00:00
|
|
|
sta _Sprites+SORTED_PREV,y ; [p] <-- [c] <=> [n]
|
|
|
|
|
2023-03-08 22:29:12 +00:00
|
|
|
sta _Sprites+SORTED_NEXT,x ; [p] <=> [c] <=> [n]
|
2022-09-09 02:51:00 +00:00
|
|
|
|
|
|
|
rts
|
|
|
|
|
|
|
|
:insert_head
|
|
|
|
stx _SortedHead
|
|
|
|
lda #$FFFF
|
|
|
|
sta _Sprites+SORTED_PREV,x
|
|
|
|
tya
|
|
|
|
sta _Sprites+SORTED_NEXT,x
|
|
|
|
txa
|
|
|
|
sta _Sprites+SORTED_PREV,y
|
|
|
|
rts
|
|
|
|
|
|
|
|
:insert_tail
|
|
|
|
txa
|
|
|
|
sta _Sprites+SORTED_NEXT,y
|
|
|
|
tya
|
|
|
|
sta _Sprites+SORTED_PREV,x
|
|
|
|
lda #$FFFF
|
|
|
|
sta _Sprites+SORTED_NEXT,x
|
|
|
|
rts
|
|
|
|
|
|
|
|
:empty
|
|
|
|
sta _Sprites+SORTED_NEXT,x
|
|
|
|
sta _Sprites+SORTED_PREV,x
|
|
|
|
stx _SortedHead
|
|
|
|
rts
|
|
|
|
|
|
|
|
; Remove a sprite from the double-linked list
|
|
|
|
_DeleteSprite
|
|
|
|
ldy _Sprites+SORTED_NEXT,x
|
|
|
|
bmi :remove_tail
|
|
|
|
|
|
|
|
cpx _SortedHead
|
|
|
|
beq :remove_head
|
|
|
|
|
|
|
|
lda _Sprites+SORTED_PREV,x
|
|
|
|
sta _Sprites+SORTED_PREV,y
|
|
|
|
|
|
|
|
tay
|
|
|
|
lda _Sprites+SORTED_NEXT,x
|
|
|
|
sta _Sprites+SORTED_NEXT,y
|
|
|
|
rts
|
|
|
|
|
|
|
|
:remove_head
|
|
|
|
sty _SortedHead
|
|
|
|
lda #$FFFF
|
|
|
|
sta _Sprites+SORTED_PREV,y
|
|
|
|
rts
|
|
|
|
|
|
|
|
:remove_tail
|
|
|
|
ldy _Sprites+SORTED_PREV,x
|
|
|
|
bmi :make_empty
|
|
|
|
|
|
|
|
lda #$FFFF
|
|
|
|
sta _Sprites+SORTED_NEXT,y
|
|
|
|
rts
|
|
|
|
|
|
|
|
:make_empty
|
|
|
|
lda #$FFFF
|
|
|
|
sta _SortedHead
|
|
|
|
rts
|
|
|
|
|
2023-03-09 02:09:57 +00:00
|
|
|
; Validate the integrity of the linked list
|
|
|
|
_Validate
|
|
|
|
:prev equ tmp0
|
|
|
|
:curr equ tmp1
|
|
|
|
|
|
|
|
ldy #$FFFF
|
|
|
|
ldx _SortedHead
|
|
|
|
bmi :done
|
|
|
|
:loop
|
|
|
|
sty :prev
|
|
|
|
stx :curr
|
|
|
|
|
|
|
|
lda _Sprites+SORTED_PREV,x
|
|
|
|
cmp :prev
|
|
|
|
beq *+4
|
|
|
|
brk $08
|
|
|
|
|
|
|
|
cpy #$FFFF
|
|
|
|
beq :skip
|
|
|
|
lda _Sprites+SORTED_NEXT,y
|
|
|
|
cmp :curr
|
|
|
|
beq *+4
|
|
|
|
brk $06
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_CLIP_TOP,x
|
|
|
|
cmp _Sprites+SPRITE_CLIP_TOP,y
|
|
|
|
bcs *+4
|
|
|
|
brk $0A
|
|
|
|
:skip
|
|
|
|
txy
|
|
|
|
lda _Sprites+SORTED_NEXT,x
|
|
|
|
tax
|
|
|
|
bpl :loop
|
2022-02-19 02:43:55 +00:00
|
|
|
|
2023-03-09 02:09:57 +00:00
|
|
|
:done
|
|
|
|
rts
|
2022-05-23 20:18:34 +00:00
|
|
|
; Macro to make the unrolled loop more concise
|
|
|
|
;
|
|
|
|
; 1. Load the tile store address from a fixed offset
|
|
|
|
; 2. Clears the sprite bit from the TS_SPRITE_FLAG location
|
|
|
|
; 3. Checks if the tile is dirty and marks it
|
|
|
|
; 4. If the tile was dirty, save the tile store address to be added to the DirtyTiles list later
|
|
|
|
TSClearSprite mac
|
2022-06-01 03:53:33 +00:00
|
|
|
ldy TileStoreLookup+{]1},x
|
2022-05-23 20:18:34 +00:00
|
|
|
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,y
|
2022-05-31 13:43:26 +00:00
|
|
|
and tmp0
|
2022-05-23 20:18:34 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,y
|
|
|
|
|
|
|
|
lda TileStore+TS_DIRTY,y
|
|
|
|
bne next
|
|
|
|
inc
|
|
|
|
sta TileStore+TS_DIRTY,y
|
2022-05-27 00:36:40 +00:00
|
|
|
|
|
|
|
tya
|
|
|
|
ldy DirtyTileCount
|
|
|
|
sta DirtyTiles,y
|
|
|
|
iny
|
|
|
|
iny
|
|
|
|
sty DirtyTileCount
|
2022-05-23 20:18:34 +00:00
|
|
|
next
|
|
|
|
<<<
|
|
|
|
|
2022-04-20 12:43:16 +00:00
|
|
|
; Alternate implementation that uses the TS_COVERAGE_SIZE and TS_LOOKUP_INDEX properties to
|
|
|
|
; load the old values directly from the TileStoreLookup table, rather than caching them.
|
|
|
|
; This is more efficient, because the work in MarkDirtySprite is independent of the
|
|
|
|
; sprite size and, by inlining the _PushDirtyTile logic, we can save a fair amount of overhead
|
2022-05-23 20:18:34 +00:00
|
|
|
_ClearSpriteFromTileStore
|
|
|
|
lda _SpriteBitsNot,y ; Cache this value in a direct page location
|
|
|
|
sta tmp0
|
2022-06-08 19:25:52 +00:00
|
|
|
ldx _Sprites+TS_COVERAGE_SIZE,y
|
2022-04-20 12:43:16 +00:00
|
|
|
jmp (csfts_tbl,x)
|
|
|
|
csfts_tbl dw csfts_1x1,csfts_1x2,csfts_1x3,csfts_out
|
|
|
|
dw csfts_2x1,csfts_2x2,csfts_2x3,csfts_out
|
|
|
|
dw csfts_3x1,csfts_3x2,csfts_3x3,csfts_out
|
|
|
|
dw csfts_out,csfts_out,csfts_out,csfts_out
|
|
|
|
|
2022-05-27 00:36:40 +00:00
|
|
|
csfts_out rts
|
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_3x3 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
|
|
|
TSClearSprite 2
|
|
|
|
TSClearSprite 4
|
2022-06-01 12:50:19 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+2
|
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+4
|
2022-06-01 12:50:19 +00:00
|
|
|
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+0
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+2
|
|
|
|
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+4
|
2022-05-27 00:36:40 +00:00
|
|
|
rts
|
2022-05-23 20:18:34 +00:00
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_3x2 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
|
|
|
TSClearSprite 2
|
2022-06-01 12:50:19 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+2
|
2022-06-01 12:50:19 +00:00
|
|
|
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+0
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+2
|
2022-05-27 00:36:40 +00:00
|
|
|
rts
|
2022-05-23 20:18:34 +00:00
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_3x1 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
2022-06-01 12:50:19 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
|
|
|
|
TSClearSprite 2*{TS_LOOKUP_SPAN*2}+0
|
2022-05-27 00:36:40 +00:00
|
|
|
rts
|
2022-05-23 20:18:34 +00:00
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_2x3 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
|
|
|
TSClearSprite 2
|
|
|
|
TSClearSprite 4
|
2022-06-01 12:50:19 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+2
|
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+4
|
2022-05-27 00:36:40 +00:00
|
|
|
rts
|
2022-05-23 20:18:34 +00:00
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_2x2 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
|
|
|
TSClearSprite 2
|
2022-06-01 12:50:19 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+2
|
2022-05-27 00:36:40 +00:00
|
|
|
rts
|
2022-05-23 20:18:34 +00:00
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_2x1 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
2022-06-01 12:50:19 +00:00
|
|
|
TSClearSprite 1*{TS_LOOKUP_SPAN*2}+0
|
2022-05-27 00:36:40 +00:00
|
|
|
rts
|
2022-05-23 20:18:34 +00:00
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_1x3 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
|
|
|
TSClearSprite 2
|
|
|
|
TSClearSprite 4
|
2022-05-27 00:36:40 +00:00
|
|
|
rts
|
2022-05-23 20:18:34 +00:00
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_1x2 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
|
|
|
TSClearSprite 2
|
2022-05-27 00:36:40 +00:00
|
|
|
rts
|
2022-04-20 12:43:16 +00:00
|
|
|
|
2022-06-08 19:25:52 +00:00
|
|
|
csfts_1x1 ldx _Sprites+TS_LOOKUP_INDEX,y
|
2022-05-23 20:18:34 +00:00
|
|
|
TSClearSprite 0
|
2022-02-07 07:19:31 +00:00
|
|
|
rts
|
2021-11-22 19:26:25 +00:00
|
|
|
|
2022-02-18 18:12:32 +00:00
|
|
|
; Use the blttmp space to build the active sprite list. Since the sprite tiles are not drawn until later,
|
|
|
|
; it's OK to use that scratch space here. And it's just the right size, 32 bytes
|
2022-02-07 07:19:31 +00:00
|
|
|
RebuildSpriteArray
|
|
|
|
lda SpriteMap ; Get the bit field
|
2022-02-18 18:12:32 +00:00
|
|
|
|
2022-04-20 12:43:16 +00:00
|
|
|
; Unrolled loop to get the sprite index values that correspond to the set bit positions
|
2022-02-18 18:12:32 +00:00
|
|
|
|
|
|
|
pea $FFFF ; end-of-list marker
|
|
|
|
]step equ 0
|
|
|
|
lup 4
|
2022-02-21 16:31:35 +00:00
|
|
|
lsr
|
2022-02-18 18:12:32 +00:00
|
|
|
bcc :skip_1
|
|
|
|
pea ]step
|
2022-02-21 16:31:35 +00:00
|
|
|
:skip_1 lsr
|
2022-02-18 18:12:32 +00:00
|
|
|
bcc :skip_2
|
|
|
|
pea ]step+2
|
2022-02-21 16:31:35 +00:00
|
|
|
:skip_2 lsr
|
2022-02-18 18:12:32 +00:00
|
|
|
bcc :skip_3
|
|
|
|
pea ]step+4
|
2022-02-21 16:31:35 +00:00
|
|
|
:skip_3 lsr
|
2022-02-18 18:12:32 +00:00
|
|
|
bcc :skip_4
|
|
|
|
pea ]step+6
|
|
|
|
:skip_4 beq :end_1
|
|
|
|
]step equ ]step+8
|
2022-02-07 07:19:31 +00:00
|
|
|
--^
|
2022-02-18 18:12:32 +00:00
|
|
|
:end_1
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-18 18:12:32 +00:00
|
|
|
; Now pop the values off of the stack until reaching the sentinel value. This could be unrolled, but
|
|
|
|
; it is only done once per frame.
|
|
|
|
|
|
|
|
ldx #0
|
|
|
|
:loop
|
|
|
|
pla
|
|
|
|
bmi :out
|
2022-02-21 16:31:35 +00:00
|
|
|
sta activeSpriteList,x
|
2022-02-18 18:12:32 +00:00
|
|
|
inx
|
|
|
|
inx
|
|
|
|
bra :loop
|
|
|
|
:out
|
|
|
|
stx ActiveSpriteCount
|
2022-02-07 07:19:31 +00:00
|
|
|
rts
|
|
|
|
|
2021-10-21 13:50:07 +00:00
|
|
|
; _GetTileAt
|
|
|
|
;
|
|
|
|
; Given a relative playfield coordinate [0, ScreenWidth), [0, ScreenHeight) return the
|
|
|
|
; X = horizontal point [0, ScreenTileWidth]
|
|
|
|
; Y = vertical point [0, ScreenTileHeight]
|
|
|
|
;
|
|
|
|
; Return
|
|
|
|
; C = 1, out of range
|
|
|
|
; C = 0, X = column, Y = row
|
|
|
|
_GetTileAt
|
|
|
|
cpx ScreenWidth
|
|
|
|
bcc *+3
|
|
|
|
rts
|
|
|
|
|
|
|
|
cpy ScreenHeight
|
|
|
|
bcc *+3
|
|
|
|
rts
|
|
|
|
|
|
|
|
tya ; carry is clear here
|
|
|
|
adc StartYMod208 ; This is the code field line that is at the top of the screen
|
|
|
|
cmp #208
|
|
|
|
bcc *+5
|
|
|
|
sbc #208
|
|
|
|
|
|
|
|
lsr
|
|
|
|
lsr
|
|
|
|
lsr
|
|
|
|
tay ; This is the code field row for this point
|
|
|
|
|
|
|
|
clc
|
|
|
|
txa
|
|
|
|
adc StartXMod164
|
|
|
|
cmp #164
|
|
|
|
bcc *+5
|
|
|
|
sbc #164
|
|
|
|
|
|
|
|
lsr
|
|
|
|
lsr
|
|
|
|
tax ; Could call _CopyBG0Tile with these arguments
|
|
|
|
|
|
|
|
clc
|
|
|
|
rts
|
|
|
|
|
2022-02-22 08:35:21 +00:00
|
|
|
; Small initialization routine to cache the banks for the sprite data and mask and tile/sprite stuff
|
2022-02-02 16:21:31 +00:00
|
|
|
_CacheSpriteBanks
|
|
|
|
lda #>spritemask
|
|
|
|
and #$FF00
|
|
|
|
ora #^spritedata
|
|
|
|
sta SpriteBanks
|
2022-02-22 08:35:21 +00:00
|
|
|
|
|
|
|
lda #$0100
|
|
|
|
ora #^TileStore
|
|
|
|
sta TileStoreBankAndBank01
|
|
|
|
|
|
|
|
lda #>tiledata
|
|
|
|
and #$FF00
|
|
|
|
ora #^TileStore
|
|
|
|
sta TileStoreBankAndTileDataBank
|
|
|
|
|
2022-06-12 10:28:12 +00:00
|
|
|
xba
|
|
|
|
ldx #$100
|
|
|
|
sta DP2_TILEDATA_AND_TILESTORE_BANKS,x ; put a reversed copy in the second direct page
|
2022-07-05 04:55:32 +00:00
|
|
|
and #$FF00
|
|
|
|
ora #$0001
|
|
|
|
sta DP2_BANK01_AND_TILESTORE_BANKS,x ; put a value with bank 01 and the tile store
|
2022-06-12 10:28:12 +00:00
|
|
|
|
2022-06-20 20:55:09 +00:00
|
|
|
lda #>spritedata
|
|
|
|
and #$FF00
|
|
|
|
ora #^tiledata
|
|
|
|
sta DP2_TILEDATA_AND_SPRITEDATA_BANKS,x
|
|
|
|
|
2022-06-14 13:12:33 +00:00
|
|
|
lda #>spritedata
|
|
|
|
and #$FF00
|
|
|
|
ora #^TileStore
|
|
|
|
xba
|
|
|
|
ldx #$100
|
|
|
|
sta DP2_SPRITEDATA_AND_TILESTORE_BANKS,x ; put a reversed copy in the second direct page
|
|
|
|
|
2022-04-20 12:43:16 +00:00
|
|
|
lda #>TileStore
|
|
|
|
and #$FF00
|
|
|
|
ora #^TileStore
|
|
|
|
sta TileStoreBankDoubled
|
|
|
|
|
2022-02-02 16:21:31 +00:00
|
|
|
rts
|
|
|
|
|
2023-02-27 21:30:56 +00:00
|
|
|
; Precalculate some cached values for a sprite. These are *only* to make other parts of code,
|
2022-02-04 18:37:05 +00:00
|
|
|
; specifically the draw/erase routines more efficient.
|
|
|
|
;
|
|
|
|
; X = sprite index
|
2023-01-08 07:30:51 +00:00
|
|
|
_PrecalcSpriteVBuff
|
2023-03-01 19:18:37 +00:00
|
|
|
lda _Sprites+SPRITE_ID,x ; Compiled sprites use the SPRITE_DISP as a fixed address to compiled code
|
|
|
|
bit #SPRITE_COMPILED
|
|
|
|
bne :compiled
|
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
xba
|
2022-04-20 12:43:16 +00:00
|
|
|
and #$0006
|
2022-06-02 17:28:49 +00:00
|
|
|
tay
|
|
|
|
lda _Sprites+VBUFF_ADDR,x
|
2022-05-27 00:36:40 +00:00
|
|
|
clc
|
2022-06-02 17:28:49 +00:00
|
|
|
adc _stamp_step,y
|
2023-03-01 19:18:37 +00:00
|
|
|
sta _Sprites+SPRITE_DISP,x ; Interpreted as an address in the VBUFF bank
|
|
|
|
rts
|
|
|
|
|
|
|
|
:compiled
|
|
|
|
xba
|
|
|
|
and #$0006 ; Pick the address from the table of 4 values. Can use this value directly
|
|
|
|
clc ; as an index
|
|
|
|
adc _Sprites+VBUFF_ADDR,x
|
|
|
|
tay
|
|
|
|
lda [CompileBank0],y
|
|
|
|
sta _Sprites+SPRITE_DISP,x ; Interpreted as an address in the CompileBank
|
|
|
|
rts
|
|
|
|
|
|
|
|
; Compile the four stamps and keep a reference to the addresses. We take the current CompileBankTop address and allocate 8 bytes
|
|
|
|
; of memory. Then compile each stamp and save the compilation address in the header area. Finally, the DISP_ADDR is set
|
|
|
|
; to that value and the SPRITE_COMPILED bit is set in the SPRITE_ID word.
|
|
|
|
;
|
|
|
|
; A = sprite Id
|
|
|
|
; X = vbuff base address
|
|
|
|
_CompileStampSet
|
|
|
|
:height equ tmp8
|
|
|
|
:width equ tmp9
|
|
|
|
:base equ tmp10
|
|
|
|
:output equ tmp11
|
|
|
|
:addrs equ tmp12 ; 4 words (tmp12, tmp13, tmp14 and tmp15)
|
|
|
|
|
|
|
|
; Save the base address
|
|
|
|
stx :base
|
|
|
|
|
|
|
|
; Initialize the height and width based on the sprite flags
|
|
|
|
|
|
|
|
ldy #8
|
|
|
|
sty :height
|
|
|
|
ldx #4
|
|
|
|
stx :width
|
|
|
|
|
|
|
|
bit #$1000 ; wide flag
|
|
|
|
beq :skinny
|
|
|
|
ldx #8
|
|
|
|
stx :width
|
|
|
|
:skinny
|
|
|
|
|
|
|
|
bit #$0800 ; tall flag
|
|
|
|
beq :short
|
|
|
|
ldy #16
|
|
|
|
sty :height
|
|
|
|
:short
|
|
|
|
|
|
|
|
lda CompileBankTop
|
|
|
|
sta :output ; Save the current address as the return value
|
|
|
|
|
|
|
|
clc
|
|
|
|
adc #8
|
|
|
|
sta CompileBankTop ; Allocate space for the 4 addresses return by _CompileStamp
|
|
|
|
|
|
|
|
; ldy :height ; X and Y are already set for the first call
|
|
|
|
; ldx :width
|
|
|
|
lda :base
|
|
|
|
jsr _CompileStamp ; Compile into the bank
|
|
|
|
sta :addrs ; Save the address temporarily
|
|
|
|
|
|
|
|
ldy :height
|
|
|
|
ldx :width
|
|
|
|
clc
|
|
|
|
lda :base
|
|
|
|
adc _stamp_step+2
|
|
|
|
jsr _CompileStamp
|
|
|
|
sta :addrs+2
|
|
|
|
|
|
|
|
ldy :height
|
|
|
|
ldx :width
|
|
|
|
clc
|
|
|
|
lda :base
|
|
|
|
adc _stamp_step+4
|
|
|
|
jsr _CompileStamp
|
|
|
|
sta :addrs+4
|
|
|
|
|
|
|
|
ldy :height
|
|
|
|
ldx :width
|
|
|
|
clc
|
|
|
|
lda :base
|
|
|
|
adc _stamp_step+6
|
|
|
|
jsr _CompileStamp
|
|
|
|
sta :addrs+6
|
|
|
|
|
|
|
|
; Now the sprite stamps are all compiled. Set the bank to the compilation bank and fill in the header
|
|
|
|
|
|
|
|
phb
|
|
|
|
|
|
|
|
ldy :output
|
|
|
|
pei CompileBank
|
|
|
|
plb
|
|
|
|
|
|
|
|
lda :addrs
|
|
|
|
sta: 0,y
|
|
|
|
lda :addrs+2
|
|
|
|
sta: 2,y
|
|
|
|
lda :addrs+4
|
|
|
|
sta: 4,y
|
|
|
|
lda :addrs+6
|
|
|
|
sta: 6,y
|
|
|
|
|
|
|
|
plb
|
|
|
|
plb
|
|
|
|
|
|
|
|
tya ; Put the output value into the accumulator
|
|
|
|
clc ; No error
|
2023-01-08 07:30:51 +00:00
|
|
|
rts
|
2022-02-07 07:19:31 +00:00
|
|
|
|
2023-01-08 07:30:51 +00:00
|
|
|
_PrecalcSpriteSize
|
2022-02-21 19:33:39 +00:00
|
|
|
; Set the sprite's width and height
|
|
|
|
lda #4
|
|
|
|
sta _Sprites+SPRITE_WIDTH,x
|
|
|
|
lda #8
|
|
|
|
sta _Sprites+SPRITE_HEIGHT,x
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_ID,x
|
|
|
|
bit #$1000 ; width select
|
|
|
|
beq :width_4
|
|
|
|
lda #8
|
|
|
|
sta _Sprites+SPRITE_WIDTH,x
|
|
|
|
:width_4
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_ID,x
|
2022-06-02 17:28:49 +00:00
|
|
|
bit #$0800 ; height select
|
2022-02-21 19:33:39 +00:00
|
|
|
beq :height_8
|
|
|
|
lda #16
|
|
|
|
sta _Sprites+SPRITE_HEIGHT,x
|
|
|
|
:height_8
|
2022-09-09 02:51:00 +00:00
|
|
|
rts
|
2022-02-21 19:33:39 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; Clip the sprite's bounding box to the play field size and also set a flag if the sprite
|
2022-02-21 19:33:39 +00:00
|
|
|
; is fully off-screen or not
|
2023-01-08 07:30:51 +00:00
|
|
|
_PrecalcSpriteBounds
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_X,x
|
|
|
|
bpl :pos_x
|
|
|
|
lda #0
|
|
|
|
:pos_x cmp ScreenWidth
|
|
|
|
bcs :offscreen ; sprite is off-screen, exit early
|
|
|
|
sta _Sprites+SPRITE_CLIP_LEFT,x
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_Y,x
|
|
|
|
bpl :pos_y
|
|
|
|
lda #0
|
|
|
|
:pos_y cmp ScreenHeight
|
|
|
|
bcs :offscreen ; sprite is off-screen, exit early
|
|
|
|
sta _Sprites+SPRITE_CLIP_TOP,x
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_X,x
|
|
|
|
clc
|
2022-02-21 19:33:39 +00:00
|
|
|
adc _Sprites+SPRITE_WIDTH,x
|
|
|
|
dec
|
2022-02-07 07:19:31 +00:00
|
|
|
bmi :offscreen
|
|
|
|
cmp ScreenWidth
|
|
|
|
bcc :ok_x
|
|
|
|
lda ScreenWidth
|
|
|
|
dec
|
|
|
|
:ok_x sta _Sprites+SPRITE_CLIP_RIGHT,x
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_Y,x
|
|
|
|
clc
|
2022-02-21 19:33:39 +00:00
|
|
|
adc _Sprites+SPRITE_HEIGHT,x
|
|
|
|
dec
|
2022-02-07 07:19:31 +00:00
|
|
|
bmi :offscreen
|
|
|
|
cmp ScreenHeight
|
|
|
|
bcc :ok_y
|
|
|
|
lda ScreenHeight
|
|
|
|
dec
|
|
|
|
:ok_y sta _Sprites+SPRITE_CLIP_BOTTOM,x
|
|
|
|
|
2022-02-21 19:33:39 +00:00
|
|
|
stz _Sprites+IS_OFF_SCREEN,x ; passed all of the off-screen tests
|
|
|
|
|
|
|
|
; Calculate the clipped width and height
|
|
|
|
lda _Sprites+SPRITE_CLIP_RIGHT,x
|
|
|
|
sec
|
|
|
|
sbc _Sprites+SPRITE_CLIP_LEFT,x
|
|
|
|
inc
|
|
|
|
sta _Sprites+SPRITE_CLIP_WIDTH,x
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_CLIP_BOTTOM,x
|
|
|
|
sec
|
|
|
|
sbc _Sprites+SPRITE_CLIP_TOP,x
|
|
|
|
inc
|
|
|
|
sta _Sprites+SPRITE_CLIP_HEIGHT,x
|
2022-05-31 21:31:44 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
rts
|
|
|
|
|
|
|
|
:offscreen
|
|
|
|
lda #1
|
|
|
|
sta _Sprites+IS_OFF_SCREEN,x
|
2022-02-04 18:37:05 +00:00
|
|
|
rts
|
|
|
|
|
2022-01-20 02:58:57 +00:00
|
|
|
; Remove a sprite from the list. Just mark its STATUS as FREE and it will be
|
2022-02-03 14:50:11 +00:00
|
|
|
; picked up in the next AddSprite.
|
2022-01-20 02:58:57 +00:00
|
|
|
;
|
|
|
|
; A = Sprite ID
|
|
|
|
_RemoveSprite
|
2022-04-20 12:43:16 +00:00
|
|
|
cmp #MAX_SPRITES
|
|
|
|
bcc :ok
|
|
|
|
rts
|
|
|
|
|
|
|
|
:ok
|
|
|
|
asl
|
2022-02-03 14:50:11 +00:00
|
|
|
tax
|
2022-01-20 02:58:57 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_STATUS,x
|
|
|
|
ora #SPRITE_STATUS_REMOVED
|
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
2022-04-20 12:43:16 +00:00
|
|
|
|
2023-01-02 17:04:26 +00:00
|
|
|
rts ; The _DeleteSprite call is made in _DoPhase1 during the next render
|
2022-01-20 02:58:57 +00:00
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
; Update the sprite's flags. We do not allow the size of a sprite to be changed. That requires
|
2021-11-20 18:16:03 +00:00
|
|
|
; the sprite to be removed and re-added.
|
|
|
|
;
|
2022-05-23 04:54:47 +00:00
|
|
|
; A = Sprite slot
|
2022-04-20 12:43:16 +00:00
|
|
|
; X = New Sprite Flags
|
2023-03-01 19:18:37 +00:00
|
|
|
; Y = New Sprite Stamp Address | New Compiled Sprite Token
|
2021-11-20 18:16:03 +00:00
|
|
|
_UpdateSprite
|
2022-04-20 12:43:16 +00:00
|
|
|
cmp #MAX_SPRITES
|
2021-11-20 18:16:03 +00:00
|
|
|
bcc :ok
|
|
|
|
rts
|
|
|
|
|
|
|
|
:ok
|
2022-04-20 12:43:16 +00:00
|
|
|
phx ; Save X to swap into A
|
|
|
|
asl
|
|
|
|
tax
|
|
|
|
pla
|
2022-02-23 14:41:02 +00:00
|
|
|
|
2022-05-31 21:31:44 +00:00
|
|
|
; Do some work to see if only the H or V bits have changed. If so, merge them into the
|
|
|
|
; SPRITE_ID
|
|
|
|
eor _Sprites+SPRITE_ID,x ; If either bit has changed, this will be non-zero
|
2022-07-08 17:35:49 +00:00
|
|
|
and #SPRITE_VFLIP+SPRITE_HFLIP+SPRITE_HIDE
|
2022-05-31 21:31:44 +00:00
|
|
|
bne :sprite_flag_change
|
|
|
|
|
2022-04-20 12:43:16 +00:00
|
|
|
tya
|
2022-07-08 17:35:49 +00:00
|
|
|
cmp _Sprites+VBUFF_ADDR,x ; Did the stamp change?
|
2022-04-20 12:43:16 +00:00
|
|
|
bne :sprite_stamp_change
|
|
|
|
rts ; Nothing changed, so just return
|
2021-11-20 18:16:03 +00:00
|
|
|
|
2022-04-20 12:43:16 +00:00
|
|
|
:sprite_flag_change
|
2022-05-31 21:31:44 +00:00
|
|
|
eor _Sprites+SPRITE_ID,x ; put the new bits into the value. ---HV--- ^ SPRITE_ID & 00011000 ^ SPRITE_ID = SSSHVSSS
|
2022-04-20 12:43:16 +00:00
|
|
|
sta _Sprites+SPRITE_ID,x ; Keep a copy of the full descriptor
|
2022-07-08 17:35:49 +00:00
|
|
|
|
|
|
|
bit #SPRITE_HIDE ; Sync the SPRITE_HIDE bit into the SPRITE_STATUS_HIDDEN flag
|
|
|
|
beq :not_hidden
|
|
|
|
lda #SPRITE_STATUS_HIDDEN
|
|
|
|
ora _Sprites+SPRITE_STATUS,x
|
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
|
|
|
bra :sync_complete
|
|
|
|
:not_hidden lda #$FFFF!SPRITE_STATUS_HIDDEN
|
|
|
|
and _Sprites+SPRITE_STATUS,x
|
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
|
|
|
:sync_complete
|
|
|
|
|
2022-04-20 12:43:16 +00:00
|
|
|
tya
|
|
|
|
:sprite_stamp_change
|
2022-07-08 17:35:49 +00:00
|
|
|
sta _Sprites+VBUFF_ADDR,x ; Just save this to stay in sync
|
2022-02-04 18:37:05 +00:00
|
|
|
|
2022-04-20 12:43:16 +00:00
|
|
|
lda _Sprites+SPRITE_STATUS,x ; Mark this sprite as updated
|
2022-02-07 07:19:31 +00:00
|
|
|
ora #SPRITE_STATUS_UPDATED
|
2021-11-20 18:16:03 +00:00
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
|
|
|
|
2023-01-08 07:30:51 +00:00
|
|
|
jmp _PrecalcSpriteVBuff ; Cache stuff and return
|
2021-11-20 18:16:03 +00:00
|
|
|
|
2021-10-24 03:31:38 +00:00
|
|
|
; Move a sprite to a new location. If the tile ID of the sprite needs to be changed, then
|
|
|
|
; a full remove/add cycle needs to happen
|
|
|
|
;
|
2022-06-02 17:28:49 +00:00
|
|
|
; A = sprite slot
|
2021-10-24 03:31:38 +00:00
|
|
|
; X = x position
|
|
|
|
; Y = y position
|
2021-11-20 18:16:03 +00:00
|
|
|
_MoveSprite
|
2022-04-20 12:43:16 +00:00
|
|
|
cmp #MAX_SPRITES
|
2021-10-24 03:31:38 +00:00
|
|
|
bcc :ok
|
|
|
|
rts
|
|
|
|
|
|
|
|
:ok
|
2022-04-20 12:43:16 +00:00
|
|
|
phx ; Save X to swap into A
|
|
|
|
asl
|
|
|
|
tax
|
|
|
|
pla
|
|
|
|
|
2022-02-21 21:45:11 +00:00
|
|
|
cmp _Sprites+SPRITE_X,x
|
|
|
|
bne :changed1
|
2022-02-04 05:44:46 +00:00
|
|
|
tya
|
2022-02-21 21:45:11 +00:00
|
|
|
cmp _Sprites+SPRITE_Y,x
|
|
|
|
bne :changed2
|
|
|
|
rts
|
2022-02-03 14:50:11 +00:00
|
|
|
|
2022-02-21 21:45:11 +00:00
|
|
|
:changed1
|
|
|
|
sta _Sprites+SPRITE_X,x ; Update the X coordinate
|
|
|
|
tya
|
|
|
|
:changed2
|
|
|
|
sta _Sprites+SPRITE_Y,x ; Update the Y coordinate
|
2022-02-18 18:12:32 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_STATUS,x
|
|
|
|
ora #SPRITE_STATUS_MOVED
|
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
2021-10-24 03:31:38 +00:00
|
|
|
|
2023-01-08 07:30:51 +00:00
|
|
|
jsr _PrecalcSpriteBounds ; Can be specialized to only update (x,y) values
|
2023-03-09 02:09:57 +00:00
|
|
|
jsr _SortSprite ; Update the sprite's sorted position
|
|
|
|
jmp _Validate
|