Add in all linked list operations
This commit is contained in:
parent
eaedee546e
commit
b8a7641307
|
@ -275,5 +275,6 @@ ScalingTables EXT
|
|||
StartXMod164Arr EXT
|
||||
LastPatchOffsetArr EXT
|
||||
|
||||
_SortedHead EXT
|
||||
; Tool error codes
|
||||
NO_TIMERS_AVAILABLE equ 10
|
||||
|
|
275
src/Sprite.s
275
src/Sprite.s
|
@ -397,8 +397,6 @@ _AddSprite
|
|||
and #$00FF
|
||||
sta _Sprites+SPRITE_X,x ; X coordinate
|
||||
|
||||
jsr _PrecalcAllSpriteInfo ; Cache sprite property values (simple stuff)
|
||||
|
||||
; Mark the dirty bit to indicate that the active sprite list needs to be rebuilt in the next
|
||||
; render call
|
||||
|
||||
|
@ -408,7 +406,266 @@ _AddSprite
|
|||
lda _SpriteBits,x ; Get the bit flag for this sprite slot
|
||||
tsb SpriteMap ; Mark it in the sprite map bit field
|
||||
|
||||
rts
|
||||
jmp _PrecalcAllSpriteInfo ; Cache sprite property values
|
||||
|
||||
; _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
|
||||
;
|
||||
; The sorting strategy is to
|
||||
;
|
||||
; a) check if the corrent slot's y-pos is greater than the next item. If yes, then search forward
|
||||
; 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
|
||||
bcc :chk_bkwd ; The current node needs to move to an lower position
|
||||
|
||||
: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
|
||||
jsr _OrphanNode
|
||||
|
||||
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
|
||||
jsr _OrphanNode
|
||||
|
||||
lda #$FFFF
|
||||
sta _Sprites+SORTED_NEXT,x
|
||||
tya
|
||||
sta _Sprites+SORTED_PREV,x
|
||||
txa
|
||||
sta _Sprites+SORTED_NEXT,y
|
||||
rts
|
||||
|
||||
:chk_bkwd
|
||||
ldy _Sprites+SORTED_PREV,x ; If there is nothing behind the current node, we're done
|
||||
bmi :done
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,y ; If the current node is >= the previous node, we're done
|
||||
bcs :done
|
||||
|
||||
; 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
|
||||
jsr _OrphanNode
|
||||
|
||||
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 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
|
||||
jsr _OrphanNode
|
||||
|
||||
stx _SortedHead
|
||||
txa
|
||||
sta _Sprites+SORTED_PREV,y
|
||||
lda #$FFFF
|
||||
sta _Sprites+SORTED_PREV,x
|
||||
tya
|
||||
sta _Sprites+SORTED_NEXT,x
|
||||
rts
|
||||
|
||||
:done
|
||||
rts
|
||||
|
||||
; Take the node pointed at X and remove it from the doubly-linked list. Assumes it is not
|
||||
; at the beginning or end of the list
|
||||
_OrphanNode
|
||||
phy
|
||||
ldy _Sprites+SORTED_PREV,x ; Remove X from between A and B
|
||||
lda _Sprites+SORTED_NEXT,x
|
||||
sta _Sprites+SORTED_NEXT,y
|
||||
tay
|
||||
lda _Sprites+SORTED_PREV,x
|
||||
sta _Sprites+SORTED_PREV,y
|
||||
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
|
||||
|
||||
:insert
|
||||
lda _Sprites+SORTED_PREV,y
|
||||
sta _Sprites+SORTED_PREV,x ; [p] <-- [c] [n]
|
||||
|
||||
tya
|
||||
sta _Sprites+SORTED_NEXT,x ; [p] <-- [c] --> [n]
|
||||
|
||||
txa
|
||||
sta _Sprites+SORTED_PREV,y ; [p] <-- [c] <=> [n]
|
||||
|
||||
ldy _Sprites+SORTED_PREV,x
|
||||
sta _Sprites+SORTED_NEXT,y ; [p] <=> [c] <=> [n]
|
||||
|
||||
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
|
||||
|
||||
|
||||
; Macro to make the unrolled loop more concise
|
||||
;
|
||||
|
@ -651,6 +908,10 @@ _CacheSpriteBanks
|
|||
;
|
||||
; X = sprite index
|
||||
_PrecalcAllSpriteInfo
|
||||
jsr _PrecalcSpriteState
|
||||
jmp _PrecalcSpritePos
|
||||
|
||||
_PrecalcSpriteState
|
||||
lda _Sprites+SPRITE_ID,x
|
||||
; and #$3E00
|
||||
xba
|
||||
|
@ -681,10 +942,11 @@ _PrecalcAllSpriteInfo
|
|||
lda #16
|
||||
sta _Sprites+SPRITE_HEIGHT,x
|
||||
:height_8
|
||||
rts
|
||||
|
||||
; Clip the sprite's bounding box to the play field size and also set a flag if the sprite
|
||||
; is fully off-screen or not
|
||||
|
||||
_PrecalcSpritePos
|
||||
lda _Sprites+SPRITE_X,x
|
||||
bpl :pos_x
|
||||
lda #0
|
||||
|
@ -813,7 +1075,7 @@ _UpdateSprite
|
|||
ora #SPRITE_STATUS_UPDATED
|
||||
sta _Sprites+SPRITE_STATUS,x
|
||||
|
||||
jmp _PrecalcAllSpriteInfo ; Cache stuff and return
|
||||
jmp _PrecalcSpriteState ; Cache stuff and return
|
||||
|
||||
; 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
|
||||
|
@ -849,4 +1111,5 @@ _MoveSprite
|
|||
ora #SPRITE_STATUS_MOVED
|
||||
sta _Sprites+SPRITE_STATUS,x
|
||||
|
||||
jmp _PrecalcAllSpriteInfo ; Can be specialized to only update (x,y) values
|
||||
jsr _PrecalcSpritePos ; Can be specialized to only update (x,y) values
|
||||
jmp _SortSprite ; UPdate the sprite's sorted position
|
||||
|
|
|
@ -19,8 +19,7 @@ _ScanlineBG0XPos
|
|||
:base_address equ tmp8
|
||||
:opcode equ tmp9
|
||||
:odd_entry_offset equ tmp10
|
||||
|
||||
brk $AB
|
||||
|
||||
lda StartYMod208 ; This is the base line of the virtual screen
|
||||
asl
|
||||
sta :virt_line_x2 ; Keep track of it
|
||||
|
|
|
@ -503,6 +503,13 @@ _SpriteBits ENT
|
|||
_SpriteBitsNot ENT
|
||||
dw $FFFE,$FFFD,$FFFB,$FFF7,$FFEF,$FFDF,$FFBF,$FF7F,$FEFF,$FDFF,$FBFF,$F7FF,$EFFF,$DFFF,$BFFF,$7FFF
|
||||
|
||||
; Doubly linked list that allows the sprites to be traversed in SPRITE_CLIP_TOP order. The prev/next
|
||||
; index links are stored in the parallel _Sprites structure; just the extra head and tail index values
|
||||
; are stored here. A negative value is used as a setinel
|
||||
_SortedHead ENT
|
||||
dw $FFFF
|
||||
;_SortedTail dw $FFFF
|
||||
|
||||
; Steps to the different sprite stamps
|
||||
_stamp_step ENT
|
||||
dw 0,12,24,36
|
||||
|
|
|
@ -62,7 +62,9 @@ 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
|
||||
;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
|
||||
SORTED_PREV equ {MAX_SPRITES*36}
|
||||
SORTED_NEXT equ {MAX_SPRITES*38}
|
||||
|
||||
; 52 rows by 82 columns + 2 extra rows and columns for sprite sizes
|
||||
;
|
||||
|
|
Loading…
Reference in New Issue