mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-06-09 10:29:30 +00:00
Background rendering again
This commit is contained in:
parent
95572fbf49
commit
bb83e7f7c5
|
@ -53,36 +53,35 @@ DOWN_ARROW equ $0A
|
||||||
SPRITE_ID equ {SPRITE_16X16+1}
|
SPRITE_ID equ {SPRITE_16X16+1}
|
||||||
OKTOROK equ {SPRITE_16X16+79}
|
OKTOROK equ {SPRITE_16X16+79}
|
||||||
|
|
||||||
lda #SPRITE_ID ; 16x16 sprite
|
; lda #SPRITE_ID ; 16x16 sprite
|
||||||
ldx PlayerX
|
; ldx PlayerX
|
||||||
ldy PlayerY
|
; ldy PlayerY
|
||||||
jsl AddSprite
|
; jsl AddSprite
|
||||||
bcc :sprite_ok
|
; bcc :sprite_ok
|
||||||
brl Exit ; If we could not allocate a sprite, exit
|
; brl Exit ; If we could not allocate a sprite, exit
|
||||||
:sprite_ok
|
;:sprite_ok
|
||||||
sta PlayerID
|
; sta PlayerID
|
||||||
brl Exit
|
|
||||||
|
|
||||||
; Add 4 octoroks
|
; Add 4 octoroks
|
||||||
lda #OKTOROK
|
; lda #OKTOROK
|
||||||
ldx #32
|
; ldx #32
|
||||||
ldy #48
|
; ldy #48
|
||||||
jsl AddSprite
|
; jsl AddSprite
|
||||||
|
|
||||||
lda #OKTOROK
|
; lda #OKTOROK
|
||||||
ldx #96
|
; ldx #96
|
||||||
ldy #32
|
; ldy #32
|
||||||
jsl AddSprite
|
; jsl AddSprite
|
||||||
|
|
||||||
lda #OKTOROK
|
; lda #OKTOROK
|
||||||
ldx #56
|
; ldx #56
|
||||||
ldy #96
|
; ldy #96
|
||||||
jsl AddSprite
|
; jsl AddSprite
|
||||||
|
|
||||||
lda #OKTOROK
|
; lda #OKTOROK
|
||||||
ldx #72
|
; ldx #72
|
||||||
ldy #96
|
; ldy #96
|
||||||
jsl AddSprite
|
; jsl AddSprite
|
||||||
|
|
||||||
; Draw the initial screen
|
; Draw the initial screen
|
||||||
|
|
||||||
|
@ -90,6 +89,7 @@ OKTOROK equ {SPRITE_16X16+79}
|
||||||
tsb DirtyBits
|
tsb DirtyBits
|
||||||
jsl Render
|
jsl Render
|
||||||
|
|
||||||
|
|
||||||
; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
|
; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
|
||||||
; leave it alone. We are just testing the ability to merge sprite plane data into
|
; leave it alone. We are just testing the ability to merge sprite plane data into
|
||||||
; the play field tiles.
|
; the play field tiles.
|
||||||
|
@ -122,7 +122,8 @@ EvtLoop
|
||||||
bne :not_q
|
bne :not_q
|
||||||
brl Exit
|
brl Exit
|
||||||
:not_q
|
:not_q
|
||||||
|
brl EvtLoop
|
||||||
|
|
||||||
cmp #'d'
|
cmp #'d'
|
||||||
bne :not_d
|
bne :not_d
|
||||||
inc PlayerX
|
inc PlayerX
|
||||||
|
|
|
@ -158,25 +158,6 @@ asr8 mac
|
||||||
ror
|
ror
|
||||||
<<<
|
<<<
|
||||||
|
|
||||||
; Inline macros for fast calculation of some internal values
|
|
||||||
_TileStoreOffset mac
|
|
||||||
lda ]2
|
|
||||||
asl
|
|
||||||
tay
|
|
||||||
lda ]1
|
|
||||||
asl ; Assume in range, so asl puts a 0 bit into the carry
|
|
||||||
adc TileStoreYTable,y
|
|
||||||
<<<
|
|
||||||
|
|
||||||
_TileStoreOffsetX mac
|
|
||||||
lda ]2
|
|
||||||
asl
|
|
||||||
tax
|
|
||||||
lda ]1
|
|
||||||
asl ; Assume in range, so asl puts a 0 bit into the carry
|
|
||||||
adc TileStoreYTable,x
|
|
||||||
<<<
|
|
||||||
|
|
||||||
; Macro to define script steps
|
; Macro to define script steps
|
||||||
ScriptStep MAC
|
ScriptStep MAC
|
||||||
IF #=]5
|
IF #=]5
|
||||||
|
|
|
@ -57,7 +57,6 @@ GetTileAddr EXT
|
||||||
PushDirtyTile EXT ; A = address from GetTileStoreOffset, marks as dirty (will not mark the same tile more than once)
|
PushDirtyTile EXT ; A = address from GetTileStoreOffset, marks as dirty (will not mark the same tile more than once)
|
||||||
PopDirtyTile EXT ; No args, returns Y with tile store offset of the dirty tile
|
PopDirtyTile EXT ; No args, returns Y with tile store offset of the dirty tile
|
||||||
ApplyTiles EXT ; Drain the dirty tile queue and call RenderTile on each
|
ApplyTiles EXT ; Drain the dirty tile queue and call RenderTile on each
|
||||||
RenderTile EXT ; Y = address from GetTileStoreOffset
|
|
||||||
GetTileStoreOffset EXT ; X = column, Y = row
|
GetTileStoreOffset EXT ; X = column, Y = row
|
||||||
TileStore EXT ; Tile store internal data structure
|
TileStore EXT ; Tile store internal data structure
|
||||||
|
|
||||||
|
|
34
src/Render.s
34
src/Render.s
|
@ -90,7 +90,7 @@ _Render
|
||||||
|
|
||||||
; The code fields are locked in now and ready to be rendered
|
; The code fields are locked in now and ready to be rendered
|
||||||
|
|
||||||
jsr _ShadowOff
|
; jsr _ShadowOff
|
||||||
|
|
||||||
; Shadowing is turned off. Render all of the scan lines that need a second pass. One
|
; Shadowing is turned off. Render all of the scan lines that need a second pass. One
|
||||||
; optimization that can be done here is that the lines can be rendered in any order
|
; optimization that can be done here is that the lines can be rendered in any order
|
||||||
|
@ -102,27 +102,27 @@ _Render
|
||||||
|
|
||||||
; Turn shadowing back on
|
; Turn shadowing back on
|
||||||
|
|
||||||
jsr _ShadowOn
|
; jsr _ShadowOn
|
||||||
|
|
||||||
; Now render all of the remaining lines in top-to-bottom (or bottom-to-top) order
|
; Now render all of the remaining lines in top-to-bottom (or bottom-to-top) order
|
||||||
|
|
||||||
lda ScreenY0 ; pass the address of the first line of the overlay
|
; lda ScreenY0 ; pass the address of the first line of the overlay
|
||||||
clc
|
; clc
|
||||||
adc #0
|
; adc #0
|
||||||
asl
|
; asl
|
||||||
tax
|
; tax
|
||||||
lda ScreenAddr,x
|
; lda ScreenAddr,x
|
||||||
clc
|
; clc
|
||||||
adc ScreenX0
|
; adc ScreenX0
|
||||||
; jsl Overlay
|
; jsl Overlay
|
||||||
|
|
||||||
ldx #0 ; Blit the full virtual buffer to the screen
|
ldx #0 ; Blit the full virtual buffer to the screen
|
||||||
ldy ScreenHeight
|
ldy ScreenHeight
|
||||||
jsr _BltRange
|
jsr _BltRange
|
||||||
|
|
||||||
; ldx #0
|
ldx #0
|
||||||
; ldy ScreenHeight
|
ldy ScreenHeight
|
||||||
; jsr _BltSCB
|
jsr _BltSCB
|
||||||
|
|
||||||
lda StartY ; Restore the fields back to their original state
|
lda StartY ; Restore the fields back to their original state
|
||||||
ldx ScreenHeight
|
ldx ScreenHeight
|
||||||
|
@ -139,10 +139,10 @@ _Render
|
||||||
sta OldBG1StartX
|
sta OldBG1StartX
|
||||||
|
|
||||||
stz DirtyBits
|
stz DirtyBits
|
||||||
stz LastRender
|
stz LastRender ; Mark that a full render was just performed
|
||||||
rts
|
rts
|
||||||
|
|
||||||
; This is a specialized redner function that only updated the dirty tiles *and* draws them
|
; This is a specialized render function that only updates the dirty tiles *and* draws them
|
||||||
; directly onto the SHR graphics buffer. The playfield is not used at all. In some way, this
|
; directly onto the SHR graphics buffer. The playfield is not used at all. In some way, this
|
||||||
; ignores almost all of the capabilities of GTE, but it does provide a convenient way to use
|
; ignores almost all of the capabilities of GTE, but it does provide a convenient way to use
|
||||||
; the sprite subsystem + tile attributes for single-screen games which should be able to run
|
; the sprite subsystem + tile attributes for single-screen games which should be able to run
|
||||||
|
@ -207,7 +207,7 @@ _RenderDirtyTile
|
||||||
xba
|
xba
|
||||||
tax
|
tax
|
||||||
ldal DirtyTileSpriteProcs,x
|
ldal DirtyTileSpriteProcs,x
|
||||||
sta :tiledisp+1
|
stal :tiledisp+1
|
||||||
bra :sprite
|
bra :sprite
|
||||||
|
|
||||||
:nosprite
|
:nosprite
|
||||||
|
@ -216,7 +216,7 @@ _RenderDirtyTile
|
||||||
xba
|
xba
|
||||||
tax
|
tax
|
||||||
ldal DirtyTileProcs,x ; load and patch in the appropriate subroutine
|
ldal DirtyTileProcs,x ; load and patch in the appropriate subroutine
|
||||||
sta :tiledisp+1
|
stal :tiledisp+1
|
||||||
|
|
||||||
:sprite
|
:sprite
|
||||||
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
||||||
|
|
211
src/Sprite.s
211
src/Sprite.s
|
@ -1,49 +1,6 @@
|
||||||
; Functions for sprite handling. Mostly maintains the sprite list and provides
|
; Functions for sprite handling. Mostly maintains the sprite list and provides
|
||||||
; utility functions to calculate sprite/tile intersections
|
; utility functions to calculate sprite/tile intersections
|
||||||
;
|
;
|
||||||
; 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.
|
|
||||||
;
|
|
||||||
; 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.
|
|
||||||
;
|
|
||||||
; 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)
|
|
||||||
|
|
||||||
; 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.
|
|
||||||
;
|
|
||||||
; Initialize the sprite data and mask banks (all data = $0000, all masks = $FFFF)
|
; Initialize the sprite data and mask banks (all data = $0000, all masks = $FFFF)
|
||||||
InitSprites
|
InitSprites
|
||||||
ldx #$FFFE
|
ldx #$FFFE
|
||||||
|
@ -92,6 +49,89 @@ VBUFF_SPRITE_START equ {8*VBUFF_TILE_ROW_BYTES}+4
|
||||||
jsr _CacheSpriteBanks
|
jsr _CacheSpriteBanks
|
||||||
rts
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; 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)
|
||||||
|
; Bit 13 : Reserved. Must be zero.
|
||||||
|
; Bit 14 : Reserved. Must be zero.
|
||||||
|
; Bit 15 : Low Sprite priority. Draws behind high priority tiles.
|
||||||
|
;
|
||||||
|
; 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
|
||||||
|
; X = x position
|
||||||
|
; Y = y position
|
||||||
|
AddSprite ENT
|
||||||
|
phb
|
||||||
|
phk
|
||||||
|
plb
|
||||||
|
jsr _AddSprite
|
||||||
|
plb
|
||||||
|
rtl
|
||||||
|
|
||||||
|
_AddSprite
|
||||||
|
phx ; Save the horizontal position
|
||||||
|
ldx _NextOpenSlot ; Get the next free sprite slot index
|
||||||
|
bpl :open ; A negative number means we are full
|
||||||
|
|
||||||
|
plx ; Early out
|
||||||
|
sec ; Signal that no sprite slot was available
|
||||||
|
rts
|
||||||
|
|
||||||
|
:open
|
||||||
|
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
|
||||||
|
|
||||||
|
lda #SPRITE_STATUS_OCCUPIED+SPRITE_STATUS_ADDED
|
||||||
|
sta _Sprites+SPRITE_STATUS,x
|
||||||
|
|
||||||
|
tya
|
||||||
|
sta _Sprites+SPRITE_Y,x ; Y coordinate
|
||||||
|
pla ; X coordinate
|
||||||
|
sta _Sprites+SPRITE_X,x
|
||||||
|
|
||||||
|
jsr _PrecalcAllSpriteInfo ; Cache sprite property values (simple stuff)
|
||||||
|
jsr _DrawSpriteSheet ; Render the sprite into internal space
|
||||||
|
|
||||||
|
; 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
|
||||||
|
|
||||||
|
txa ; And return the sprite ID
|
||||||
|
clc ; Mark that the sprite was successfully added
|
||||||
|
|
||||||
|
; 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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
rts
|
||||||
|
|
||||||
; Run through the list of tile store offsets that this sprite was last drawn into and mark
|
; 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
|
; 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.
|
; (an unaligned 4x3 sprite), covering a 5x4 area of play field tiles.
|
||||||
|
@ -538,91 +578,6 @@ SPRITE_PLANE_SPAN equ 52 ; 256
|
||||||
; adc tmp15
|
; adc tmp15
|
||||||
; rts
|
; rts
|
||||||
|
|
||||||
; 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)
|
|
||||||
; Bit 13 : Reserved. Must be zero.
|
|
||||||
; Bit 14 : Reserved. Must be zero.
|
|
||||||
; Bit 15 : Low Sprite priority. Draws behind high priority tiles.
|
|
||||||
;
|
|
||||||
; 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
|
|
||||||
; X = x position
|
|
||||||
; Y = y position
|
|
||||||
AddSprite ENT
|
|
||||||
phb
|
|
||||||
phk
|
|
||||||
plb
|
|
||||||
jsr _AddSprite
|
|
||||||
plb
|
|
||||||
rtl
|
|
||||||
|
|
||||||
_AddSprite
|
|
||||||
phx ; Save the horizontal position
|
|
||||||
ldx _NextOpenSlot ; Get the next free sprite slot index
|
|
||||||
bpl :open ; A negative number means we are full
|
|
||||||
|
|
||||||
plx ; Early out
|
|
||||||
sec ; Signal that no sprite slot was available
|
|
||||||
rts
|
|
||||||
|
|
||||||
:open
|
|
||||||
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
|
|
||||||
|
|
||||||
lda #SPRITE_STATUS_OCCUPIED+SPRITE_STATUS_ADDED
|
|
||||||
sta _Sprites+SPRITE_STATUS,x
|
|
||||||
|
|
||||||
tya
|
|
||||||
sta _Sprites+SPRITE_Y,x ; Y coordinate
|
|
||||||
pla ; X coordinate
|
|
||||||
sta _Sprites+SPRITE_X,x
|
|
||||||
|
|
||||||
; jsr _GetSpriteVBuffAddrTmp
|
|
||||||
; sta _Sprites+VBUFF_ADDR,x ; This is now pre-calculated since each sprite slot gets a fixed location
|
|
||||||
|
|
||||||
jsr _PrecalcAllSpriteInfo ; Cache sprite property values (simple stuff)
|
|
||||||
jsr _DrawSpriteSheet ; Render the sprite into internal space
|
|
||||||
|
|
||||||
; 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
|
|
||||||
|
|
||||||
txa ; And return the sprite ID
|
|
||||||
clc ; Mark that the sprite was successfully added
|
|
||||||
|
|
||||||
; 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.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Precalculate some cached values for a sprite. These are *only* to make other part of code,
|
; Precalculate some cached values for a sprite. These are *only* to make other part of code,
|
||||||
; specifically the draw/erase routines more efficient.
|
; specifically the draw/erase routines more efficient.
|
||||||
;
|
;
|
||||||
|
|
|
@ -318,21 +318,6 @@ _MarkDirtySprite
|
||||||
rts
|
rts
|
||||||
|
|
||||||
; Begin List of subroutines to mark each tile offset
|
; Begin List of subroutines to mark each tile offset
|
||||||
;
|
|
||||||
; If we had a double-sized 2D array to be able to look up the tile store address without
|
|
||||||
; adding rows and column, we could save ~6 cycles per tile
|
|
||||||
|
|
||||||
; If all that is needed is to record the Tile Store offset for the sprite and delay any
|
|
||||||
; actual calculations, then we just need to do
|
|
||||||
;
|
|
||||||
; lda TileStore2DArray,x
|
|
||||||
; sta _Sprites+TILE_STORE_ADDR_0,y
|
|
||||||
; lda TileStore2DArray+2,x
|
|
||||||
; sta _Sprites+TILE_STORE_ADDR_1,y
|
|
||||||
; lda TileStore2DArray+41,x
|
|
||||||
; sta _Sprites+TILE_STORE_ADDR_2,y
|
|
||||||
; ...
|
|
||||||
|
|
||||||
:mark_0_0
|
:mark_0_0
|
||||||
ldx RowTop
|
ldx RowTop
|
||||||
lda ColLeft
|
lda ColLeft
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
; The table values are pre-reversed so that loop can go in logical order 0, 2, 4, ...
|
; The table values are pre-reversed so that loop can go in logical order 0, 2, 4, ...
|
||||||
; and the resulting offsets will map to the code instructions in right-to-left order.
|
; and the resulting offsets will map to the code instructions in right-to-left order.
|
||||||
;
|
;
|
||||||
; Remember, because the data is pushed on to the stask, the last instruction, which is
|
; Remember, because the data is pushed on to the stack, the last instruction, which is
|
||||||
; in the highest memory location, pushed data that apepars on the left edge of the screen.
|
; in the highest memory location, pushed data that apepars on the left edge of the screen.
|
||||||
PER_TILE_SIZE equ 3
|
PER_TILE_SIZE equ 3
|
||||||
]step equ 0
|
]step equ 0
|
||||||
|
@ -238,18 +238,6 @@ TileStoreYTable ENT
|
||||||
]step = ]step+{41*2}
|
]step = ]step+{41*2}
|
||||||
--^
|
--^
|
||||||
|
|
||||||
;TileStore2DYTable
|
|
||||||
;]step equ 0
|
|
||||||
; lup 26
|
|
||||||
; dw ]step
|
|
||||||
;]step = ]step+{41*2*2}
|
|
||||||
; --^
|
|
||||||
;]step equ 0
|
|
||||||
; lup 26
|
|
||||||
; dw ]step
|
|
||||||
;]step = ]step+{41*2*2}
|
|
||||||
; --^
|
|
||||||
|
|
||||||
; Create a table to look up the "next" column with modulo wraparound. Basically a[i] = i
|
; Create a table to look up the "next" column with modulo wraparound. Basically a[i] = i
|
||||||
; and the table is double-length. Use constant offsets to pick an amount to advance
|
; and the table is double-length. Use constant offsets to pick an amount to advance
|
||||||
NextCol
|
NextCol
|
||||||
|
|
|
@ -103,14 +103,6 @@ _RenderTileBG1
|
||||||
; Store record contains all of the low-level information that's needed to call the renderer.
|
; Store record contains all of the low-level information that's needed to call the renderer.
|
||||||
;
|
;
|
||||||
; Y = address of tile
|
; Y = address of tile
|
||||||
RenderTile ENT
|
|
||||||
phb
|
|
||||||
phk
|
|
||||||
plb
|
|
||||||
jsr _RenderTile2
|
|
||||||
plb
|
|
||||||
rtl
|
|
||||||
|
|
||||||
_RenderTile2
|
_RenderTile2
|
||||||
pea >TileStore ; Need that addressing flexibility here. Callers responsible for restoring bank reg
|
pea >TileStore ; Need that addressing flexibility here. Callers responsible for restoring bank reg
|
||||||
plb
|
plb
|
||||||
|
@ -118,9 +110,9 @@ _RenderTile2
|
||||||
|
|
||||||
lda TileStore+TS_TILE_ID,y ; build the finalized tile descriptor
|
lda TileStore+TS_TILE_ID,y ; build the finalized tile descriptor
|
||||||
ldx TileStore+TS_SPRITE_FLAG,y ; This is a bitfield of all the sprites that intersect this tile, only care if non-zero or not
|
ldx TileStore+TS_SPRITE_FLAG,y ; This is a bitfield of all the sprites that intersect this tile, only care if non-zero or not
|
||||||
beq :nosprite
|
; beq :nosprite
|
||||||
|
|
||||||
ora #TILE_SPRITE_BIT
|
; ora #TILE_SPRITE_BIT
|
||||||
; ldx TileStore+TS_SPRITE_ADDR,y ; TODO: collapse sprites
|
; ldx TileStore+TS_SPRITE_ADDR,y ; TODO: collapse sprites
|
||||||
; stx _SPR_X_REG
|
; stx _SPR_X_REG
|
||||||
|
|
||||||
|
@ -129,8 +121,8 @@ _RenderTile2
|
||||||
and #TILE_CTRL_MASK
|
and #TILE_CTRL_MASK
|
||||||
xba
|
xba
|
||||||
tax
|
tax
|
||||||
lda TileProcs,x ; load and patch in the appropriate subroutine
|
ldal TileProcs,x ; load and patch in the appropriate subroutine
|
||||||
sta :tiledisp+1
|
stal :tiledisp+1
|
||||||
|
|
||||||
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
||||||
|
|
||||||
|
@ -541,6 +533,7 @@ InitTiles
|
||||||
:col equ tmp0
|
:col equ tmp0
|
||||||
:row equ tmp1
|
:row equ tmp1
|
||||||
:vbuff equ tmp2
|
:vbuff equ tmp2
|
||||||
|
|
||||||
; Fill in the TileStoreYTable. This is just a table of offsets into the Tile Store for each row. There
|
; Fill in the TileStoreYTable. This is just a table of offsets into the Tile Store for each row. There
|
||||||
; are 26 rows with a stride of 41
|
; are 26 rows with a stride of 41
|
||||||
ldy #0
|
ldy #0
|
||||||
|
@ -554,36 +547,6 @@ InitTiles
|
||||||
cpy #26*2
|
cpy #26*2
|
||||||
bcc :yloop
|
bcc :yloop
|
||||||
|
|
||||||
; Fill in the TileStore2DLookup array. This is a full array lookup for the entire tile store space. Eventually
|
|
||||||
; we can remove TileStoreYTable and free up a bit of space.
|
|
||||||
lda #0
|
|
||||||
tay
|
|
||||||
tax
|
|
||||||
:xyloop
|
|
||||||
sta TileStoreYTable,y
|
|
||||||
sta TileStoreYTable+{2*41},y
|
|
||||||
sta TileStoreYTable+{4*41*26},y
|
|
||||||
sta TileStoreYTable+{4*41*26}+{2*41},y
|
|
||||||
|
|
||||||
inc ; Advance to the next offset value
|
|
||||||
inc
|
|
||||||
|
|
||||||
iny ; Advance to the next table location
|
|
||||||
iny
|
|
||||||
|
|
||||||
inx ; Increment the column counter
|
|
||||||
cpx #41 ; If we haven't filled an entire row, keep going
|
|
||||||
bcc :xyloop
|
|
||||||
|
|
||||||
ldx #0 ; reset the column counter
|
|
||||||
tya
|
|
||||||
clc
|
|
||||||
adc #2*26 ; skip over the repeated values in this row and to to the next row start
|
|
||||||
tay
|
|
||||||
|
|
||||||
cpy #4*41*26 ; Did we finish the last row, if not go back for more
|
|
||||||
bcc :xyloop
|
|
||||||
|
|
||||||
; Next, initialize the Tile Store itself
|
; Next, initialize the Tile Store itself
|
||||||
|
|
||||||
ldx #TILE_STORE_SIZE-2
|
ldx #TILE_STORE_SIZE-2
|
||||||
|
@ -741,23 +704,13 @@ _PushDirtyTileX
|
||||||
bpl :occupied2
|
bpl :occupied2
|
||||||
|
|
||||||
txa ; any non-negative value will work, this saves work below
|
txa ; any non-negative value will work, this saves work below
|
||||||
stal TileStore+TS_DIRTY,x ; and is 1 cycle fater than loading a constanct value
|
stal TileStore+TS_DIRTY,x ; and is 1 cycle faster than loading a constant value
|
||||||
|
|
||||||
; txa
|
|
||||||
ldx DirtyTileCount ; 5
|
ldx DirtyTileCount ; 5
|
||||||
sta DirtyTiles,x ; 5
|
sta DirtyTiles,x ; 5
|
||||||
|
|
||||||
inx
|
inx
|
||||||
inx
|
inx
|
||||||
stx DirtyTileCount
|
stx DirtyTileCount
|
||||||
|
|
||||||
; Same speed, but preserved the X register
|
|
||||||
; sta (DirtyTiles) ; 6
|
|
||||||
; lda DirtyTiles ; 4
|
|
||||||
; inc ; 2
|
|
||||||
; inc ; 2
|
|
||||||
; sta DirtyTiles ; 4
|
|
||||||
|
|
||||||
rts
|
rts
|
||||||
:occupied2
|
:occupied2
|
||||||
txa ; Make sure TileStore offset is returned in the accumulator
|
txa ; Make sure TileStore offset is returned in the accumulator
|
||||||
|
|
Loading…
Reference in New Issue
Block a user