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
|
|
|
;
|
2021-10-21 13:50:07 +00:00
|
|
|
; The sprite plane actually covers two banks so that more than 32K can be used as a virtual
|
|
|
|
; screen buffer. In order to be able to draw sprites offscreen, the virtual screen must be
|
|
|
|
; wider and taller than the physical graphics screen.
|
|
|
|
;
|
2022-02-07 07:19:31 +00:00
|
|
|
; NOTE: It may be posible to remove the sprite plane banks in the future and render directly from
|
|
|
|
; some small per-sprite graphic buffers. This would eliminate the need to erase/draw in
|
|
|
|
; the sprite planes and all drawing would go directly to the backing tiles. Need to
|
|
|
|
; figure out an efficient way to fall back when sprites are overlapping, though.
|
2022-02-03 14:50:11 +00:00
|
|
|
;
|
2022-02-07 07:19:31 +00:00
|
|
|
; All of the erasing must happen in an initial phase, because erasing a sprite could cause
|
|
|
|
; other sprites to be marked as "DAMAGED" which means they need to be drawn (similar to NEW state)
|
2022-02-03 14:50:11 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; What really has to happen in the various cases:
|
|
|
|
;
|
|
|
|
; When a sprite is added, it needs to
|
|
|
|
; * draw into the sprite buffer
|
|
|
|
; * add itself to the TS_SPRITE_FLAG bitfield on the tiles it occupies
|
|
|
|
; * mark the tiles it occupies as dirty
|
|
|
|
;
|
|
|
|
; When a sprite is updated (Tile ID or H/V flip flags), it needs to
|
|
|
|
; * erase itself from the sprite buffer
|
|
|
|
; * draw into the sprite buffer
|
|
|
|
; * mark the tiles it occupies as dirty
|
|
|
|
; * mark other sprites it intersects as DAMAGED
|
|
|
|
;
|
|
|
|
; When a sprite is moved, it needs to
|
|
|
|
; * erase itself from the sprite buffer at the old locations
|
|
|
|
; * remove itself from the TS_SPRITE_FLAG bitfields on the tiles it occupied
|
|
|
|
; * mark sprites that intersect as DAMAGED
|
|
|
|
; * draw into the sprite buffer at the new location
|
|
|
|
; * add itself to the TS_SPRITE_FLAG bitfield on the tiles it now occupies
|
|
|
|
; * mark the tiles it occupied as dirty
|
|
|
|
; * mark other sprites it intersects as DAMAGED
|
|
|
|
;
|
|
|
|
; When a sprite is removed, it needs to
|
|
|
|
; * erase itself from the sprite buffer at the old locations
|
|
|
|
; * remove itself from the TS_SPRITE_FLAG bitfields on the tiles it occupied
|
|
|
|
; * mark other sprites it intersects as DAMAGED
|
|
|
|
;
|
|
|
|
; The reason that things are broken into phases is that we have to handle all of the erasing first,
|
|
|
|
; set dirty tiles, identify DAMAGED sprites, and THEN perform the drawing. It is not possible to
|
|
|
|
; just do each sprite one at a time.
|
|
|
|
;
|
2021-10-21 13:50:07 +00:00
|
|
|
; Initialize the sprite plane 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
|
|
|
|
2021-11-02 04:36:53 +00:00
|
|
|
; Clear values in the sprite array
|
|
|
|
|
|
|
|
ldx #{MAX_SPRITES-1}*2
|
|
|
|
:loop3 stz _Sprites+TILE_STORE_ADDR_1,x
|
|
|
|
dex
|
|
|
|
dex
|
|
|
|
bpl :loop3
|
|
|
|
|
2022-02-02 16:21:31 +00:00
|
|
|
; Precalculate some bank values
|
|
|
|
jsr _CacheSpriteBanks
|
2021-10-21 13:50:07 +00:00
|
|
|
rts
|
|
|
|
|
2021-11-21 03:58:09 +00:00
|
|
|
; Run through the list of tile store offsets that this sprite was last drawn into and mark
|
|
|
|
; those tiles as dirty. The largest number of tiles that a sprite could possibly cover is 20
|
|
|
|
; (an unaligned 4x3 sprite), covering a 5x4 area of play field tiles.
|
|
|
|
;
|
|
|
|
; Y register = sprite record index
|
|
|
|
_ClearSpriteFromTileStore
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_1,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x ; Clear the bit in the bit field. This seems wasteful, but
|
|
|
|
and _SpriteBitsNot,y ; there is no indexed form of TSB/TRB and caching the value in
|
2022-02-07 07:19:31 +00:00
|
|
|
tsb DamagedSprites ; Mark which other sprites are impacted by this one
|
2021-11-21 03:58:09 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,x ; a direct page location, only saves 1 or 2 cycles per and costs 10.
|
|
|
|
jsr _PushDirtyTileX
|
|
|
|
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_2,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x
|
|
|
|
and _SpriteBitsNot,y
|
2022-02-07 07:19:31 +00:00
|
|
|
tsb DamagedSprites
|
2021-11-21 03:58:09 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,x
|
|
|
|
jsr _PushDirtyTileX
|
|
|
|
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_3,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x
|
|
|
|
and _SpriteBitsNot,y
|
2022-02-07 07:19:31 +00:00
|
|
|
tsb DamagedSprites
|
2021-11-21 03:58:09 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,x
|
|
|
|
jsr _PushDirtyTileX
|
|
|
|
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_4,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x
|
|
|
|
and _SpriteBitsNot,y
|
2022-02-07 07:19:31 +00:00
|
|
|
tsb DamagedSprites
|
2021-11-21 03:58:09 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,x
|
|
|
|
jsr _PushDirtyTileX
|
|
|
|
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_5,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x
|
|
|
|
and _SpriteBitsNot,y
|
|
|
|
sta TileStore+TS_SPRITE_FLAG,x
|
|
|
|
jsr _PushDirtyTileX
|
|
|
|
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_6,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x
|
|
|
|
and _SpriteBitsNot,y
|
2022-02-07 07:19:31 +00:00
|
|
|
tsb DamagedSprites
|
2021-11-21 03:58:09 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,x
|
|
|
|
jsr _PushDirtyTileX
|
|
|
|
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_7,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x
|
|
|
|
and _SpriteBitsNot,y
|
2022-02-07 07:19:31 +00:00
|
|
|
tsb DamagedSprites
|
2021-11-21 03:58:09 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,x
|
|
|
|
jsr _PushDirtyTileX
|
|
|
|
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_8,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x
|
|
|
|
and _SpriteBitsNot,y
|
2022-02-07 07:19:31 +00:00
|
|
|
tsb DamagedSprites
|
2021-11-21 03:58:09 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,x
|
|
|
|
jsr _PushDirtyTileX
|
|
|
|
|
|
|
|
ldx _Sprites+TILE_STORE_ADDR_9,y
|
|
|
|
bne *+3
|
|
|
|
rts
|
|
|
|
lda TileStore+TS_SPRITE_FLAG,x
|
|
|
|
and _SpriteBitsNot,y
|
2022-02-07 07:19:31 +00:00
|
|
|
tsb DamagedSprites
|
2021-11-21 03:58:09 +00:00
|
|
|
sta TileStore+TS_SPRITE_FLAG,x
|
|
|
|
jmp _PushDirtyTileX
|
2021-10-21 13:50:07 +00:00
|
|
|
|
|
|
|
; This function looks at the sprite list and renders the sprite plane data into the appropriate
|
2021-11-21 03:58:09 +00:00
|
|
|
; tiles in the code field. There are a few phases to this routine. The assumption is that
|
2022-02-04 18:37:05 +00:00
|
|
|
; any sprite that needs to be re-drawn has been marked as DIRTY or DAMAGED.
|
|
|
|
;
|
|
|
|
; A DIRTY sprite is one that has moved, so it needs to be erased/redrawn in the sprite
|
|
|
|
; buffer AND the tiles it covers marked for refresh. A DAMAGED sprite shared one or more
|
|
|
|
; tiles with a DIRTY sprite, so it needs to be redraw in the sprite buffer (but not erased!)
|
|
|
|
; and its tile do NOT need to be marked for refresh.
|
2021-11-21 03:58:09 +00:00
|
|
|
;
|
|
|
|
; In the first phase, we run through the list of dirty sprites and erase them from their
|
2022-02-02 16:21:31 +00:00
|
|
|
; OLD_VBUFF_ADDR. This clears the sprite plane buffers. We also iterate through the
|
2021-11-21 03:58:09 +00:00
|
|
|
; TILE_STORE_ADDR_X array and mark all of the tile store location that this sprite had occupied
|
|
|
|
; as dirty, as well as removing this sprite from the TS_SPRITE_FLAG bitfield.
|
|
|
|
;
|
2022-02-03 14:50:11 +00:00
|
|
|
; A final aspect is that any of the sprites indicated in the TS_SPRITE_FLAG are marked to be
|
2021-11-21 03:58:09 +00:00
|
|
|
; drawn in the next phase (since a portion of their content may have been erased if they overlap)
|
|
|
|
;
|
|
|
|
; In the second phase, the sprite is re-drawn into the sprite plane buffers and the appropriate
|
2022-02-02 16:21:31 +00:00
|
|
|
; Tile Store locations are marked as dirty. It is important to recognize that the sprites themselves
|
|
|
|
; can be marked dirty, and the underlying tiles in the tile store are independently marked dirty.
|
2021-10-31 20:42:59 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
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
|
|
|
|
jsr _DoPhase1
|
|
|
|
:phase1_0
|
|
|
|
jmp phase1_rtn
|
|
|
|
|
|
|
|
; If this sprite has been MOVED or REMOVED, then clear its bit from the TS_SPRITE_FLAG in
|
|
|
|
; all of the tile store locations that it occupied on the previous frame and add those
|
|
|
|
; tile store locations to the dirty tile list.
|
|
|
|
_DoPhase1
|
2022-02-04 18:37:05 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_STATUS,y
|
|
|
|
ora forceSpriteFlag
|
|
|
|
bit #SPRITE_STATUS_MOVED+SPRITE_STATUS_REMOVED
|
|
|
|
beq :no_clear
|
|
|
|
jsr _ClearSpriteFromTileStore
|
|
|
|
:no_clear
|
2022-02-04 18:37:05 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; If this sprite has been MOVED, UPDATED or REMOVED, then it needs to be erased from the
|
|
|
|
; sprite plane buffer
|
2022-02-04 18:37:05 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_STATUS,y
|
|
|
|
bit #SPRITE_STATUS_MOVED+SPRITE_STATUS_UPDATED+SPRITE_STATUS_REMOVED
|
|
|
|
beq :no_erase
|
2021-11-21 03:58:09 +00:00
|
|
|
jsr _EraseSpriteY
|
2022-02-07 07:19:31 +00:00
|
|
|
:no_erase
|
2021-11-21 03:58:09 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; Check to see if sprite was REMOVED If so, then this is where we return its Sprite ID to the
|
|
|
|
; list of open slots
|
2021-11-21 03:58:09 +00:00
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
lda _Sprites+SPRITE_STATUS,y
|
2022-02-07 07:19:31 +00:00
|
|
|
bit #SPRITE_STATUS_REMOVED
|
|
|
|
beq :out
|
2022-02-03 14:50:11 +00:00
|
|
|
|
2022-02-04 05:44:46 +00:00
|
|
|
lda #SPRITE_STATUS_EMPTY ; Mark as empty
|
|
|
|
sta _Sprites+SPRITE_STATUS,y
|
2022-02-03 14:50:11 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _SpriteBits,y ; Clear from the sprite bitmap
|
|
|
|
trb SpriteMap
|
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
ldx _OpenListHead
|
|
|
|
dex
|
|
|
|
dex
|
|
|
|
stx _OpenListHead
|
2022-02-04 05:44:46 +00:00
|
|
|
tya
|
|
|
|
sta _OpenList,x
|
|
|
|
sty _NextOpenSlot
|
2022-02-07 07:19:31 +00:00
|
|
|
:out
|
|
|
|
rts
|
2022-02-03 14:50:11 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; Second phase takes care of drawing the sprites and marking the tiles that will need to be merged
|
|
|
|
; with pixel data from the sprite plane
|
|
|
|
phase2 dw :phase2_0
|
|
|
|
dw :phase2_1,:phase2_2,:phase2_3,:phase2_4
|
|
|
|
dw :phase2_5,:phase2_6,:phase2_7,:phase2_8
|
|
|
|
dw :phase2_9,:phase2_10,:phase2_11,:phase2_12
|
|
|
|
dw :phase2_13,:phase2_14,:phase2_15,:phase2_16
|
|
|
|
|
|
|
|
:phase2_16
|
|
|
|
ldy activeSpriteList+30
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_15
|
|
|
|
ldy activeSpriteList+28
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_14
|
|
|
|
ldy activeSpriteList+26
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_13
|
|
|
|
ldy activeSpriteList+24
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_12
|
|
|
|
ldy activeSpriteList+22
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_11
|
|
|
|
ldy activeSpriteList+20
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_10
|
|
|
|
ldy activeSpriteList+18
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_9
|
|
|
|
ldy activeSpriteList+16
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_8
|
|
|
|
ldy activeSpriteList+14
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_7
|
|
|
|
ldy activeSpriteList+12
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_6
|
|
|
|
ldy activeSpriteList+10
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_5
|
|
|
|
ldy activeSpriteList+8
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_4
|
|
|
|
ldy activeSpriteList+6
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_3
|
|
|
|
ldy activeSpriteList+4
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_2
|
|
|
|
ldy activeSpriteList+2
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_1
|
|
|
|
ldy activeSpriteList
|
|
|
|
jsr _DoPhase2
|
|
|
|
:phase2_0
|
|
|
|
jmp phase2_rtn
|
|
|
|
|
|
|
|
_DoPhase2
|
|
|
|
lda _Sprites+SPRITE_STATUS,y
|
2021-10-31 20:42:59 +00:00
|
|
|
ora forceSpriteFlag
|
2022-02-07 07:19:31 +00:00
|
|
|
and #SPRITE_STATUS_ADDED+SPRITE_STATUS_MOVED+SPRITE_STATUS_UPDATED
|
|
|
|
beq :out
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2021-10-27 05:14:19 +00:00
|
|
|
; This is the complicated part; we need to draw the sprite into the sprite plane, but then
|
2021-11-11 23:06:38 +00:00
|
|
|
; calculate the tiles that overlap with the sprite potentially and mark those as dirty _AND_
|
|
|
|
; store the appropriate sprite plane address from which those tiles need to copy.
|
2022-02-07 07:19:31 +00:00
|
|
|
;
|
|
|
|
; Mark the appropriate tiles as dirty and as occupied by a sprite so that the ApplyTiles
|
|
|
|
; subroutine will get the drawn data from the sprite plane into the code field where it
|
|
|
|
; can be drawn to the screen
|
|
|
|
|
|
|
|
jsr _MarkDirtySprite
|
2021-10-29 03:18:33 +00:00
|
|
|
|
2022-02-04 05:44:46 +00:00
|
|
|
; Draw the sprite into the sprite plane buffer(s)
|
2021-10-29 03:18:33 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_DISP2,y ; use bits 9, 10, 11, 12, and 13 to dispatch
|
|
|
|
jmp (draw_sprite,x)
|
|
|
|
:out
|
|
|
|
rts
|
2021-11-22 19:26:25 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; Optimization: Could use 8-bit registers to save
|
|
|
|
RebuildSpriteArray
|
|
|
|
ldx #0 ; Number of non-empty sprite locations
|
|
|
|
lda SpriteMap ; Get the bit field
|
|
|
|
tay ; Cache to restore
|
|
|
|
|
|
|
|
bit #$0001 ; For each bit position, test and store a value
|
|
|
|
beq :chk1
|
|
|
|
stz activeSpriteList ; Shortcut for the first one
|
|
|
|
ldx #2
|
|
|
|
|
|
|
|
; A super-optimization here would be to put the activeSpriteList on the direct page (32 bytes) and then
|
|
|
|
; use PEA instructions to push the slot values. Calculate the count at the end based on the final stack
|
|
|
|
; address. Only 160 cycles to build the list.
|
|
|
|
:chk1
|
|
|
|
]flag equ $0002
|
|
|
|
]slot equ $0002
|
|
|
|
lup 15
|
|
|
|
bit #]flag
|
|
|
|
beq :chk2
|
|
|
|
lda #]slot
|
|
|
|
sta activeSpriteList,x
|
|
|
|
tya
|
|
|
|
inx
|
|
|
|
inx
|
|
|
|
:chk2
|
|
|
|
]flag equ ]flag*2
|
|
|
|
]slot equ ]slot+2
|
|
|
|
--^
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
stx activeSpriteCount
|
|
|
|
rts
|
|
|
|
|
|
|
|
forceSpriteFlag ds 2
|
|
|
|
_RenderSprites
|
|
|
|
|
|
|
|
stz DamagedSprites ; clear the potential set of damaged sprites
|
|
|
|
|
|
|
|
; 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 interative over the all of the sprites, and having a list
|
|
|
|
; and not have to contantly 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 first phase of rendering the sprites. By pre-building the list, we know exactly
|
|
|
|
; how many sprite to process and they are in a contiguous array. So we on't have to keep track
|
|
|
|
; of an iterating variable
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
ldx activeSpriteCount
|
|
|
|
jmp (phase1,x)
|
|
|
|
phase1_rtn
|
2021-11-02 04:36:53 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; Dispatch to the second phase of rendering the sprites.
|
|
|
|
ldx activeSpriteCount
|
|
|
|
jmp (phase2,x)
|
|
|
|
phase2_rtn
|
|
|
|
|
|
|
|
; Speite rendering complete
|
|
|
|
rts
|
2021-10-29 02:41:01 +00:00
|
|
|
|
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-04 18:37:05 +00:00
|
|
|
; Y = _Sprites array offset
|
2021-11-20 19:54:19 +00:00
|
|
|
_EraseSpriteY
|
|
|
|
lda _Sprites+OLD_VBUFF_ADDR,y
|
|
|
|
beq :noerase
|
2022-02-04 18:37:05 +00:00
|
|
|
ldx _Sprites+SPRITE_DISP,y ; get the dispatch index for this sprite
|
|
|
|
jmp (:do_erase,x)
|
2021-11-20 19:54:19 +00:00
|
|
|
:noerase rts
|
2022-02-04 18:37:05 +00:00
|
|
|
:do_erase dw _EraseTileSprite8x8,_EraseTileSprite8x16
|
|
|
|
dw _EraseTileSprite16x8,_EraseTileSprite16x16
|
2021-11-20 19:54:19 +00:00
|
|
|
|
|
|
|
|
2021-11-20 18:00:21 +00:00
|
|
|
; X = _Sprites array offset
|
2021-11-22 19:26:25 +00:00
|
|
|
_DrawSpriteYA
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_DISP2,y ; use bits 9, 10, 11 and 12,13 to dispatch
|
|
|
|
jmp (draw_sprite,x)
|
|
|
|
|
|
|
|
draw_sprite dw draw_8x8,draw_8x8h,draw_8x8v,draw_8x8hv
|
2021-11-20 18:00:21 +00:00
|
|
|
dw draw_8x16,draw_8x16h,draw_8x16v,draw_8x16hv
|
|
|
|
dw draw_16x8,draw_16x8h,draw_16x8v,draw_16x8hv
|
2021-11-20 19:26:00 +00:00
|
|
|
dw draw_16x16,draw_16x16h,draw_16x16v,draw_16x16hv
|
2021-11-20 18:00:21 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
dw :rtn,:rtn,:rtn,:rtn ; hidden bit is set
|
|
|
|
dw :rtn,:rtn,:rtn,:rtn
|
|
|
|
dw :rtn,:rtn,:rtn,:rtn
|
|
|
|
dw :rtn,:rtn,:rtn,:rtn
|
|
|
|
:rtn rts
|
|
|
|
|
2021-11-20 18:00:21 +00:00
|
|
|
draw_8x8
|
|
|
|
draw_8x8h
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
tay
|
|
|
|
jmp _DrawTile8x8
|
|
|
|
|
|
|
|
draw_8x8v
|
|
|
|
draw_8x8hv
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
tay
|
|
|
|
jmp _DrawTile8x8V
|
|
|
|
|
|
|
|
draw_8x16
|
|
|
|
draw_8x16h
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8
|
|
|
|
clc
|
|
|
|
txa
|
|
|
|
adc #{8*SPRITE_PLANE_SPAN}
|
|
|
|
tax
|
|
|
|
tya
|
2022-02-02 16:21:31 +00:00
|
|
|
adc #{128*32} ; 32 tiles to the next vertical one, each tile is 128 bytes
|
2021-11-20 18:00:21 +00:00
|
|
|
tay
|
|
|
|
jmp _DrawTile8x8
|
|
|
|
|
|
|
|
draw_8x16v
|
|
|
|
draw_8x16hv
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
clc
|
|
|
|
txa
|
|
|
|
adc #{8*SPRITE_PLANE_SPAN}
|
|
|
|
tax
|
|
|
|
tya
|
|
|
|
adc #{128*32}
|
|
|
|
tay
|
|
|
|
jmp _DrawTile8x8V
|
|
|
|
|
|
|
|
draw_16x8
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8
|
|
|
|
clc
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
tya
|
|
|
|
adc #128 ; Next tile is 128 bytes away
|
|
|
|
tay
|
|
|
|
jmp _DrawTile8x8
|
|
|
|
|
|
|
|
draw_16x8h
|
|
|
|
clc
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
pha
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
ply
|
|
|
|
jmp _DrawTile8x8
|
|
|
|
|
|
|
|
draw_16x8v
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
clc
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
tya
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jmp _DrawTile8x8V
|
|
|
|
|
|
|
|
draw_16x8hv
|
|
|
|
clc
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
pha
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
ply
|
|
|
|
jmp _DrawTile8x8V
|
|
|
|
|
|
|
|
draw_16x16
|
|
|
|
clc
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
tay
|
2022-01-20 02:58:57 +00:00
|
|
|
jmp _DrawTile16x16
|
|
|
|
|
|
|
|
; jsr _DrawTile8x8
|
2021-11-20 18:00:21 +00:00
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
tya
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8
|
|
|
|
txa
|
|
|
|
adc #{8*SPRITE_PLANE_SPAN}-4
|
|
|
|
tax
|
|
|
|
tya
|
|
|
|
adc #{128*{32-1}}
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
tya
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jmp _DrawTile8x8
|
|
|
|
|
|
|
|
draw_16x16h
|
|
|
|
clc
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
pha
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8
|
|
|
|
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
ply
|
|
|
|
jsr _DrawTile8x8
|
|
|
|
|
|
|
|
txa
|
|
|
|
adc #{8*SPRITE_PLANE_SPAN}-4
|
|
|
|
tax
|
|
|
|
tya
|
|
|
|
adc #{128*32}
|
|
|
|
pha
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8
|
|
|
|
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
ply
|
|
|
|
jmp _DrawTile8x8
|
|
|
|
|
2021-11-20 19:26:00 +00:00
|
|
|
draw_16x16v
|
|
|
|
clc
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
pha ; store some copies
|
|
|
|
phx
|
|
|
|
pha
|
|
|
|
adc #{128*32}
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
|
|
|
|
txa
|
|
|
|
adc #{8*SPRITE_PLANE_SPAN}
|
|
|
|
tax
|
|
|
|
ply
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
|
|
|
|
pla
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
lda 1,s
|
|
|
|
adc #{128*{32+1}}
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
|
|
|
|
txa
|
|
|
|
adc #{8*SPRITE_PLANE_SPAN}
|
|
|
|
tax
|
|
|
|
pla
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jmp _DrawTile8x8V
|
|
|
|
|
|
|
|
; TODO
|
|
|
|
draw_16x16hv
|
|
|
|
clc
|
|
|
|
ldx _Sprites+VBUFF_ADDR,y
|
|
|
|
lda _Sprites+TILE_DATA_OFFSET,y
|
|
|
|
pha
|
|
|
|
adc #128+{128*32} ; Bottom-right source to top-left
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
lda 1,s
|
|
|
|
adc #{128*32}
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
|
|
|
|
txa
|
|
|
|
adc #{8*SPRITE_PLANE_SPAN}-4
|
|
|
|
tax
|
|
|
|
lda 1,s
|
|
|
|
adc #128
|
|
|
|
tay
|
|
|
|
jsr _DrawTile8x8V
|
|
|
|
|
|
|
|
txa
|
|
|
|
adc #4
|
|
|
|
tax
|
|
|
|
ply
|
|
|
|
jmp _DrawTile8x8V
|
|
|
|
|
2021-10-29 02:41:01 +00:00
|
|
|
DrawTileSprite ENT
|
2021-11-20 18:00:21 +00:00
|
|
|
jsr _DrawTile8x8
|
2021-10-29 02:41:01 +00:00
|
|
|
rtl
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-04 05:44:46 +00:00
|
|
|
; Hypothetical compiled tile routine
|
|
|
|
;
|
|
|
|
; Need 1MB of memory to have 1:1 space for 512 tiles
|
|
|
|
; for 16 sprites we have 8 variants: Vert, Horz, Shift. The shift sprites need an extra column
|
|
|
|
;
|
|
|
|
; 16x16 sprite = 4x16 words x 4 = 256, 5x16 words x 4 = 320 = 576 words * 21 bytes/word = 12K per sprite
|
|
|
|
|
|
|
|
; pei SpriteBanks
|
|
|
|
; plb
|
|
|
|
|
|
|
|
; lda spritedata+0,x ; skipped if mask = $ffff
|
|
|
|
; and #tilemask
|
|
|
|
; ora #tiledata
|
|
|
|
; sta spritedata+0,x ; 12 bytes / word = 12 * 16 = 216 < 256 in the worst case
|
|
|
|
|
|
|
|
; lda spritedata+2,x ; if mask != 0 and data = 0
|
|
|
|
; and #tilemask
|
|
|
|
; sta spritedata+0,x
|
|
|
|
|
|
|
|
; lda #tiledata ; if mask = 0 and data != 0
|
|
|
|
; sta spritedata+0,x
|
|
|
|
|
|
|
|
; stz spritedata+0,x ; if mask = 0 and data = 0
|
|
|
|
; ...
|
|
|
|
|
|
|
|
; plb
|
|
|
|
; lda #tilemask
|
|
|
|
; and spritemask+0,x
|
|
|
|
; sta spritemask+0,x ; 9 * 16 = 144 i the worst case
|
|
|
|
;
|
|
|
|
; stz spritemask+2,x ; if mask is zero (often the case)
|
|
|
|
|
|
|
|
_DrawTileTemplate
|
2021-11-20 18:00:21 +00:00
|
|
|
; X = sprite vbuff address
|
|
|
|
; Y = tile data pointer
|
|
|
|
_DrawTile8x8
|
2021-10-21 13:50:07 +00:00
|
|
|
phb
|
|
|
|
pea #^tiledata ; Set the bank to the tile data
|
|
|
|
plb
|
|
|
|
|
|
|
|
]line equ 0
|
|
|
|
lup 8
|
|
|
|
lda: tiledata+32+{]line*4},y
|
2022-02-02 16:21:31 +00:00
|
|
|
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
stal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
2021-10-21 13:50:07 +00:00
|
|
|
|
|
|
|
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
and: tiledata+32+{]line*4},y
|
2021-10-22 05:56:12 +00:00
|
|
|
ora: tiledata+{]line*4},y
|
2021-10-21 13:50:07 +00:00
|
|
|
stal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
|
|
|
|
lda: tiledata+32+{]line*4}+2,y
|
|
|
|
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
stal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
|
|
|
|
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
and: tiledata+32+{]line*4}+2,y
|
2021-10-22 05:56:12 +00:00
|
|
|
ora: tiledata+{]line*4}+2,y
|
2021-10-21 13:50:07 +00:00
|
|
|
stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb ; pop extra byte
|
|
|
|
plb
|
|
|
|
rts
|
|
|
|
|
2022-01-20 02:58:57 +00:00
|
|
|
; X = sprite vbuff address
|
|
|
|
; Y = tile data pointer
|
|
|
|
_DrawTile16x16
|
|
|
|
phb
|
|
|
|
pea #^tiledata ; Set the bank to the tile data
|
|
|
|
plb
|
|
|
|
|
|
|
|
]line equ 0
|
|
|
|
lup 8
|
|
|
|
lda: tiledata+32+{]line*4},y
|
2022-02-02 16:21:31 +00:00
|
|
|
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
stal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
2022-01-20 02:58:57 +00:00
|
|
|
|
|
|
|
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
and: tiledata+32+{]line*4},y
|
|
|
|
ora: tiledata+{]line*4},y
|
|
|
|
stal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
|
|
|
|
lda: tiledata+32+{]line*4}+2,y
|
|
|
|
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
stal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
|
|
|
|
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
and: tiledata+32+{]line*4}+2,y
|
|
|
|
ora: tiledata+{]line*4}+2,y
|
|
|
|
stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
|
|
|
|
lda: tiledata+32+128+{]line*4},y
|
|
|
|
andl spritemask+{]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
stal spritemask+{]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
|
|
|
|
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
and: tiledata+32+128+{]line*4},y
|
|
|
|
ora: tiledata+128+{]line*4},y
|
|
|
|
stal spritedata+{]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
|
|
|
|
lda: tiledata+32+128+{]line*4}+2,y
|
|
|
|
andl spritemask+{]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
stal spritemask+{]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
|
|
|
|
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
and: tiledata+32+128+{]line*4}+2,y
|
|
|
|
ora: tiledata+128+{]line*4}+2,y
|
|
|
|
stal spritedata+{]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
TILE_ROW_STRIDE equ 32*128
|
|
|
|
SPRITE_ROW_STRIDE equ 8*SPRITE_PLANE_SPAN
|
|
|
|
|
|
|
|
]line equ 0
|
|
|
|
lup 8
|
|
|
|
lda: tiledata+TILE_ROW_STRIDE+32+{]line*4},y
|
2022-02-02 16:21:31 +00:00
|
|
|
andl spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
stal spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN},x
|
2022-01-20 02:58:57 +00:00
|
|
|
|
|
|
|
ldal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
and: tiledata+TILE_ROW_STRIDE+32+{]line*4},y
|
|
|
|
ora: tiledata+TILE_ROW_STRIDE+{]line*4},y
|
|
|
|
stal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
|
|
|
|
lda: tiledata+TILE_ROW_STRIDE+32+{]line*4}+2,y
|
|
|
|
andl spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
stal spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
|
|
|
|
ldal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
and: tiledata+TILE_ROW_STRIDE+32+{]line*4}+2,y
|
|
|
|
ora: tiledata+TILE_ROW_STRIDE+{]line*4}+2,y
|
|
|
|
stal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
|
|
|
|
lda: tiledata+TILE_ROW_STRIDE+32+128+{]line*4},y
|
|
|
|
andl spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
stal spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
|
|
|
|
ldal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
and: tiledata+TILE_ROW_STRIDE+32+128+{]line*4},y
|
|
|
|
ora: tiledata+TILE_ROW_STRIDE+128+{]line*4},y
|
|
|
|
stal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
|
|
|
|
lda: tiledata+TILE_ROW_STRIDE+32+128+{]line*4}+2,y
|
|
|
|
andl spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
stal spritemask+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
|
|
|
|
ldal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
and: tiledata+TILE_ROW_STRIDE+128+32+{]line*4}+2,y
|
|
|
|
ora: tiledata+TILE_ROW_STRIDE+128+{]line*4}+2,y
|
|
|
|
stal spritedata+SPRITE_ROW_STRIDE+{]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb ; pop extra byte
|
|
|
|
plb
|
|
|
|
rts
|
|
|
|
|
2021-11-20 18:00:21 +00:00
|
|
|
; X = sprite vbuff address
|
|
|
|
; Y = tile data pointer
|
|
|
|
;
|
|
|
|
; Draws the tile vertically flipped
|
|
|
|
_DrawTile8x8V
|
|
|
|
phb
|
|
|
|
pea #^tiledata ; Set the bank to the tile data
|
|
|
|
plb
|
|
|
|
|
|
|
|
]line equ 0
|
|
|
|
lup 8
|
|
|
|
lda: tiledata+32+{{7-]line}*4},y
|
2022-02-02 16:21:31 +00:00
|
|
|
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
stal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
2021-11-20 18:00:21 +00:00
|
|
|
|
|
|
|
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
and: tiledata+32+{{7-]line}*4},y
|
|
|
|
ora: tiledata+{{7-]line}*4},y
|
|
|
|
stal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
|
|
|
|
|
|
|
lda: tiledata+32+{{7-]line}*4}+2,y
|
|
|
|
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
stal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
|
|
|
|
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
and: tiledata+32+{{7-]line}*4}+2,y
|
|
|
|
ora: tiledata+{{7-]line}*4}+2,y
|
|
|
|
stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb ; pop extra byte
|
|
|
|
plb
|
|
|
|
rts
|
|
|
|
|
2021-10-21 13:50:07 +00:00
|
|
|
; Erase is easy -- set an 8x8 area of the data region to all $0000 and the corresponding mask
|
|
|
|
; resgion to all $FFFF
|
|
|
|
;
|
2021-10-29 03:18:33 +00:00
|
|
|
; X = address is sprite plane -- erases an 8x8 region
|
2022-02-02 16:21:31 +00:00
|
|
|
_CacheSpriteBanks
|
|
|
|
lda #>spritemask
|
|
|
|
and #$FF00
|
|
|
|
ora #^spritedata
|
|
|
|
sta SpriteBanks
|
|
|
|
rts
|
|
|
|
|
2021-10-21 13:50:07 +00:00
|
|
|
SPRITE_PLANE_SPAN equ 256
|
|
|
|
|
2022-02-04 18:37:05 +00:00
|
|
|
; A = bank address
|
2022-02-03 14:59:10 +00:00
|
|
|
_EraseTileSprite8x8
|
2022-02-04 18:37:05 +00:00
|
|
|
tax
|
2021-10-29 02:41:01 +00:00
|
|
|
phb ; Save the bank to switch to the sprite plane
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-02 16:21:31 +00:00
|
|
|
pei SpriteBanks
|
|
|
|
plb ; pop the data bank (low byte)
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-03 14:59:10 +00:00
|
|
|
]line equ 0
|
|
|
|
lup 8
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+0,x
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-02 16:21:31 +00:00
|
|
|
plb ; pop the mask bank (high byte)
|
2021-10-21 13:50:07 +00:00
|
|
|
lda #$FFFF
|
2022-02-03 14:59:10 +00:00
|
|
|
]line equ 0
|
|
|
|
lup 8
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
2021-10-21 13:50:07 +00:00
|
|
|
|
|
|
|
plb
|
|
|
|
rts
|
|
|
|
|
2022-02-03 14:59:10 +00:00
|
|
|
_EraseTileSprite8x16
|
2022-02-04 18:37:05 +00:00
|
|
|
tax
|
2022-01-20 02:58:57 +00:00
|
|
|
phb ; Save the bank to switch to the sprite plane
|
|
|
|
|
2022-02-03 14:59:10 +00:00
|
|
|
pei SpriteBanks
|
|
|
|
plb ; pop the data bank (low byte)
|
2022-01-20 02:58:57 +00:00
|
|
|
|
2022-02-03 14:59:10 +00:00
|
|
|
]line equ 0
|
|
|
|
lup 16
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+0,x
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb ; pop the mask bank (high byte)
|
|
|
|
lda #$FFFF
|
2022-01-20 02:58:57 +00:00
|
|
|
]line equ 0
|
|
|
|
lup 16
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
2022-02-03 14:59:10 +00:00
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb
|
|
|
|
rts
|
|
|
|
|
|
|
|
_EraseTileSprite16x8
|
2022-02-04 18:37:05 +00:00
|
|
|
tax
|
2022-02-03 14:59:10 +00:00
|
|
|
phb ; Save the bank to switch to the sprite plane
|
|
|
|
|
|
|
|
pei SpriteBanks
|
|
|
|
plb ; pop the data bank (low byte)
|
|
|
|
|
|
|
|
]line equ 0
|
|
|
|
lup 8
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+0,x
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb ; pop the mask bank (high byte)
|
|
|
|
lda #$FFFF
|
|
|
|
]line equ 0
|
|
|
|
lup 8
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
2022-01-20 02:58:57 +00:00
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb
|
2022-02-03 14:59:10 +00:00
|
|
|
rts
|
|
|
|
|
|
|
|
_EraseTileSprite16x16
|
2022-02-04 18:37:05 +00:00
|
|
|
tax
|
2022-02-03 14:59:10 +00:00
|
|
|
phb ; Save the bank to switch to the sprite plane
|
|
|
|
|
|
|
|
pei SpriteBanks
|
|
|
|
plb ; pop the data bank (low byte)
|
|
|
|
|
|
|
|
]line equ 0
|
|
|
|
lup 16
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+0,x
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
stz: {]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb ; pop the mask bank (high byte)
|
2022-01-20 02:58:57 +00:00
|
|
|
|
|
|
|
lda #$FFFF
|
|
|
|
]line equ 0
|
|
|
|
lup 16
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+4,x
|
|
|
|
sta: {]line*SPRITE_PLANE_SPAN}+6,x
|
|
|
|
]line equ ]line+1
|
|
|
|
--^
|
|
|
|
|
|
|
|
plb
|
|
|
|
rts
|
2022-02-03 14:50:11 +00:00
|
|
|
|
|
|
|
; 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
|
|
|
|
|
2021-10-21 13:50:07 +00:00
|
|
|
; Add a new sprite to the rendering pipeline
|
|
|
|
;
|
2022-02-07 07:19:31 +00:00
|
|
|
; The tile id in the range 0 - 511. The top 7 bits are used as sprite control bits
|
2021-10-31 00:24:23 +00:00
|
|
|
;
|
|
|
|
; Bit 9 : Horizontal flip.
|
|
|
|
; Bit 10 : Vertical flip.
|
2021-11-11 23:06:38 +00:00
|
|
|
; Bits 11 - 12 : Sprite Size Selector
|
|
|
|
; 00 - 8x8 (1x1 tile)
|
|
|
|
; 01 - 8x16 (1x2 tiles)
|
|
|
|
; 10 - 16x8 (2x1 tiles)
|
|
|
|
; 11 - 16x16 (2x2 tiles)
|
|
|
|
; Bit 13 : Reserved. Must be zero.
|
|
|
|
; Bit 14 : Reserved. Must be zero.
|
|
|
|
; Bit 15 : Low Sprite priority. Draws behind high priority tiles.
|
2021-10-31 00:24:23 +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.
|
|
|
|
;
|
|
|
|
; Single sprite are limited to 24 lines high because there are 28 lines of padding above and below the
|
|
|
|
; sprite plane buffers, so a sprite that is 32 lines high could overflow the drawing area.
|
|
|
|
;
|
|
|
|
; A = tileId + flags
|
2021-10-21 13:50:07 +00:00
|
|
|
; X = x position
|
|
|
|
; Y = y position
|
|
|
|
AddSprite ENT
|
|
|
|
phb
|
|
|
|
phk
|
|
|
|
plb
|
|
|
|
jsr _AddSprite
|
|
|
|
plb
|
|
|
|
rtl
|
|
|
|
|
|
|
|
_AddSprite
|
2022-02-03 14:50:11 +00:00
|
|
|
phx ; Save the horizontal position
|
|
|
|
ldx _NextOpenSlot ; Get the next free sprite slot index
|
|
|
|
bpl :open ; A negative number means we are full
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
plx ; Early out
|
|
|
|
sec ; Signal that no sprite slot was available
|
2021-10-21 13:50:07 +00:00
|
|
|
rts
|
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
:open
|
2021-11-11 23:06:38 +00:00
|
|
|
sta _Sprites+SPRITE_ID,x ; Keep a copy of the full descriptor
|
2021-10-31 20:42:59 +00:00
|
|
|
jsr _GetTileAddr ; This applies the TILE_ID_MASK
|
2021-10-21 13:50:07 +00:00
|
|
|
sta _Sprites+TILE_DATA_OFFSET,x
|
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
lda #SPRITE_STATUS_OCCUPIED+SPRITE_STATUS_ADDED
|
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
2021-10-31 20:42:59 +00:00
|
|
|
|
2022-02-04 05:44:46 +00:00
|
|
|
tya
|
|
|
|
sta _Sprites+SPRITE_Y,x ; Y coordinate
|
2021-10-31 20:42:59 +00:00
|
|
|
pla ; X coordinate
|
|
|
|
sta _Sprites+SPRITE_X,x
|
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
jsr _GetSpriteVBuffAddrTmp ; Preserves X-register
|
2021-10-21 13:50:07 +00:00
|
|
|
sta _Sprites+VBUFF_ADDR,x
|
|
|
|
|
2022-02-04 18:37:05 +00:00
|
|
|
jsr _PrecalcAllSpriteInfo ; Cache stuff
|
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; Mark the dirty bit to indicate that the active sprite list needs to be rebuild 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
|
|
|
|
|
2021-10-24 03:31:38 +00:00
|
|
|
txa ; And return the sprite ID
|
2022-02-03 14:50:11 +00:00
|
|
|
clc ; Mark that the sprite was successfully added
|
2021-10-24 03:31:38 +00:00
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
; We can only get to this point if there was an open slot, so we know we're not at the
|
|
|
|
; end of the list yet.
|
2021-10-31 20:42:59 +00:00
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
ldx _OpenListHead
|
|
|
|
inx
|
|
|
|
inx
|
|
|
|
stx _OpenListHead
|
|
|
|
ldy _OpenList,x ; If this is the end, then the sentinel value will
|
|
|
|
sty _NextOpenSlot ; get stored into _NextOpenSlot
|
2021-10-29 02:41:01 +00:00
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
rts
|
2022-01-20 02:58:57 +00:00
|
|
|
|
2022-02-04 18:37:05 +00:00
|
|
|
; Precalculate some cached values for a sprite. These are *only* to make other part of code,
|
|
|
|
; specifically the draw/erase routines more efficient.
|
|
|
|
;
|
|
|
|
; There are variations of thi routine based on whether we are adding a new sprite, updating
|
|
|
|
; it's tile information, or changing its position.
|
|
|
|
;
|
|
|
|
; X = sprite index
|
|
|
|
_PrecalcAllSpriteInfo
|
|
|
|
lda _Sprites+SPRITE_ID,x
|
2022-02-07 07:19:31 +00:00
|
|
|
and #$2E00
|
|
|
|
xba
|
|
|
|
sta _Sprites+SPRITE_DISP2,x ; use bits 9 through 13 for full dispatch
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_ID,x
|
|
|
|
and #$1800 ; use bits 11 and 12 to dispatch (only care about size)
|
2022-02-04 18:37:05 +00:00
|
|
|
lsr
|
|
|
|
lsr
|
|
|
|
xba
|
|
|
|
sta _Sprites+SPRITE_DISP,x
|
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
|
|
|
|
; is fully offs-screen or not
|
|
|
|
tay ; use the index we just calculated
|
|
|
|
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
|
|
|
|
adc _SpriteWidthMinus1,y
|
|
|
|
bmi :offscreen
|
|
|
|
cmp ScreenWidth
|
|
|
|
bcc :ok_x
|
|
|
|
lda ScreenWidth
|
|
|
|
dec
|
|
|
|
:ok_x sta _Sprites+SPRITE_CLIP_RIGHT,x
|
|
|
|
|
|
|
|
lda _Sprites+SPRITE_Y,x
|
|
|
|
clc
|
|
|
|
adc _SpriteHeightMinus1,y
|
|
|
|
bmi :offscreen
|
|
|
|
cmp ScreenHeight
|
|
|
|
bcc :ok_y
|
|
|
|
lda ScreenHeight
|
|
|
|
dec
|
|
|
|
:ok_y sta _Sprites+SPRITE_CLIP_BOTTOM,x
|
|
|
|
|
|
|
|
stz _Sprites+IS_OFF_SCREEN,x ; passed all of the off-screen test
|
|
|
|
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 ENT
|
|
|
|
phb
|
|
|
|
phk
|
|
|
|
plb
|
|
|
|
jsr _RemoveSprite
|
|
|
|
plb
|
|
|
|
rtl
|
|
|
|
|
|
|
|
_RemoveSprite
|
2022-02-03 14:50:11 +00:00
|
|
|
tax
|
2022-01-20 02:58:57 +00:00
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
_RemoveSpriteX
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_STATUS,x
|
|
|
|
ora #SPRITE_STATUS_REMOVED
|
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
2022-01-20 02:58:57 +00:00
|
|
|
rts
|
|
|
|
|
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.
|
|
|
|
;
|
|
|
|
; A = Sprite ID
|
|
|
|
; X = Sprite Tile ID and Flags
|
|
|
|
UpdateSprite ENT
|
|
|
|
phb
|
|
|
|
phk
|
|
|
|
plb
|
|
|
|
jsr _UpdateSprite
|
|
|
|
plb
|
|
|
|
rtl
|
|
|
|
|
|
|
|
_UpdateSprite
|
2022-02-03 14:50:11 +00:00
|
|
|
phx ; swap X/A to be more efficient
|
|
|
|
tax
|
|
|
|
pla
|
|
|
|
|
|
|
|
_UpdateSpriteX
|
|
|
|
cpx #MAX_SPRITES*2 ; Make sure we're in bounds
|
2021-11-20 18:16:03 +00:00
|
|
|
bcc :ok
|
|
|
|
rts
|
|
|
|
|
|
|
|
:ok
|
2022-02-03 14:50:11 +00:00
|
|
|
_UpdateSpriteXnc
|
|
|
|
sta _Sprites+SPRITE_ID,x ; Keep a copy of the full descriptor
|
|
|
|
jsr _GetTileAddr ; This applies the TILE_ID_MASK
|
|
|
|
sta _Sprites+TILE_DATA_OFFSET,x
|
2021-11-20 18:16:03 +00:00
|
|
|
|
2022-02-04 18:37:05 +00:00
|
|
|
jsr _PrecalcAllSpriteInfo ; Cache stuff
|
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
lda _Sprites+SPRITE_STATUS,x
|
|
|
|
ora #SPRITE_STATUS_UPDATED
|
2021-11-20 18:16:03 +00:00
|
|
|
sta _Sprites+SPRITE_STATUS,x
|
|
|
|
|
|
|
|
rts
|
|
|
|
|
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
|
|
|
|
;
|
|
|
|
; A = sprite ID
|
|
|
|
; X = x position
|
|
|
|
; Y = y position
|
2021-11-20 18:16:03 +00:00
|
|
|
MoveSprite ENT
|
2021-10-24 03:31:38 +00:00
|
|
|
phb
|
|
|
|
phk
|
|
|
|
plb
|
2021-11-20 18:16:03 +00:00
|
|
|
jsr _MoveSprite
|
2021-10-24 03:31:38 +00:00
|
|
|
plb
|
|
|
|
rtl
|
|
|
|
|
2021-11-20 18:16:03 +00:00
|
|
|
_MoveSprite
|
2022-02-03 14:50:11 +00:00
|
|
|
phx ; swap X/A to be more efficient
|
|
|
|
tax
|
|
|
|
pla
|
|
|
|
|
|
|
|
_MoveSpriteX
|
|
|
|
cpx #MAX_SPRITES*2 ; Make sure we're in bounds
|
2021-10-24 03:31:38 +00:00
|
|
|
bcc :ok
|
|
|
|
rts
|
|
|
|
|
|
|
|
:ok
|
2022-02-03 14:50:11 +00:00
|
|
|
_MoveSpriteXnc
|
|
|
|
sta _Sprites+SPRITE_X,x ; Update the X coordinate
|
2022-02-04 05:44:46 +00:00
|
|
|
pha
|
|
|
|
tya
|
|
|
|
sta _Sprites+SPRITE_Y,x ; Update the Y coordinate
|
|
|
|
pla
|
2022-02-03 14:50:11 +00:00
|
|
|
|
|
|
|
jsr _GetSpriteVBuffAddrTmp ; A = x-coord, Y = y-coord
|
|
|
|
ldy _Sprites+VBUFF_ADDR,x ; Save the previous draw location for erasing
|
|
|
|
sta _Sprites+VBUFF_ADDR,x ; Overwrite with the new location
|
2022-02-04 05:44:46 +00:00
|
|
|
tya
|
|
|
|
sta _Sprites+OLD_VBUFF_ADDR,x
|
2021-10-24 03:31:38 +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
|
|
|
|
2021-10-21 13:50:07 +00:00
|
|
|
rts
|
|
|
|
|
|
|
|
; Sprite data structures. We cache quite a few pieces of information about the sprite
|
|
|
|
; to make calculations faster, so this is hidden from the caller.
|
|
|
|
;
|
|
|
|
; Each sprite record contains the following properties:
|
|
|
|
;
|
|
|
|
; +0: Sprite status word (0 = unoccupied)
|
|
|
|
; +2: Tile data address
|
|
|
|
; +4: Screen offset address (used for data and masks)
|
|
|
|
|
|
|
|
; Number of "off-screen" lines above logical (0,0)
|
|
|
|
NUM_BUFF_LINES equ 24
|
|
|
|
|
2021-11-02 04:36:53 +00:00
|
|
|
MAX_SPRITES equ 16
|
2022-02-07 07:19:31 +00:00
|
|
|
SPRITE_REC_SIZE equ 48
|
|
|
|
|
|
|
|
; Mark each sprite as ADDED, UPDATED, MOVED, REMOVED depending on the actions applied to it
|
|
|
|
; on this frame. Quick note, the same Sprite ID cannot be removed and added in the same frame.
|
|
|
|
; A REMOVED sprite if removed from the sprite list during the Render call, so it's ID is not
|
|
|
|
; available to the AddSprite function until the next frame.
|
|
|
|
|
|
|
|
SPRITE_STATUS_EMPTY equ $0000 ; If the status value is zero, this sprite slot is available
|
|
|
|
SPRITE_STATUS_OCCUPIED equ $8000 ; Set the MSB to flag it as occupied
|
|
|
|
SPRITE_STATUS_ADDED equ $0001 ; Sprite was just added (new sprite)
|
|
|
|
SPRITE_STATUS_MOVED equ $0002 ; Sprite's position was changed
|
|
|
|
SPRITE_STATUS_UPDATED equ $0004 ; Sprite's non-position attributes were changed
|
|
|
|
SPRITE_STATUS_REMOVED equ $0008 ; Sprite has been removed.
|
2022-02-04 18:37:05 +00:00
|
|
|
|
2022-02-07 07:19:31 +00:00
|
|
|
; Each subroutine just sets the relevant bits, so it's possible to call AddSprite / UpdateSprite / MoveSprite
|
|
|
|
; and RemoveSprite in a single frame. These bits have priorities, so in this case, the sprite is immediately
|
|
|
|
; removed and never displayed.
|
2022-02-04 18:37:05 +00:00
|
|
|
|
|
|
|
SPRITE_STATUS equ {MAX_SPRITES*0}
|
|
|
|
TILE_DATA_OFFSET equ {MAX_SPRITES*2}
|
|
|
|
VBUFF_ADDR equ {MAX_SPRITES*4}
|
|
|
|
SPRITE_ID equ {MAX_SPRITES*6}
|
|
|
|
SPRITE_X equ {MAX_SPRITES*8}
|
|
|
|
SPRITE_Y equ {MAX_SPRITES*10}
|
|
|
|
OLD_VBUFF_ADDR equ {MAX_SPRITES*12}
|
|
|
|
TILE_STORE_ADDR_1 equ {MAX_SPRITES*14}
|
|
|
|
TILE_STORE_ADDR_2 equ {MAX_SPRITES*16}
|
|
|
|
TILE_STORE_ADDR_3 equ {MAX_SPRITES*18}
|
|
|
|
TILE_STORE_ADDR_4 equ {MAX_SPRITES*20}
|
|
|
|
TILE_STORE_ADDR_5 equ {MAX_SPRITES*22}
|
|
|
|
TILE_STORE_ADDR_6 equ {MAX_SPRITES*24}
|
|
|
|
TILE_STORE_ADDR_7 equ {MAX_SPRITES*26}
|
|
|
|
TILE_STORE_ADDR_8 equ {MAX_SPRITES*28}
|
|
|
|
TILE_STORE_ADDR_9 equ {MAX_SPRITES*30}
|
2021-11-11 23:06:38 +00:00
|
|
|
TILE_STORE_ADDR_10 equ {MAX_SPRITES*32}
|
2022-02-04 18:37:05 +00:00
|
|
|
SPRITE_DISP equ {MAX_SPRITES*34} ; pre-calculated index for jmp (abs,x) based on sprite size
|
2022-02-07 07:19:31 +00:00
|
|
|
SPRITE_CLIP_LEFT equ {MAX_SPRITES*36}
|
|
|
|
SPRITE_CLIP_RIGHT equ {MAX_SPRITES*38}
|
|
|
|
SPRITE_CLIP_TOP equ {MAX_SPRITES*40}
|
|
|
|
SPRITE_CLIP_BOTTOM equ {MAX_SPRITES*42}
|
|
|
|
IS_OFF_SCREEN equ {MAX_SPRITES*44}
|
|
|
|
SPRITE_DISP2 equ {MAX_SPRITES*46}
|
2021-10-21 13:50:07 +00:00
|
|
|
|
2022-02-03 14:50:11 +00:00
|
|
|
; Maintain the index of the next open sprite slot. This allows us to have amortized
|
|
|
|
; constant sprite add performance. A negative value means no slots are available.
|
|
|
|
_NextOpenSlot dw 0
|
|
|
|
_OpenListHead dw 0
|
|
|
|
_OpenList dw 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,$FFFF ; List with sentinel at the end
|
|
|
|
|
2021-10-21 13:50:07 +00:00
|
|
|
_Sprites ds SPRITE_REC_SIZE*MAX_SPRITES
|
2022-02-07 07:19:31 +00:00
|
|
|
|
|
|
|
; On-demand cached list of active sprite slots
|
|
|
|
activeSpriteCount ds 2
|
|
|
|
activeSpriteList ds 2*MAX_SPRITES
|
|
|
|
|