mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-06-07 11:29:33 +00:00
commit
93ed3b3f16
|
@ -36,7 +36,7 @@ DOWN_ARROW equ $0A
|
|||
ldy #0
|
||||
jsl SetPalette
|
||||
|
||||
ldx #256
|
||||
ldx #256 ; 32 x 22 playfield (704 tiles, $580 tiles)
|
||||
ldy #176
|
||||
jsl SetScreenMode
|
||||
|
||||
|
@ -44,12 +44,13 @@ DOWN_ARROW equ $0A
|
|||
jsr BG0SetUp
|
||||
|
||||
; Initialize the sprite's global position (this is tracked outside of the tile engine)
|
||||
stz PlayerX
|
||||
stz PlayerY
|
||||
lda #64
|
||||
sta PlayerX
|
||||
sta PlayerY
|
||||
stz MapScreenX
|
||||
stz MapScreenY
|
||||
|
||||
; Add a sprite to the engine and save it's sprite ID
|
||||
; Add a sprite to the engine and save its sprite
|
||||
SPRITE_ID equ {SPRITE_16X16+1}
|
||||
OKTOROK equ {SPRITE_16X16+79}
|
||||
|
||||
|
@ -63,25 +64,25 @@ OKTOROK equ {SPRITE_16X16+79}
|
|||
sta PlayerID
|
||||
|
||||
; Add 4 octoroks
|
||||
lda #OKTOROK
|
||||
ldx #32
|
||||
ldy #48
|
||||
jsl AddSprite
|
||||
; lda #OKTOROK
|
||||
; ldx #32
|
||||
; ldy #48
|
||||
; jsl AddSprite
|
||||
|
||||
lda #OKTOROK
|
||||
ldx #96
|
||||
ldy #32
|
||||
jsl AddSprite
|
||||
; lda #OKTOROK
|
||||
; ldx #96
|
||||
; ldy #32
|
||||
; jsl AddSprite
|
||||
|
||||
lda #OKTOROK
|
||||
ldx #56
|
||||
ldy #96
|
||||
jsl AddSprite
|
||||
; lda #OKTOROK
|
||||
; ldx #56
|
||||
; ldy #96
|
||||
; jsl AddSprite
|
||||
|
||||
lda #OKTOROK
|
||||
ldx #72
|
||||
ldy #96
|
||||
jsl AddSprite
|
||||
; lda #OKTOROK
|
||||
; ldx #72
|
||||
; ldy #96
|
||||
; jsl AddSprite
|
||||
|
||||
; Draw the initial screen
|
||||
|
||||
|
@ -89,6 +90,7 @@ OKTOROK equ {SPRITE_16X16+79}
|
|||
tsb DirtyBits
|
||||
jsl Render
|
||||
|
||||
|
||||
; 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
|
||||
; the play field tiles.
|
||||
|
@ -179,10 +181,10 @@ EvtLoop
|
|||
lda vsync
|
||||
beq :no_vsync
|
||||
:vsyncloop jsl GetVerticalCounter ; 8-bit value
|
||||
cmp ScreenY1
|
||||
cmp ScreenY0
|
||||
bcc :vsyncloop
|
||||
sec
|
||||
sbc ScreenY1
|
||||
sbc ScreenY0
|
||||
cmp #8
|
||||
bcs :vsyncloop ; Wait until we're within the top 8 scanlines
|
||||
lda #1
|
||||
|
|
|
@ -35,3 +35,9 @@
|
|||
ASM SprMask.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
SNA SPRMASK
|
||||
|
||||
; Segment #6 -- 64KB Tile Store
|
||||
|
||||
ASM TileStore.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
SNA TSTORE
|
||||
|
|
2
demos/zelda/TileStore.s
Normal file
2
demos/zelda/TileStore.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
TileStore ENT
|
||||
ds 65536
|
|
@ -158,34 +158,6 @@ asr8 mac
|
|||
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 variant to calculate inline from any source
|
||||
_SpriteVBuffAddr mac
|
||||
lda ]2
|
||||
clc
|
||||
adc #NUM_BUFF_LINES
|
||||
xba
|
||||
adc ]1
|
||||
<<<
|
||||
|
||||
; Macro to define script steps
|
||||
ScriptStep MAC
|
||||
IF #=]5
|
||||
|
|
104
src/Core.s
104
src/Core.s
|
@ -12,14 +12,76 @@
|
|||
NO_INTERRUPTS equ 1 ; turn off for crossrunner debugging
|
||||
NO_MUSIC equ 1 ; turn music + tool loading off
|
||||
|
||||
; External data provided by the main program segment
|
||||
; External data space provided by the main program segment
|
||||
tiledata EXT
|
||||
TileStore EXT
|
||||
|
||||
; Sprite plane data and mask banks are provided as an exteral segment
|
||||
;
|
||||
; The sprite data holds a set of pre-rendered sprites that are optimized to support the rendering pipeline. There
|
||||
; are four copies of each sprite, along with the cooresponding mask laid out into 4x4 tile regions where the
|
||||
; empty row and column is shared between adjacent blocks.
|
||||
;
|
||||
; Logically, the memory is laid out as 4 columns of sprites and 4 rows.
|
||||
;
|
||||
; +---+---+---+---+---+---+---+---+---+---+---+---+-...
|
||||
; | | | | | | | | | | | | | ...
|
||||
; +---+---+---+---+---+---+---+---+---+---+---+---+-...
|
||||
; | | 0 | 0 | | 1 | 1 | | 2 | 2 | | 3 | 3 | ...
|
||||
; +---+---+---+---+---+---+---+---+---+---+---+---+-...
|
||||
; | | 0 | 0 | | 1 | 1 | | 2 | 2 | | 3 | 3 | ...
|
||||
; +---+---+---+---+---+---+---+---+---+---+---+---+-...
|
||||
; | | | | | | | | | | | | | ...
|
||||
; +---+---+---+---+---+---+---+---+---+---+---+---+-...
|
||||
; | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 7 | 7 | ...
|
||||
; +---+---+---+---+---+---+---+---+---+---+---+---+-...
|
||||
; | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 7 | 7 | ...
|
||||
; +---+---+---+---+---+---+---+---+---+---+---+---+-...
|
||||
; | | | | | | | | | | | | | ...
|
||||
; +---+---+---+---+---+---+---+---+---+---+---+---+-...
|
||||
;
|
||||
; For each sprite, when it needs to be copied into an on-screen tile, it could exist at any offset compared to its
|
||||
; natural alignment. By having a buffer around the sprite data, an address pointer can be set to a different origin
|
||||
; and a simple 8x8 block copy can cut out the appropriate bit of the sprite. For example, here is a zoomed-in look
|
||||
; at a sprite with an offset, O, at (-2,-3). As shown, by selecting an appropriate origin, just the top corner
|
||||
; of the sprite data will be copied.
|
||||
;
|
||||
; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+..
|
||||
; | | || | || | | | || | | | |
|
||||
; +---+-- O----------------+ --+---++---+---+---+---++---+---+---+---+..
|
||||
; | | | | | || | | | || | | | |
|
||||
; +---+-- | | --+---++---+---+---+---++---+---+---+---+..
|
||||
; | | | | | || | | | || | | | |
|
||||
; +---+-- | | --+---++---+---+---+---++---+---+---+---+..
|
||||
; | | | | | || | | | || | | | |
|
||||
; +===+== | ++===+== | ==+===++===+===+===+===++===+===+===+===+..
|
||||
; | | | || | S | S | S || S | S | S | || | | | |
|
||||
; +---+-- +----------------+ --+---++---+---+---+---++---+---+---+---+..
|
||||
; | | || S | S S | S || S | S | S | S || | | | |
|
||||
; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+..
|
||||
; | | | | || S | S | S | S || S | S | S | S || | | | |
|
||||
; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+..
|
||||
; | | | | || S | S | S | S || S | S | S | S || | | | |
|
||||
; +===+===+===+===++===+===+===+===++===+===+===+===++===+===+===+===+..
|
||||
; | | | | || S | S | S | S || S | S | S | S || | | | |
|
||||
; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+..
|
||||
; | | | | || S | S | S | S || S | S | S | S || | | | |
|
||||
; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+..
|
||||
; | | | | || S | S | S | S || S | S | S | S || | | | |
|
||||
; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+..
|
||||
; | | | | || | S | S | S || S | S | S | || | | | |
|
||||
; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+..
|
||||
; . . . . . . . . . . . . . . . . .
|
||||
;
|
||||
; Each sprite will take up, effectively 9 tiles of storage space per
|
||||
; instance (plus edges) and there are 4 instances for the H/V bits
|
||||
; and 4 more for the masks. This results in a need for 43,264 bytes
|
||||
; for all 16 sprites.
|
||||
|
||||
spritedata EXT
|
||||
spritemask EXT
|
||||
|
||||
; IF there are overlays, they are provided as an external
|
||||
; If there are overlays, they are provided as an external
|
||||
Overlay EXT
|
||||
|
||||
; Core engine functionality. The idea is that that source file can be PUT into
|
||||
|
@ -258,16 +320,29 @@ EngineReset
|
|||
stz SCBArrayPtr
|
||||
stz SCBArrayPtr+2
|
||||
|
||||
stz SpriteBanks
|
||||
stz SpriteMap
|
||||
stz ActiveSpriteCount
|
||||
|
||||
stz OneSecondCounter
|
||||
|
||||
]step equ 0
|
||||
lup 13
|
||||
lda #13
|
||||
sta tmp15
|
||||
stz tmp14
|
||||
|
||||
:loop
|
||||
ldx #BlitBuff
|
||||
lda #^BlitBuff
|
||||
ldy #]step
|
||||
ldy tmp14
|
||||
jsr BuildBank
|
||||
]step equ ]step+4
|
||||
--^
|
||||
|
||||
lda tmp14
|
||||
clc
|
||||
adc #4
|
||||
sta tmp14
|
||||
|
||||
dec tmp15
|
||||
bne :loop
|
||||
|
||||
rts
|
||||
|
||||
|
@ -285,12 +360,13 @@ EngineReset
|
|||
; 7. Ancient Land of Y's : 36 x 16 288 x 128 (18,432 bytes ( 57.6%))
|
||||
; 8. Game Boy Color : 20 x 18 160 x 144 (11,520 bytes ( 36.0%))
|
||||
; 9. Agony (Amiga) : 36 x 24 288 x 192 (27,648 bytes ( 86.4%))
|
||||
; 10. Atari Lynx : 20 x 13 160 x 102 (8,160 bytes ( 25.5%))
|
||||
;
|
||||
; X = mode number OR width in pixels (must be multiple of 2)
|
||||
; Y = height in pixels (if X > 8)
|
||||
|
||||
ScreenModeWidth dw 320,272,256,256,280,256,240,288,160,320
|
||||
ScreenModeHeight dw 200,192,200,176,160,160,160,128,144,1
|
||||
ScreenModeWidth dw 320,272,256,256,280,256,240,288,160,288,160,320
|
||||
ScreenModeHeight dw 200,192,200,176,160,160,160,128,144,192,102,1
|
||||
|
||||
SetScreenMode ENT
|
||||
phb
|
||||
|
@ -301,8 +377,8 @@ SetScreenMode ENT
|
|||
rtl
|
||||
|
||||
_SetScreenMode
|
||||
cpx #9
|
||||
bcs :direct ; if x > 8, then assume X and Y are the dimensions
|
||||
cpx #11
|
||||
bcs :direct ; if x > 10, then assume X and Y are the dimensions
|
||||
|
||||
txa
|
||||
asl
|
||||
|
@ -411,10 +487,14 @@ _ReadControl
|
|||
pla
|
||||
rts
|
||||
|
||||
put blitter/Template.s
|
||||
|
||||
put Memory.s
|
||||
put Graphics.s
|
||||
put Sprite.s
|
||||
put blitter/Tiles.s
|
||||
put Sprite2.s
|
||||
put SpriteRender.s
|
||||
put Render.s
|
||||
put Timer.s
|
||||
put Script.s
|
||||
|
@ -422,8 +502,6 @@ _ReadControl
|
|||
put blitter/Horz.s
|
||||
put blitter/PEISlammer.s
|
||||
put blitter/Tables.s
|
||||
put blitter/Template.s
|
||||
put blitter/Tiles.s
|
||||
put blitter/Tiles00000.s ; normal tiles
|
||||
put blitter/Tiles00001.s ; dynamic tiles
|
||||
put blitter/Tiles00010.s ; normal masked tiles
|
||||
|
|
28
src/Defs.s
28
src/Defs.s
|
@ -81,14 +81,14 @@ BG1TileMapPtr equ 86
|
|||
SCBArrayPtr equ 90 ; Used for palette binding
|
||||
SpriteBanks equ 94 ; Bank bytes for the sprite data and sprite mask
|
||||
LastRender equ 96 ; Record which reder function was last executed
|
||||
DamagedSprites equ 98
|
||||
; DamagedSprites equ 98
|
||||
SpriteMap equ 100 ; Bitmap of open sprite slots.
|
||||
Next equ 102
|
||||
|
||||
BankLoad equ 128
|
||||
ActiveSpriteCount equ 102
|
||||
BankLoad equ 104
|
||||
Next equ 106
|
||||
|
||||
activeSpriteList equ 128 ; 32 bytes for the active sprite list (can persist across frames)
|
||||
AppSpace equ 160 ; 16 bytes of space reserved for application use
|
||||
|
||||
tiletmp equ 178 ; 16 bytes of temp storage for the tile renderers
|
||||
blttmp equ 192 ; 32 bytes of local cache/scratch space for blitter
|
||||
|
||||
|
@ -154,13 +154,13 @@ SPRITE_HFLIP equ $0200
|
|||
MAX_TILES equ {26*41} ; Number of tiles in the code field (41 columns * 26 rows)
|
||||
TILE_STORE_SIZE equ {MAX_TILES*2} ; The tile store contains a tile descriptor in each slot
|
||||
|
||||
TS_TILE_ID equ TILE_STORE_SIZE*0
|
||||
TS_DIRTY equ TILE_STORE_SIZE*1
|
||||
TS_SPRITE_FLAG equ TILE_STORE_SIZE*2
|
||||
TS_TILE_ADDR equ TILE_STORE_SIZE*3 ; const value
|
||||
TS_CODE_ADDR_LOW equ TILE_STORE_SIZE*4 ; const value
|
||||
TS_TILE_ID equ TILE_STORE_SIZE*0 ; tile descriptor for this location
|
||||
TS_DIRTY equ TILE_STORE_SIZE*1 ; Flag. Used to prevent a tile from being queues multiple times per frame
|
||||
TS_SPRITE_FLAG equ TILE_STORE_SIZE*2 ; Bitfield of all sprites that intersect this tile. 0 if no sprites.
|
||||
TS_TILE_ADDR equ TILE_STORE_SIZE*3 ; cached value, the address of the tiledata for this tile
|
||||
TS_CODE_ADDR_LOW equ TILE_STORE_SIZE*4 ; const value, address of this tile in the code fields
|
||||
TS_CODE_ADDR_HIGH equ TILE_STORE_SIZE*5 ; const value
|
||||
TS_WORD_OFFSET equ TILE_STORE_SIZE*6
|
||||
TS_BASE_ADDR equ TILE_STORE_SIZE*7
|
||||
TS_SPRITE_ADDR equ TILE_STORE_SIZE*8
|
||||
TS_SCREEN_ADDR equ TILE_STORE_SIZE*9
|
||||
TS_WORD_OFFSET equ TILE_STORE_SIZE*6 ; const value, word offset value for this tile if LDA (dp),y instructions re used
|
||||
TS_BASE_ADDR equ TILE_STORE_SIZE*7 ; const value, because there are two rows of tiles per bank, this is set to $0000 ot $8000.
|
||||
TS_SCREEN_ADDR equ TILE_STORE_SIZE*8 ; cached value of on-screen location of tile. Used for DirtyRender.
|
||||
TS_VBUFF_ARRAY_ADDR equ TILE_STORE_SIZE*9 ; const value to an aligned 32-byte array starting at $8000 in TileStore bank
|
||||
|
|
|
@ -57,13 +57,12 @@ GetTileAddr EXT
|
|||
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
|
||||
ApplyTiles EXT ; Drain the dirty tile queue and call RenderTile on each
|
||||
RenderTile EXT ; Y = address from GetTileStoreOffset
|
||||
GetTileStoreOffset EXT ; X = column, Y = row
|
||||
TileStore EXT ; Tile store internal data structure
|
||||
|
||||
RenderDirty EXT ; Render only dirty tiles + sprites directly to the SHR screen
|
||||
|
||||
GetSpriteVBuffAddr EXT ; X = x-coordinate (0 - 159), Y = y-coordinate (0 - 199). Return in Acc.
|
||||
; GetSpriteVBuffAddr EXT ; X = x-coordinate (0 - 159), Y = y-coordinate (0 - 199). Return in Acc.
|
||||
|
||||
; Allocate a full 64K bank
|
||||
AllocBank EXT
|
||||
|
|
|
@ -32,4 +32,64 @@ The engine run through the following render loop on every frame
|
|||
|
||||
* The dirty tile list has a fast test to see if a tile has already been marked as dirty it is not added twice
|
||||
* The tile renderer is where data from the sprite plane is combined with tile data to show the sprites on-screen.
|
||||
* Typically, there will not be Overlays defined and the last step of the renderer is just a single render of all playfield lines at once.
|
||||
* Typically, there will not be Overlays defined and the last step of the renderer is just a single render of all playfield lines at once.
|
||||
|
||||
= Sprite Redesign =
|
||||
|
||||
In the rendering function, for a given TileStore location, we need to be able to read and array of VBUFF addresses
|
||||
for sprite data. This can be done by processing the SPRITE_BIT array in to a list to get a set of offsets. These
|
||||
VBUFF addresses also need to be set. Currently we are calculating the addresses in the sprite functions, but the
|
||||
issue is that we need to find an addressing scheme that's essentially 2D because we have >TileStore+VARNAME,x and
|
||||
Sprite+VARNAME,y, but we need something like >TileStore+VARNAME[x][y]
|
||||
|
||||
In a perfect scenario, we can use the following code sequence to render stacked sprites
|
||||
|
||||
lda tiledata,y ; tile addressed (bank register set)
|
||||
ldx activeSprite+4 ; sprite VBUFF address cached on direct page
|
||||
andl >spritemask,x
|
||||
oral >spritedata,x
|
||||
ldx activeSprite+2
|
||||
andl >spritemask,x
|
||||
oral >spritedata,x
|
||||
ldx activeSprite
|
||||
andl >spritemask,x
|
||||
oral >spritedata,x
|
||||
sta tmp0
|
||||
|
||||
|
||||
; Core phases
|
||||
|
||||
; Convert bit field to compact array of sprite indexes
|
||||
lda TileStore+VBUFF_ARR_PTR,x
|
||||
sta cache
|
||||
lda TileStore+SPRITE_BITS,x
|
||||
bit #$0008
|
||||
bne ...
|
||||
|
||||
lda cache ; This is 11 cycles. A PEA + TSB is 13, so a bit faster to do it at once
|
||||
ora #$0006
|
||||
pha
|
||||
|
||||
; When storing for a sprite, the corner VBUFF is calulated and stored at
|
||||
|
||||
base = TileStore+VBUFF_ARR_ADDR,x + SPRITE_ID
|
||||
|
||||
sta base
|
||||
sta base+32 ; next column (mod columns)
|
||||
sta base+(32*width) ; next row
|
||||
sta base+(32*width+32) ; next corner
|
||||
|
||||
Possibilities
|
||||
|
||||
1. Have >TileStore+SPRITE_VBUFF be the address to an array and then manually add the y-register value so we can still use
|
||||
absolute addressing
|
||||
|
||||
tya
|
||||
adc >TileStore+SPRITE_VBUFF_ARR_ADDR,x ; Points to addreses 32 bytes apart ad Y-reg is [0, 30]
|
||||
tax
|
||||
lda >TileStore,x ; Load the address
|
||||
tay
|
||||
|
||||
lda 0000,y
|
||||
lda 0002,y
|
||||
...
|
||||
|
|
202
src/Render.s
202
src/Render.s
|
@ -46,7 +46,7 @@
|
|||
; edges of the rendered play field.
|
||||
|
||||
|
||||
; The render function is the point of committment -- most of the APIs that set sprintes and
|
||||
; The render function is the point of committment -- most of the APIs that set sprites and
|
||||
; update coordinates are lazy; they simply save the value and set a dirty flag in the
|
||||
; DirtyBits word.
|
||||
;
|
||||
|
@ -78,11 +78,13 @@ _Render
|
|||
jsr _ApplyBG0XPosPre
|
||||
jsr _ApplyBG1XPosPre
|
||||
|
||||
nop
|
||||
jsr _RenderSprites ; Once the BG0 X and Y positions are committed, update sprite data
|
||||
|
||||
jsr _UpdateBG0TileMap ; and the tile maps. These subroutines build up a list of tiles
|
||||
jsr _UpdateBG1TileMap ; that need to be updated in the code field
|
||||
|
||||
nop
|
||||
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||
|
||||
jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode
|
||||
|
@ -90,7 +92,7 @@ _Render
|
|||
|
||||
; 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
|
||||
; optimization that can be done here is that the lines can be rendered in any order
|
||||
|
@ -102,27 +104,27 @@ _Render
|
|||
|
||||
; Turn shadowing back on
|
||||
|
||||
jsr _ShadowOn
|
||||
; jsr _ShadowOn
|
||||
|
||||
; 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
|
||||
clc
|
||||
adc #0
|
||||
asl
|
||||
tax
|
||||
lda ScreenAddr,x
|
||||
clc
|
||||
adc ScreenX0
|
||||
; lda ScreenY0 ; pass the address of the first line of the overlay
|
||||
; clc
|
||||
; adc #0
|
||||
; asl
|
||||
; tax
|
||||
; lda ScreenAddr,x
|
||||
; clc
|
||||
; adc ScreenX0
|
||||
; jsl Overlay
|
||||
|
||||
ldx #0 ; Blit the full virtual buffer to the screen
|
||||
ldy ScreenHeight
|
||||
jsr _BltRange
|
||||
|
||||
; ldx #0
|
||||
; ldy ScreenHeight
|
||||
; jsr _BltSCB
|
||||
ldx #0
|
||||
ldy ScreenHeight
|
||||
jsr _BltSCB
|
||||
|
||||
lda StartY ; Restore the fields back to their original state
|
||||
ldx ScreenHeight
|
||||
|
@ -139,10 +141,10 @@ _Render
|
|||
sta OldBG1StartX
|
||||
|
||||
stz DirtyBits
|
||||
stz LastRender
|
||||
stz LastRender ; Mark that a full render was just performed
|
||||
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
|
||||
; 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
|
||||
|
@ -184,35 +186,50 @@ _ApplyDirtyTiles
|
|||
|
||||
; Loop again until the list of dirty tiles is empty
|
||||
|
||||
:begin ldx DirtyTileCount
|
||||
:begin ldy DirtyTileCount
|
||||
bne :loop
|
||||
rts
|
||||
|
||||
; Only render solid tiles and sprites
|
||||
_RenderDirtyTile
|
||||
pea >TileStore ; Need that addressing flexibility here. Callers responsible for restoring bank reg
|
||||
plb
|
||||
plb
|
||||
txy
|
||||
|
||||
lda 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
|
||||
|
||||
jsr BuildActiveSpriteArray ; Build the sprite index list from the bit field
|
||||
sta ActiveSpriteCount
|
||||
|
||||
lda TileStore+TS_VBUFF_ARRAY_ADDR,y ; Scratch space
|
||||
sta _SPR_X_REG
|
||||
phy
|
||||
ldy spriteIdx
|
||||
lda (_SPR_X_REG),y
|
||||
sta _SPR_X_REG
|
||||
ply
|
||||
|
||||
lda TileStore+TS_TILE_ID,y ; build the finalized tile descriptor
|
||||
and #TILE_VFLIP_BIT+TILE_HFLIP_BIT ; get the lookup value
|
||||
xba
|
||||
|
||||
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
|
||||
|
||||
ldx TileStore+TS_SPRITE_ADDR,y
|
||||
stx _SPR_X_REG
|
||||
|
||||
tax
|
||||
lda DirtyTileSpriteProcs,x
|
||||
sta :tiledisp+1
|
||||
ldal DirtyTileSpriteProcs,x
|
||||
stal :tiledisp+1
|
||||
bra :sprite
|
||||
|
||||
:nosprite
|
||||
lda TileStore+TS_TILE_ID,y ; build the finalized tile descriptor
|
||||
and #TILE_VFLIP_BIT+TILE_HFLIP_BIT ; get the lookup value
|
||||
xba
|
||||
tax
|
||||
lda DirtyTileProcs,x ; load and patch in the appropriate subroutine
|
||||
sta :tiledisp+1
|
||||
ldal DirtyTileProcs,x ; load and patch in the appropriate subroutine
|
||||
stal :tiledisp+1
|
||||
|
||||
:sprite
|
||||
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
||||
lda TileStore+TS_SCREEN_ADDR,y ; Get the on-screen address of this tile
|
||||
lda TileStore+TS_SCREEN_ADDR,y ; Get the on-screen address of this tile
|
||||
pha
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,y
|
||||
|
@ -268,7 +285,11 @@ _TBDirtySpriteTile_VH
|
|||
jsr _TBCopyTileDataToCBuffV
|
||||
jmp _TBApplyDirtySpriteData
|
||||
|
||||
|
||||
; Just copy in the data from the first sprite
|
||||
_TBApplyDirtySpriteData
|
||||
|
||||
_TBApplyDirtySpriteData0
|
||||
ldx _SPR_X_REG ; set to the unaligned tile block address in the sprite plane
|
||||
|
||||
]line equ 0
|
||||
|
@ -284,4 +305,125 @@ _TBApplyDirtySpriteData
|
|||
sta: $0002+{]line*160},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
rts
|
||||
|
||||
; Input: A = bit field, assumed non-zero
|
||||
; Output: A = number of bits set
|
||||
; Side Effect: Fill in the ActiveSprite list with sprite indices.
|
||||
;
|
||||
; We try very hard to be fast and clever here. Early out, keeping everything in
|
||||
; registers when possible, and reducing overhead.
|
||||
|
||||
spriteIdx equ tmp12
|
||||
BuildActiveSpriteArray
|
||||
|
||||
; Push a sentinel value on the stack so we know where to end later. We con't count during the
|
||||
; initial process, because the Z flag needs to be maintained and almost evey opcode affects it.
|
||||
|
||||
; cmp lastActiveValue ; Assume that there is a decent chance of having the same
|
||||
; beq early_out ; sprite bitfield in consecutive dirty tiles. Saves a lot.
|
||||
|
||||
tsx ; save the stack pointer
|
||||
pea $FFFF ; sentinel value
|
||||
|
||||
; This first loop scans the bits in the accumulator and pushed a sprite index onto the stack. We
|
||||
; could push any constanct, which gives us some flexibility. This only works because the PEA
|
||||
; instruction does not affect any register. We also check to see if the acumulator is zero as
|
||||
; an early-out test, but only do that every 4 bits in order to amortize the overhead a bit.
|
||||
|
||||
]step equ 0
|
||||
lup 4
|
||||
lsr
|
||||
bcc :skip_1
|
||||
pea ]step
|
||||
:skip_1 lsr
|
||||
bcc :skip_2
|
||||
pea ]step+2
|
||||
:skip_2 lsr
|
||||
bcc :skip_3
|
||||
pea ]step+4
|
||||
:skip_3 lsr
|
||||
bcc :skip_4
|
||||
pea ]step+6
|
||||
:skip_4 beq :end_1
|
||||
]step equ ]step+8
|
||||
--^
|
||||
:end_1
|
||||
|
||||
; This second loop pops values off of the stack and places them into a linear array. We also
|
||||
; set the count on exit. As an optimization / restriction, we only allow up to four overlapping
|
||||
; sprites. This is similar to the NES/C64 "8 sprites per line" restriction.
|
||||
|
||||
pla ; Can always assume at least one bit was set...
|
||||
sta spriteIdx
|
||||
|
||||
pla
|
||||
bmi :out_1
|
||||
sta spriteIdx+2
|
||||
|
||||
pla
|
||||
bmi :out_2
|
||||
sta spriteIdx+4
|
||||
|
||||
pla
|
||||
bmi :out_3
|
||||
sta spriteIdx+6
|
||||
|
||||
; Reset the stack point if we did not pop everything off yet
|
||||
txs
|
||||
|
||||
; These are the exit points which know exactly how many items (x2) have been processed
|
||||
:out_4 lda #8
|
||||
rts
|
||||
:out_0 lda #0
|
||||
rts
|
||||
:out_1 lda #2
|
||||
rts
|
||||
:out_2 lda #4
|
||||
rts
|
||||
:out_3 lda #6
|
||||
rts
|
||||
|
||||
; Run through all of the active sprites and put then on-screen. We have three different heuristics depending on
|
||||
; how many active sprites there are intersecting this tile.
|
||||
|
||||
; Version 2. No sprite place, instead each sprite has a set of pre-rendered panels and we render from
|
||||
; those panels in tile-sized blocks.
|
||||
;
|
||||
; If there is only one sprite + tile background, then we can render directly to the screen
|
||||
;
|
||||
; ldal tiledata+0,x
|
||||
; and sprite+MASK_OFFSET,y
|
||||
; ora sprite,y
|
||||
; sta 00
|
||||
; ...
|
||||
; sta 02
|
||||
; ...
|
||||
; sta A0
|
||||
; ...
|
||||
; sta A2
|
||||
; tdc
|
||||
; adc #320
|
||||
; tcd
|
||||
;
|
||||
; Since this is a common case, it is reasonable to do so. Otherwise, we must explode the TS_SPRITE_FLAG to
|
||||
; get a list of sprite origin addresses and then flatten against the tile
|
||||
;
|
||||
; ldal tiledata+0,x
|
||||
; ldx spriteCount
|
||||
; jmp (disp,x)
|
||||
; ...
|
||||
; ldy list+2
|
||||
; and sprite+MASK_OFFSET,y
|
||||
; ora sprite,y
|
||||
; ldy list
|
||||
; and sprite+MASK_OFFSET,y
|
||||
; ora sprite,y
|
||||
; sta 00
|
||||
|
||||
; sta 02
|
||||
; sta A0
|
||||
; sta A2
|
||||
; tdc
|
||||
; adc #320
|
||||
; tcd
|
1138
src/Sprite.s
1138
src/Sprite.s
File diff suppressed because it is too large
Load Diff
242
src/Sprite2.s
242
src/Sprite2.s
|
@ -64,7 +64,7 @@ _LocalToTileStore
|
|||
; code field offsets and then cache variations of this value needed in the rest of the subroutine
|
||||
;
|
||||
; The SpriteX is always the MAXIMUM value of the corner coordinates. We subtract (SpriteX + StartX) mod 4
|
||||
; to find the coordinate in the sprite plane that matches up with the tile in the play field and
|
||||
; to find the coordinate in the sprite cache that matches up with the tile in the play field and
|
||||
; then use that to calculate the VBUFF address from which to copy sprite data.
|
||||
;
|
||||
; StartX SpriteX z = * mod 4 (SpriteX - z)
|
||||
|
@ -92,36 +92,35 @@ _MarkDirtySprite
|
|||
lda _Sprites+IS_OFF_SCREEN,y ; Check if the sprite is visible in the playfield
|
||||
bne mdsOut
|
||||
|
||||
; At this point we know that we have to update the tiles that overlap the sprite plane rectangle defined
|
||||
; by (Top, Left), (Bottom, Right). The general process is to figure out the top-left coordinate in the
|
||||
; sprite plane that matches up with the code field and then calculate the number of tiles in each direction
|
||||
; that need to be dirtied to cover the sprite.
|
||||
; At this point we know that we have to update the tiles that overlap the sprite's rectangle defined
|
||||
; by (Top, Left), (Bottom, Right). First, calculate the row and column in the TileStore that
|
||||
; encloses the top-left on-screen corner of the sprite
|
||||
|
||||
clc
|
||||
lda _Sprites+SPRITE_CLIP_TOP,y
|
||||
adc StartYMod208 ; Adjust for the scroll offset (could be a negative number!)
|
||||
tax ; Save this value
|
||||
and #$0007 ; Get (StartY + SpriteY) mod 8
|
||||
eor #$FFFF
|
||||
inc
|
||||
clc
|
||||
adc _Sprites+SPRITE_CLIP_TOP,y ; subtract from the Y position (possible to go negative here)
|
||||
sta TileTop ; This position will line up with the tile that the sprite overlaps with
|
||||
|
||||
txa ; Get back the position of the sprite top in the code field
|
||||
adc StartYMod208 ; Adjust for the scroll offset
|
||||
tax ; cache
|
||||
cmp #208 ; check if we went too far positive
|
||||
bcc *+5
|
||||
sbc #208
|
||||
lsr
|
||||
lsr
|
||||
; lsr ; This is the row in the Tile Store for top-left corner of the sprite
|
||||
and #$FFFE ; Store the pre-multiplied by 2 for indexing in the :mark_R_C routines
|
||||
lsr ; This is the row in the Tile Store for top-left corner of the sprite
|
||||
and #$FFFE ; Store the value pre-multiplied by 2 for indexing in the :mark_R_C routines
|
||||
sta RowTop
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_BOTTOM,y ; Figure out how many tiles are needed to cover the sprite's area
|
||||
sec
|
||||
sbc TileTop
|
||||
and #$0018 ; Clear out the lower bits and stash in bits 4 and 5
|
||||
; Next, calculate how many tiles are covered by the sprite. This uses the table at the top of this function, but
|
||||
; the idea is that for every increment of StartX or StartY, that can shift the sprite into the next tile, up to
|
||||
; a maximum of mod 4 / mod 8. So the effective width of a sprite is (((StartX + Clip_Left) mod 4) + Clip_Width) / 4
|
||||
|
||||
txa
|
||||
and #$0007
|
||||
sta tmp0 ; save to adjust sprite origin
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_HEIGHT,y ; Nominal value between 0 and 16+7 = 23 = 10111
|
||||
dec
|
||||
clc
|
||||
adc tmp0
|
||||
and #$0018
|
||||
sta AreaIndex
|
||||
|
||||
; Repeat to get the same information for the columns
|
||||
|
@ -130,60 +129,61 @@ _MarkDirtySprite
|
|||
lda _Sprites+SPRITE_CLIP_LEFT,y
|
||||
adc StartXMod164
|
||||
tax
|
||||
and #$0003
|
||||
eor #$FFFF
|
||||
inc
|
||||
clc
|
||||
adc _Sprites+SPRITE_CLIP_LEFT,y
|
||||
sta TileLeft
|
||||
|
||||
txa
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
lsr
|
||||
; lsr
|
||||
and #$FFFE ; Same pre-multiply by 2 for later
|
||||
sta ColLeft
|
||||
|
||||
; Calculate the offset into the TileStore lookup array for the top-left tile
|
||||
|
||||
; ldx RowTop
|
||||
; lda ColLeft
|
||||
; clc
|
||||
; adc TileStore2DYTable,x ; Fixed offset to the next row
|
||||
; sta Origin ; This is the index into the TileStore2DLookup table
|
||||
|
||||
; Sneak a pre-calculation here. Calculate the tile-aligned upper-left corner of the sprite in the sprite plane.
|
||||
; We can reuse this in all of the routines below. This is not the (x,y) of the sprite itself, but
|
||||
; the corner of the tile it overlaps with
|
||||
txa
|
||||
and #$0003
|
||||
sta tmp1 ; save to adjust sprite origin
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_WIDTH,y ; max width = 8 = 0x08
|
||||
dec
|
||||
clc
|
||||
lda TileTop
|
||||
adc #NUM_BUFF_LINES
|
||||
xba
|
||||
clc
|
||||
adc TileLeft
|
||||
sta VBuffOrigin ; Save once to use later (constant offsets)
|
||||
|
||||
; Calculate the number of columns and dispatch
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_RIGHT,y
|
||||
sec
|
||||
sbc TileLeft
|
||||
and #$000C
|
||||
lsr ; bit 0 is always zero and width stored in bits 1 and 2
|
||||
adc tmp1
|
||||
lsr ; max value = 4 = 0x04
|
||||
and #$0006
|
||||
ora AreaIndex
|
||||
sta AreaIndex
|
||||
pla
|
||||
|
||||
; Calculate the modified origin address for the sprite. We need to look at the sprite flip bits
|
||||
; to determine which of the four sprite stamps is the correct one to use. Then, offset that origin
|
||||
; based on the (x, y) and (startx, starty) positions.
|
||||
|
||||
lda _Sprites+SPRITE_DISP,y ; Each stamp is 12 bytes
|
||||
and #$0006
|
||||
tax
|
||||
lda :stamp_step,x
|
||||
clc
|
||||
adc _Sprites+VBUFF_ADDR,y
|
||||
sec
|
||||
sbc tmp1 ; Subtract the horizontal within-tile displacement
|
||||
asl tmp0
|
||||
ldx tmp0
|
||||
sec
|
||||
sbc :vbuff_mul,x
|
||||
sta VBuffOrigin
|
||||
lda #^TileStore
|
||||
sta tmp1
|
||||
|
||||
; Dispatch to cover the tiles
|
||||
|
||||
ldx AreaIndex
|
||||
jmp (:mark,x)
|
||||
:mark dw :mark1x1,:mark1x2,:mark1x3,mdsOut
|
||||
dw :mark2x1,:mark2x2,:mark2x3,mdsOut
|
||||
dw :mark3x1,:mark3x2,:mark3x3,mdsOut
|
||||
dw mdsOut,mdsOut,mdsOut,mdsOut
|
||||
|
||||
:stamp_step dw 0,12,24,36
|
||||
:vbuff_mul dw 0,52,104,156,208,260,312,364
|
||||
; Dispatch to the calculated sizing
|
||||
|
||||
; Begin a list of subroutines to cover all of the valid sprite size compinations. This is all unrolled code,
|
||||
; Begin a list of subroutines to cover all of the valid sprite size combinations. This is all unrolled code,
|
||||
; mainly to be able to do an unrolled fill of the TILE_STORE_ADDR_X values. Thus, it's important that the clipping
|
||||
; function does its job properly since it allows us to save a lot of time here.
|
||||
;
|
||||
|
@ -319,24 +319,22 @@ _MarkDirtySprite
|
|||
rts
|
||||
|
||||
; 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
|
||||
|
||||
:mark_0_0
|
||||
ldx RowTop
|
||||
lda ColLeft
|
||||
ldx RowTop
|
||||
lda ColLeft
|
||||
clc
|
||||
adc TileStoreYTable,x ; Fixed offset to the next row
|
||||
adc TileStoreYTable,x ; Fixed offset to the next row
|
||||
tax
|
||||
|
||||
; ldx Origin
|
||||
; lda TileStore2DLookup,x
|
||||
; tax ; This is the tile store offset
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin ; This is an interesting case. The mapping between the tile store
|
||||
lda VBuffOrigin
|
||||
sta [tmp0],y
|
||||
|
||||
; lda VBuffOrigin ; This is an interesting case. The mapping between the tile store
|
||||
; adc #{0*4}+{0*256} ; and the sprite buffers changes as the StartX, StartY values change
|
||||
sta TileStore+TS_SPRITE_ADDR,x ; but don't depend on any sprite information. However, by setting the
|
||||
; stal TileStore+TS_SPRITE_ADDR,x ; but don't depend on any sprite information. However, by setting the
|
||||
; value only for the tiles that get added to the dirty tile list, we
|
||||
; can avoid recalculating over 1,000 values whenever the screen scrolls
|
||||
; (which is common) and just limit it to the number of tiles covered by
|
||||
|
@ -344,10 +342,10 @@ _MarkDirtySprite
|
|||
; moving and they are being dirtied, then we may do more work, but the
|
||||
; odds are in our favor to just take care of it here.
|
||||
|
||||
lda TileStore+TS_SPRITE_FLAG,x
|
||||
; lda TileStore+TS_SPRITE_FLAG,x
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX ; Needs X = tile store offset; destroys A,X. Returns X in A
|
||||
|
||||
|
@ -358,13 +356,16 @@ _MarkDirtySprite
|
|||
adc TileStoreYTable+2,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{0*4}+{1*8*256}
|
||||
sta TileStore+TS_SPRITE_ADDR,x
|
||||
adc #{0*4}+{1*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
|
@ -375,13 +376,16 @@ _MarkDirtySprite
|
|||
adc TileStoreYTable+4,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{0*4}+{2*8*256}
|
||||
sta TileStore+TS_SPRITE_ADDR,x
|
||||
adc #{0*4}+{2*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
|
@ -393,13 +397,16 @@ _MarkDirtySprite
|
|||
adc TileStoreYTable,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{1*4}+{0*8*256}
|
||||
sta TileStore+TS_SPRITE_ADDR,x
|
||||
adc #{1*4}+{0*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
|
@ -411,13 +418,16 @@ _MarkDirtySprite
|
|||
adc TileStoreYTable+2,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{1*4}+{1*8*256}
|
||||
sta TileStore+TS_SPRITE_ADDR,x
|
||||
adc #{1*4}+{1*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
|
@ -429,13 +439,16 @@ _MarkDirtySprite
|
|||
adc TileStoreYTable+4,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{1*4}+{2*8*256}
|
||||
sta TileStore+TS_SPRITE_ADDR,x
|
||||
adc #{1*4}+{2*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
|
@ -447,13 +460,16 @@ _MarkDirtySprite
|
|||
adc TileStoreYTable,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{2*4}+{0*8*256}
|
||||
sta TileStore+TS_SPRITE_ADDR,x
|
||||
adc #{2*4}+{0*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
|
@ -465,13 +481,16 @@ _MarkDirtySprite
|
|||
adc TileStoreYTable+2,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{2*4}+{1*8*256}
|
||||
sta TileStore+TS_SPRITE_ADDR,x
|
||||
adc #{2*4}+{1*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
|
@ -483,13 +502,16 @@ _MarkDirtySprite
|
|||
adc TileStoreYTable+4,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{2*4}+{2*8*256}
|
||||
sta TileStore+TS_SPRITE_ADDR,x
|
||||
adc #{2*4}+{2*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
|
@ -500,12 +522,12 @@ _MarkDirtySprite
|
|||
; a value of zero means that all of the sprite's rows are off-screen.
|
||||
;
|
||||
; This subroutine takes are of calculating the extra tile for unaligned accesses, too.
|
||||
_SpriteHeight dw 8,8,16,16
|
||||
_SpriteHeightMinus1 dw 7,7,15,15
|
||||
_SpriteRows dw 1,1,2,2
|
||||
_SpriteWidth dw 4,8,4,8
|
||||
_SpriteWidthMinus1 dw 3,7,3,7
|
||||
_SpriteCols dw 1,2,1,2
|
||||
;_SpriteHeight dw 8,8,16,16
|
||||
;_SpriteHeightMinus1 dw 7,7,15,15
|
||||
;_SpriteRows dw 1,1,2,2
|
||||
;_SpriteWidth dw 4,8,4,8
|
||||
;_SpriteWidthMinus1 dw 3,7,3,7
|
||||
;_SpriteCols dw 1,2,1,2
|
||||
|
||||
; Convert sprite index to a bit position
|
||||
_SpriteBits dw $0001,$0002,$0004,$0008,$0010,$0020,$0040,$0080,$0100,$0200,$0400,$0800,$1000,$2000,$4000,$8000
|
||||
|
|
326
src/SpriteRender.s
Normal file
326
src/SpriteRender.s
Normal file
|
@ -0,0 +1,326 @@
|
|||
; Function to render a sprite from a sprite definition into the internal data buffers
|
||||
;
|
||||
; X = sprite index
|
||||
_DrawSpriteSheet
|
||||
DISP_VFLIP equ $0004 ; hard code these because they are internal values
|
||||
DISP_HFLIP equ $0002
|
||||
DISP_MASK equ $0018 ; Isolate the size bits
|
||||
|
||||
phx
|
||||
|
||||
lda _Sprites+VBUFF_ADDR,x
|
||||
sta tmp1
|
||||
|
||||
lda _Sprites+TILE_DATA_OFFSET,x
|
||||
sta tmp2
|
||||
|
||||
lda _Sprites+SPRITE_DISP,x
|
||||
and #DISP_MASK ; dispatch to all of the different orientations
|
||||
sta tmp3
|
||||
|
||||
; Set bank
|
||||
phb
|
||||
pea #^tiledata ; Set the bank to the tile data
|
||||
plb
|
||||
|
||||
ldx tmp3
|
||||
ldy tmp2
|
||||
lda tmp1
|
||||
jsr _DrawSprite
|
||||
|
||||
lda tmp3
|
||||
ora #DISP_HFLIP
|
||||
tax
|
||||
ldy tmp2
|
||||
lda tmp1
|
||||
clc
|
||||
adc #4*3
|
||||
jsr _DrawSprite
|
||||
|
||||
lda tmp3
|
||||
ora #DISP_VFLIP
|
||||
tax
|
||||
ldy tmp2
|
||||
lda tmp1
|
||||
clc
|
||||
adc #4*6
|
||||
jsr _DrawSprite
|
||||
|
||||
lda tmp3
|
||||
ora #DISP_HFLIP+DISP_VFLIP
|
||||
tax
|
||||
ldy tmp2
|
||||
lda tmp1
|
||||
clc
|
||||
adc #4*9
|
||||
jsr _DrawSprite
|
||||
|
||||
; Restore bank
|
||||
plb ; pop extra byte
|
||||
plb
|
||||
|
||||
plx
|
||||
rts
|
||||
;
|
||||
; X = _Sprites array offset
|
||||
_DrawSprite
|
||||
; ldx _Sprites+SPRITE_DISP,y ; use bits 9, 10, 11, 12 and 13 to dispatch
|
||||
jmp (draw_sprite,x)
|
||||
|
||||
draw_sprite dw draw_8x8,draw_8x8h,draw_8x8v,draw_8x8hv
|
||||
dw draw_8x16,draw_8x16h,draw_8x16v,draw_8x16hv
|
||||
dw draw_16x8,draw_16x8h,draw_16x8v,draw_16x8hv
|
||||
dw draw_16x16,draw_16x16h,draw_16x16v,draw_16x16hv
|
||||
|
||||
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
|
||||
|
||||
draw_8x8
|
||||
draw_8x8h
|
||||
tax
|
||||
jmp _DrawTile8x8
|
||||
|
||||
draw_8x8v
|
||||
draw_8x8hv
|
||||
tax
|
||||
jmp _DrawTile8x8V
|
||||
|
||||
draw_8x16
|
||||
draw_8x16h
|
||||
tax
|
||||
jsr _DrawTile8x8
|
||||
clc
|
||||
txa
|
||||
adc #{8*SPRITE_PLANE_SPAN}
|
||||
tax
|
||||
tya
|
||||
adc #{128*32} ; 32 tiles to the next vertical one, each tile is 128 bytes
|
||||
tay
|
||||
jmp _DrawTile8x8
|
||||
|
||||
draw_8x16v
|
||||
draw_8x16hv
|
||||
tax
|
||||
jsr _DrawTile8x8V
|
||||
clc
|
||||
txa
|
||||
adc #{8*SPRITE_PLANE_SPAN}
|
||||
tax
|
||||
tya
|
||||
adc #{128*32}
|
||||
tay
|
||||
jmp _DrawTile8x8V
|
||||
|
||||
draw_16x8
|
||||
tax
|
||||
jsr _DrawTile8x8
|
||||
clc
|
||||
txa
|
||||
adc #4
|
||||
tax
|
||||
tya
|
||||
adc #128 ; Next tile is 128 bytes away
|
||||
tay
|
||||
jmp _DrawTile8x8
|
||||
|
||||
draw_16x8h
|
||||
clc
|
||||
tax
|
||||
tya
|
||||
pha
|
||||
adc #128
|
||||
tay
|
||||
jsr _DrawTile8x8
|
||||
txa
|
||||
adc #4
|
||||
tax
|
||||
ply
|
||||
jmp _DrawTile8x8
|
||||
|
||||
draw_16x8v
|
||||
tax
|
||||
jsr _DrawTile8x8V
|
||||
clc
|
||||
txa
|
||||
adc #4
|
||||
tax
|
||||
tya
|
||||
adc #128
|
||||
tay
|
||||
jmp _DrawTile8x8V
|
||||
|
||||
draw_16x8hv
|
||||
clc
|
||||
tax
|
||||
tya
|
||||
pha
|
||||
adc #128
|
||||
tay
|
||||
jsr _DrawTile8x8V
|
||||
txa
|
||||
adc #4
|
||||
tax
|
||||
ply
|
||||
jmp _DrawTile8x8V
|
||||
|
||||
draw_16x16
|
||||
clc
|
||||
tax
|
||||
jsr _DrawTile8x8
|
||||
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
|
||||
tax
|
||||
tya
|
||||
adc #64
|
||||
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
|
||||
|
||||
draw_16x16v
|
||||
clc
|
||||
tax
|
||||
tya
|
||||
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
|
||||
|
||||
draw_16x16hv
|
||||
clc
|
||||
tax
|
||||
tya
|
||||
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
|
||||
|
||||
|
||||
; X = sprite vbuff address
|
||||
; Y = tile data pointer
|
||||
_DrawTile8x8
|
||||
_CopyTile8x8
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda: tiledata+32+{]line*4},y
|
||||
stal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
lda: tiledata+{]line*4},y
|
||||
stal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
|
||||
lda: tiledata+32+{]line*4}+2,y
|
||||
stal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
lda: tiledata+{]line*4}+2,y
|
||||
stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_DrawTile8x8V
|
||||
_CopyTile8x8V
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda: tiledata+32+{{7-]line}*4},y
|
||||
stal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
lda: tiledata+{{7-]line}*4},y
|
||||
stal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
|
||||
lda: tiledata+32+{{7-]line}*4}+2,y
|
||||
stal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
lda: tiledata+{{7-]line}*4}+2,y
|
||||
stal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
|
@ -17,7 +17,7 @@
|
|||
; 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.
|
||||
;
|
||||
; 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.
|
||||
PER_TILE_SIZE equ 3
|
||||
]step equ 0
|
||||
|
@ -238,18 +238,6 @@ TileStoreYTable ENT
|
|||
]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
|
||||
; and the table is double-length. Use constant offsets to pick an amount to advance
|
||||
NextCol
|
||||
|
|
|
@ -137,7 +137,7 @@ SetScreenRect sty ScreenHeight ; Save the screen height and
|
|||
ldx #0
|
||||
ldy #0
|
||||
:tsloop
|
||||
sta TileStore+TS_SCREEN_ADDR,X
|
||||
stal TileStore+TS_SCREEN_ADDR,x
|
||||
|
||||
clc
|
||||
adc #4 ; Go to the next tile
|
||||
|
@ -205,7 +205,7 @@ Counter equ tmp3
|
|||
tax ; NOTE: Try to rework to use new TileStore2DLookup array
|
||||
|
||||
lda OnScreenAddr
|
||||
sta TileStore+TS_SCREEN_ADDR,X
|
||||
stal TileStore+TS_SCREEN_ADDR,x
|
||||
|
||||
clc
|
||||
adc #4 ; Go to the next tile
|
||||
|
|
|
@ -75,6 +75,17 @@ _GetTileAddr
|
|||
asl ; x128
|
||||
rts
|
||||
|
||||
; Ignore the horizontal flip bit
|
||||
_GetBaseTileAddr
|
||||
asl ; Multiply by 2
|
||||
asl ; x4
|
||||
asl ; x8
|
||||
asl ; x16
|
||||
asl ; x32
|
||||
asl ; x64
|
||||
asl ; x128
|
||||
rts
|
||||
|
||||
; On entry
|
||||
;
|
||||
; B is set to the correct BG1 data bank
|
||||
|
@ -103,30 +114,40 @@ _RenderTileBG1
|
|||
; Store record contains all of the low-level information that's needed to call the renderer.
|
||||
;
|
||||
; Y = address of tile
|
||||
RenderTile ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _RenderTile2
|
||||
plb
|
||||
rtl
|
||||
|
||||
_RenderTile2
|
||||
pea >TileStore ; Need that addressing flexibility here. Caller is responsible for restoring bank reg
|
||||
plb
|
||||
plb
|
||||
txy ; We can be better than this....
|
||||
|
||||
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
|
||||
beq :nosprite
|
||||
|
||||
txa
|
||||
jsr BuildActiveSpriteArray ; Build the max 4 array of active sprites for this tile
|
||||
; sta ActiveSpriteCount
|
||||
|
||||
lda TileStore+TS_VBUFF_ARRAY_ADDR,y ; Scratch space
|
||||
sta _SPR_X_REG
|
||||
phy
|
||||
ldy spriteIdx
|
||||
lda (_SPR_X_REG),y
|
||||
sta _SPR_X_REG
|
||||
ply
|
||||
|
||||
lda TileStore+TS_TILE_ID,y
|
||||
ora #TILE_SPRITE_BIT
|
||||
ldx TileStore+TS_SPRITE_ADDR,y
|
||||
stx _SPR_X_REG
|
||||
; ldx TileStore+TS_VBUFF_ARRAY_ADDR,y
|
||||
; stx _SPR_X_REG
|
||||
|
||||
:nosprite
|
||||
sta _TILE_ID ; Some tile blitters need to get the tile descriptor
|
||||
and #TILE_CTRL_MASK
|
||||
xba
|
||||
tax
|
||||
lda TileProcs,x ; load and patch in the appropriate subroutine
|
||||
sta :tiledisp+1
|
||||
ldal TileProcs,x ; load and patch in the appropriate subroutine
|
||||
stal :tiledisp+1
|
||||
|
||||
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
||||
|
||||
|
@ -498,17 +519,34 @@ _CopyBG1Tile
|
|||
;
|
||||
; TileStore+TS_TILE_ID : Tile descriptor
|
||||
; TileStore+TS_DIRTY : $FFFF is clean, otherwise stores a back-reference to the DirtyTiles array
|
||||
; TileStore+TS_SPRITE_FLAG : Set to TILE_SPRITE_BIT if a sprite is present at this tile location
|
||||
; TileStore+TS_SPRITE_ADDR ; Address of the tile in the sprite plane
|
||||
; TileStore+TS_TILE_ADDR : Address of the tile in the tile data buffer
|
||||
; TileStore+TS_CODE_ADDR_LOW : Low word of the address in the code field that receives the tile
|
||||
; TileStore+TS_CODE_ADDR_HIGH : High word of the address in the code field that receives the tile
|
||||
; TileStore+TS_WORD_OFFSET : Logical number of word for this location
|
||||
; TileStore+TS_BASE_ADDR : Copy of BTableAddrLow
|
||||
; TileStore+TS_SCREEN_ADDR : Address ont he physical screen corresponding to this tile (for direct rendering)
|
||||
; TileStore+TS_SCREEN_ADDR : Address on the physical screen corresponding to this tile (for direct rendering)
|
||||
; TileStore+TS_SPRITE_FLAG : A bit field of all sprites that intersect this tile
|
||||
; TileStore+TS_SPRITE_ADDR_1 ; Address of the sprite data that aligns with this tile. These
|
||||
; TileStore+TS_SPRITE_ADDR_2 ; values are 1:1 with the TS_SPRITE_FLAG bits and are not contiguous.
|
||||
; TileStore+TS_SPRITE_ADDR_3 ; If the bit position in TS_SPRITE_FLAG is not set, then the value in
|
||||
; TileStore+TS_SPRITE_ADDR_4 ; the TS_SPRITE_ADDR_* field is undefined.
|
||||
; TileStore+TS_SPRITE_ADDR_5
|
||||
; TileStore+TS_SPRITE_ADDR_6
|
||||
; TileStore+TS_SPRITE_ADDR_7
|
||||
; TileStore+TS_SPRITE_ADDR_8
|
||||
; TileStore+TS_SPRITE_ADDR_9
|
||||
; TileStore+TS_SPRITE_ADDR_10
|
||||
; TileStore+TS_SPRITE_ADDR_11
|
||||
; TileStore+TS_SPRITE_ADDR_12
|
||||
; TileStore+TS_SPRITE_ADDR_13
|
||||
; TileStore+TS_SPRITE_ADDR_14
|
||||
; TileStore+TS_SPRITE_ADDR_15
|
||||
; TileStore+TS_SPRITE_ADDR_16
|
||||
|
||||
TileStore ENT
|
||||
ds TILE_STORE_SIZE*11
|
||||
|
||||
; TileStore+
|
||||
;TileStore ENT
|
||||
; ds TILE_STORE_SIZE*11
|
||||
|
||||
; A list of dirty tiles that need to be updated in a given frame
|
||||
DirtyTileCount ds 2
|
||||
|
@ -519,6 +557,7 @@ DirtyTiles ds TILE_STORE_SIZE ; At most this many tiles can possibly
|
|||
InitTiles
|
||||
:col equ tmp0
|
||||
:row equ tmp1
|
||||
:vbuff equ tmp2
|
||||
|
||||
; 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
|
||||
|
@ -533,36 +572,6 @@ InitTiles
|
|||
cpy #26*2
|
||||
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
|
||||
|
||||
ldx #TILE_STORE_SIZE-2
|
||||
|
@ -570,18 +579,27 @@ InitTiles
|
|||
sta :row
|
||||
lda #40
|
||||
sta :col
|
||||
lda #$8000
|
||||
sta :vbuff
|
||||
|
||||
:loop
|
||||
|
||||
; The first set of values in the Tile Store are changed during each frame based on the actions
|
||||
; that are happening
|
||||
|
||||
stz TileStore+TS_TILE_ID,x ; clear the tile store with the special zero tile
|
||||
stz TileStore+TS_TILE_ADDR,x
|
||||
lda #0
|
||||
stal TileStore+TS_TILE_ID,x ; clear the tile store with the special zero tile
|
||||
stal TileStore+TS_TILE_ADDR,x
|
||||
|
||||
stz TileStore+TS_SPRITE_FLAG,x ; no sprites are set at the beginning
|
||||
stal TileStore+TS_SPRITE_FLAG,x ; no sprites are set at the beginning
|
||||
lda #$FFFF ; none of the tiles are dirty
|
||||
sta TileStore+TS_DIRTY,x
|
||||
stal TileStore+TS_DIRTY,x
|
||||
|
||||
lda :vbuff ; array of sprite vbuff addresses per tile
|
||||
stal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
clc
|
||||
adc #32
|
||||
sta :vbuff
|
||||
|
||||
; The next set of values are constants that are simply used as cached parameters to avoid needing to
|
||||
; calculate any of these values during tile rendering
|
||||
|
@ -590,20 +608,20 @@ InitTiles
|
|||
asl ; exists in the code fields
|
||||
tay
|
||||
lda BRowTableHigh,y
|
||||
sta TileStore+TS_CODE_ADDR_HIGH,x ; High word of the tile address (just the bank)
|
||||
stal TileStore+TS_CODE_ADDR_HIGH,x ; High word of the tile address (just the bank)
|
||||
lda BRowTableLow,y
|
||||
sta TileStore+TS_BASE_ADDR,x ; May not be needed later if we can figure out the right constant...
|
||||
stal TileStore+TS_BASE_ADDR,x ; May not be needed later if we can figure out the right constant...
|
||||
|
||||
lda :col ; Set the offset values based on the column
|
||||
asl ; of this tile
|
||||
asl
|
||||
sta TileStore+TS_WORD_OFFSET,x ; This is the offset from 0 to 82, used in LDA (dp),y instruction
|
||||
stal TileStore+TS_WORD_OFFSET,x ; This is the offset from 0 to 82, used in LDA (dp),y instruction
|
||||
|
||||
tay
|
||||
lda Col2CodeOffset+2,y
|
||||
clc
|
||||
adc TileStore+TS_BASE_ADDR,x
|
||||
sta TileStore+TS_CODE_ADDR_LOW,x ; Low word of the tile address in the code field
|
||||
adcl TileStore+TS_BASE_ADDR,x
|
||||
stal TileStore+TS_CODE_ADDR_LOW,x ; Low word of the tile address in the code field
|
||||
|
||||
dec :col
|
||||
bpl :hop
|
||||
|
@ -663,22 +681,24 @@ _GetTileStoreOffset0
|
|||
; A = tile id
|
||||
; X = tile column [0, 40] (41 columns)
|
||||
; Y = tile row [0, 25] (26 rows)
|
||||
;
|
||||
; Registers are not preserved
|
||||
_SetTile
|
||||
pha
|
||||
jsr _GetTileStoreOffset0 ; Get the address of the X,Y tile position
|
||||
tay
|
||||
tax
|
||||
pla
|
||||
|
||||
cmp TileStore+TS_TILE_ID,y ; Only set to dirty if the value changed
|
||||
cmpl TileStore+TS_TILE_ID,x ; Only set to dirty if the value changed
|
||||
beq :nochange
|
||||
|
||||
sta TileStore+TS_TILE_ID,y ; Value is different, store it.
|
||||
stal TileStore+TS_TILE_ID,x ; Value is different, store it.
|
||||
|
||||
jsr _GetTileAddr
|
||||
sta TileStore+TS_TILE_ADDR,y ; Committed to drawing this tile, so get the address of the tile in the tiledata bank for later
|
||||
stal TileStore+TS_TILE_ADDR,x ; Committed to drawing this tile, so get the address of the tile in the tiledata bank for later
|
||||
|
||||
tya ; Add this tile to the list of dirty tiles to refresh
|
||||
jmp _PushDirtyTile ; on the next call to _ApplyTiles
|
||||
; txa ; Add this tile to the list of dirty tiles to refresh
|
||||
jmp _PushDirtyTileX ; on the next call to _ApplyTiles
|
||||
|
||||
:nochange rts
|
||||
|
||||
|
@ -705,27 +725,17 @@ _PushDirtyTile
|
|||
|
||||
; alternate entry point if the x-register is already set
|
||||
_PushDirtyTileX
|
||||
lda TileStore+TS_DIRTY,x
|
||||
ldal TileStore+TS_DIRTY,x
|
||||
bpl :occupied2
|
||||
|
||||
txa ; any non-negative value will work, this saves work below
|
||||
sta 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
|
||||
sta DirtyTiles,x ; 5
|
||||
|
||||
inx
|
||||
inx
|
||||
stx DirtyTileCount
|
||||
|
||||
; Same speed, but preserved the Z register
|
||||
; sta (DirtyTiles) ; 6
|
||||
; lda DirtyTiles ; 4
|
||||
; inc ; 2
|
||||
; inc ; 2
|
||||
; sta DirtyTiles ; 4
|
||||
|
||||
rts
|
||||
:occupied2
|
||||
txa ; Make sure TileStore offset is returned in the accumulator
|
||||
|
@ -745,18 +755,18 @@ PopDirtyTile ENT
|
|||
rtl
|
||||
|
||||
_PopDirtyTile
|
||||
ldx DirtyTileCount
|
||||
ldy DirtyTileCount
|
||||
bne _PopDirtyTile2
|
||||
rts
|
||||
|
||||
_PopDirtyTile2 ; alternate entry point
|
||||
dex
|
||||
dex
|
||||
stx DirtyTileCount ; remove last item from the list
|
||||
dey
|
||||
dey
|
||||
sty DirtyTileCount ; remove last item from the list
|
||||
|
||||
ldy DirtyTiles,x ; load the offset into the Tile Store
|
||||
ldx DirtyTiles,y ; load the offset into the Tile Store
|
||||
lda #$FFFF
|
||||
sta TileStore+TS_DIRTY,y ; clear the occupied backlink
|
||||
stal TileStore+TS_DIRTY,x ; clear the occupied backlink
|
||||
rts
|
||||
|
||||
; Run through the dirty tile list and render them into the code field
|
||||
|
@ -772,11 +782,11 @@ _ApplyTiles
|
|||
bra :begin
|
||||
|
||||
:loop
|
||||
; Retrieve the offset of the next dirty Tile Store items in the Y-register
|
||||
; Retrieve the offset of the next dirty Tile Store items in the X-register
|
||||
|
||||
jsr _PopDirtyTile2
|
||||
|
||||
; Call the generic dispatch with the Tile Store record pointer at by the Y-register.
|
||||
; Call the generic dispatch with the Tile Store record pointer at by the X-register.
|
||||
|
||||
phb
|
||||
jsr _RenderTile2
|
||||
|
@ -784,6 +794,6 @@ _ApplyTiles
|
|||
|
||||
; Loop again until the list of dirty tiles is empty
|
||||
|
||||
:begin ldx DirtyTileCount
|
||||
:begin ldy DirtyTileCount
|
||||
bne :loop
|
||||
rts
|
Loading…
Reference in New Issue
Block a user