Merge branch 'master' into toolbox-docs
This commit is contained in:
commit
7a2cba6bea
|
@ -1,4 +1,7 @@
|
|||
node_modules
|
||||
emu
|
||||
.vscode
|
||||
*_Output.txt
|
||||
src/GTETestApp
|
||||
src/GTETestApp
|
||||
*.2mg
|
||||
Tool160.SHK
|
|
@ -210,4 +210,5 @@ GTE provides the following capabilities
|
|||
* [Adaptive Tile Refresh](https://en.wikipedia.org/wiki/Adaptive_tile_refresh)
|
||||
* [A Guide to the Graphics of the Sega Mega Drive / Genesis](https://rasterscroll.com/mdgraphics/)
|
||||
* [Jon Burton / Traveller's Tales / Coding Secrets](https://ttjontt.wixsite.com/gamehut/coding-secrets)
|
||||
* [Lou's Pseudo 3d Page](http://www.extentofthejam.com/pseudo/)
|
||||
* [Lou's Pseudo 3d Page](http://www.extentofthejam.com/pseudo/)
|
||||
* [A Great Old-Timey Game-Programming Hack](https://blog.moertel.com/posts/2013-12-14-great-old-timey-game-programming-hack.html)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
GTETool.SHK=Type(E0),AuxType(8002),VersionCreate(00),MinVersion(87),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
Tool160.SHK=Type(E0),AuxType(8002),VersionCreate(00),MinVersion(B8),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
|
@ -0,0 +1,18 @@
|
|||
echo off
|
||||
|
||||
REM Copy all of the assets into the ProDOS image for emulator testing
|
||||
REM
|
||||
REM Pass the path of the Cadius tool as the first argument (%1)
|
||||
|
||||
set CADIUS="%1"
|
||||
set IMAGE=".\\emu\\Target.2mg"
|
||||
set FOLDER="/GTEDEV/Toolbox"
|
||||
|
||||
REM Cadius does not overwrite files, so clear the root folder first
|
||||
%CADIUS% DELETEFOLDER %IMAGE% %FOLDER%
|
||||
%CADIUS% CREATEFOLDER %IMAGE% %FOLDER%
|
||||
|
||||
REM Now copy files and folders as needed
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% .\src\GTETool
|
||||
|
||||
REM Copy in the image assets
|
|
@ -3,10 +3,24 @@
|
|||
"height": 4300,
|
||||
"width": 2
|
||||
},
|
||||
"activeFile": "",
|
||||
"activeFile": "world-map.tmx",
|
||||
"expandedProjectPaths": [
|
||||
"."
|
||||
],
|
||||
"file.lastUsedOpenFilter": "All Files (*)",
|
||||
"fileStates": {
|
||||
"world-map.tmx": {
|
||||
"scale": 4,
|
||||
"selectedLayer": 1,
|
||||
"viewCenter": {
|
||||
"x": 143.375,
|
||||
"y": 120.75
|
||||
}
|
||||
},
|
||||
"world-tiles.tsx": {
|
||||
"scaleInDock": 4,
|
||||
"scaleInEditor": 1
|
||||
}
|
||||
},
|
||||
"last.imagePath": "C:/checkout/iigs-game-engine/demos/fatdog-rpg/assets",
|
||||
"map.height": 128,
|
||||
|
@ -15,9 +29,13 @@
|
|||
"map.tileWidth": 8,
|
||||
"map.width": 128,
|
||||
"openFiles": [
|
||||
"world-map.tmx",
|
||||
"world-tiles.tsx"
|
||||
],
|
||||
"project": "fatdog-rpg.tiled-project",
|
||||
"recentFiles": [
|
||||
"world-tiles.tsx",
|
||||
"world-map.tmx"
|
||||
],
|
||||
"tileset.lastUsedFormat": "tsx",
|
||||
"tileset.tileSize": {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="128" height="128" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="1">
|
||||
<tileset firstgid="1" source="world-tiles.tsx"/>
|
||||
<layer id="1" name="Base Layer" width="128" height="128" locked="1">
|
||||
<layer id="1" name="Base Layer" width="128" height="128" visible="0" locked="1">
|
||||
<data encoding="csv">
|
||||
1,1,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
GTEShooter
|
|
@ -0,0 +1 @@
|
|||
GTEPacMan=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
|
@ -0,0 +1 @@
|
|||
GTETestApp
|
|
@ -9,11 +9,14 @@
|
|||
use Tool222.Macs.s
|
||||
use Util.Macs.s
|
||||
use CORE.MACS.s
|
||||
use ../../src/GTE.s
|
||||
use GTE.Macs
|
||||
|
||||
use ../../src/Defs.s
|
||||
|
||||
mx %00
|
||||
|
||||
TSet EXT
|
||||
|
||||
; Feature flags
|
||||
NO_INTERRUPTS equ 0 ; turn off for crossrunner debugging
|
||||
NO_MUSIC equ 1 ; turn music + tool loading off
|
||||
|
@ -22,40 +25,39 @@ NO_MUSIC equ 1 ; turn music + tool loadi
|
|||
phk
|
||||
plb
|
||||
|
||||
jsl EngineStartUp
|
||||
sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #^MyPalette
|
||||
ldx #MyPalette
|
||||
ldy #0
|
||||
jsl SetPalette
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
ldx #0
|
||||
jsl SetScreenMode
|
||||
; Load a tileset
|
||||
|
||||
pea #^TSet
|
||||
pea #TSet
|
||||
_GTELoadTileSet
|
||||
|
||||
|
||||
pea $0000
|
||||
pea #^MyPalette
|
||||
pea #MyPalette
|
||||
_GTESetPalette
|
||||
|
||||
pea $0000
|
||||
_GTESetScreenMode
|
||||
|
||||
; Set up our level data
|
||||
jsr BG0SetUp
|
||||
jsr BG1SetUp
|
||||
jsr TileAnimInit
|
||||
jsr BG0SetUp
|
||||
jsr BG1SetUp
|
||||
jsr TileAnimInit
|
||||
|
||||
; Allocate room to load data
|
||||
|
||||
jsl AllocBank ; Alloc 64KB for Load/Unpack
|
||||
sta BankLoad ; Store "Bank Pointer"
|
||||
jsl AllocBank ; Alloc 64KB for Load/Unpack
|
||||
sta BankLoad ; Store "Bank Pointer"
|
||||
|
||||
jsr MovePlayerToOrigin ; Put the player at the beginning of the map
|
||||
|
||||
jsr InitOverlay ; Initialize the status bar
|
||||
jsr MovePlayerToOrigin ; Put the player at the beginning of the map
|
||||
jsr InitOverlay ; Initialize the status bar
|
||||
|
||||
lda #DIRTY_BIT_BG0_REFRESH ; Redraw all of the tiles on the next Render
|
||||
ora #DIRTY_BIT_BG1_REFRESH
|
||||
tsb DirtyBits
|
||||
|
||||
stz frameCount
|
||||
ldal OneSecondCounter
|
||||
sta oldOneSecondCounter
|
||||
|
||||
lda #$FFFF
|
||||
jsl Render
|
||||
EvtLoop
|
||||
jsl DoTimers
|
||||
jsl Render
|
||||
|
@ -439,6 +441,59 @@ closeRec dw 1 ; pCount
|
|||
qtRec adrl $0000
|
||||
da $00
|
||||
|
||||
|
||||
; Load the GTE User Tool and install it
|
||||
GTEStartUp
|
||||
pea $0000
|
||||
_LoaderStatus
|
||||
pla
|
||||
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000 ; result space
|
||||
|
||||
lda MyUserId
|
||||
pha
|
||||
|
||||
pea #^ToolPath
|
||||
pea #ToolPath
|
||||
pea $0001 ; do not load into special memory
|
||||
_InitialLoad
|
||||
bcc :ok1
|
||||
brk $01
|
||||
|
||||
:ok1
|
||||
ply
|
||||
pla ; Address of the loaded tool
|
||||
plx
|
||||
ply
|
||||
ply
|
||||
|
||||
pea $8000 ; User toolset
|
||||
pea $00A0 ; Set the tool set number
|
||||
phx
|
||||
pha ; Address of function pointer table
|
||||
_SetTSPtr
|
||||
bcc :ok2
|
||||
brk $02
|
||||
|
||||
:ok2
|
||||
clc ; Give GTE a page of direct page memory
|
||||
tdc
|
||||
adc #$0100
|
||||
pha
|
||||
pea #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER ; Enable Dynamic Tiles and Two Layer
|
||||
lda MyUserId ; Pass the userId for memory allocation
|
||||
pha
|
||||
_GTEStartUp
|
||||
bcc :ok3
|
||||
brk $03
|
||||
|
||||
:ok3
|
||||
rts
|
||||
|
||||
PUT App.Msg.s
|
||||
PUT Actions.s
|
||||
PUT font.s
|
||||
|
|
|
@ -7,30 +7,9 @@
|
|||
; Segment #1 -- Main execution block
|
||||
|
||||
ASM App.Main.s
|
||||
DS 0 ; Number of bytes of 0's to add at the end of the Segment
|
||||
KND #$1100 ; Type and Attributes ($11=Static+Bank Relative,$00=Code)
|
||||
ALI None ; Boundary Alignment (None)
|
||||
SNA Main
|
||||
|
||||
; Segment #2 -- Core GTE Code
|
||||
|
||||
ASM ..\..\src\Core.s
|
||||
SNA Core
|
||||
|
||||
; Segment #3 -- 64KB Tile Memory
|
||||
; Segment #2 -- Tileset
|
||||
|
||||
ASM gen\App.TileSet.s
|
||||
DS 0
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
; ALI BANK
|
||||
SNA Tiles
|
||||
|
||||
; Segment #4 -- Rotation table data
|
||||
|
||||
ASM ..\..\src\RotData.s
|
||||
DS 0
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA RotData
|
||||
|
||||
|
||||
SNA TSET
|
|
@ -10,7 +10,27 @@
|
|||
; There are two subroutines that need to be implemented -- one to update the overlay content and a
|
||||
; second to actually render to the screen
|
||||
|
||||
; Initialize the overlay be drawin gin static content that will not change over time
|
||||
STATE_REG equ $E0C068
|
||||
|
||||
_R0W0 mac ; Read Bank 0 / Write Bank 0
|
||||
ldal STATE_REG
|
||||
and #$FFCF
|
||||
stal STATE_REG
|
||||
<<<
|
||||
|
||||
_R0W1 mac ; Read Bank 0 / Write Bank 1
|
||||
ldal STATE_REG
|
||||
ora #$0010
|
||||
stal STATE_REG
|
||||
<<<
|
||||
|
||||
_R1W1 mac ; Read Bank 0 / Write Bank 1
|
||||
ldal STATE_REG
|
||||
ora #$0030
|
||||
stal STATE_REG
|
||||
<<<
|
||||
|
||||
; Initialize the overlay be drawing in static content that will not change over time
|
||||
|
||||
CHAR_TILE_BASE equ 193 ; set this to the real tile id that starts an ASCII run starting at '0' through 'Z'
|
||||
|
||||
|
@ -32,35 +52,57 @@ l_mask equ ovrly_mask
|
|||
|
||||
MASK_OFFSET equ {ovrly_mask-ovrly_buff}
|
||||
|
||||
TileDataPtr equ $FC
|
||||
TileMaskPtr equ $F8
|
||||
|
||||
InitOverlay
|
||||
|
||||
pha
|
||||
pha
|
||||
_GTEGetTileDataAddr
|
||||
pla
|
||||
sta TileDataPtr
|
||||
clc
|
||||
adc #32
|
||||
sta TileMaskPtr
|
||||
pla
|
||||
sta TileDataPtr+2
|
||||
sta TileMaskPtr+2
|
||||
|
||||
lda #'F'
|
||||
ldy #l_line+{CHAR_WIDTH*0}
|
||||
ldx #l_line+{CHAR_WIDTH*0}
|
||||
jsr _DrawChar
|
||||
lda #'P'
|
||||
ldy #l_line+{CHAR_WIDTH*1}
|
||||
ldx #l_line+{CHAR_WIDTH*1}
|
||||
jsr _DrawChar
|
||||
lda #'S'
|
||||
ldy #l_line+{CHAR_WIDTH*2}
|
||||
ldx #l_line+{CHAR_WIDTH*2}
|
||||
jsr _DrawChar
|
||||
lda #':'
|
||||
ldy #l_line+{CHAR_WIDTH*3}
|
||||
ldx #l_line+{CHAR_WIDTH*3}
|
||||
jsr _DrawChar
|
||||
|
||||
lda #'T'
|
||||
ldy #r_line+{CHAR_WIDTH*0}
|
||||
ldx #r_line+{CHAR_WIDTH*0}
|
||||
jsr _DrawChar
|
||||
lda #'I'
|
||||
ldy #r_line+{CHAR_WIDTH*1}
|
||||
ldx #r_line+{CHAR_WIDTH*1}
|
||||
jsr _DrawChar
|
||||
lda #'C'
|
||||
ldy #r_line+{CHAR_WIDTH*2}
|
||||
ldx #r_line+{CHAR_WIDTH*2}
|
||||
jsr _DrawChar
|
||||
lda #'K'
|
||||
ldy #r_line+{CHAR_WIDTH*3}
|
||||
ldx #r_line+{CHAR_WIDTH*3}
|
||||
jsr _DrawChar
|
||||
lda #':'
|
||||
ldy #r_line+{CHAR_WIDTH*4}
|
||||
ldx #r_line+{CHAR_WIDTH*4}
|
||||
jsr _DrawChar
|
||||
|
||||
pea $0000
|
||||
pea $0008
|
||||
pea #^StatusBar
|
||||
pea #StatusBar
|
||||
_GTESetOverlay
|
||||
rts
|
||||
|
||||
; Update the dynamic content of the overlay
|
||||
|
@ -79,8 +121,8 @@ UdtOverlay
|
|||
lda frameCount ; render the FPS value
|
||||
xba
|
||||
jsr _num2ascii
|
||||
ldy #l_line+{CHAR_WIDTH*4}
|
||||
jsr _DrawChar
|
||||
ldx #l_line+{CHAR_WIDTH*4}
|
||||
jsr _DrawChar
|
||||
|
||||
lda frameCount
|
||||
lsr
|
||||
|
@ -88,44 +130,52 @@ UdtOverlay
|
|||
lsr
|
||||
lsr
|
||||
jsr _num2ascii
|
||||
ldy #l_line+{CHAR_WIDTH*5}
|
||||
ldx #l_line+{CHAR_WIDTH*5}
|
||||
jsr _DrawChar
|
||||
|
||||
lda frameCount
|
||||
jsr _num2ascii
|
||||
ldy #l_line+{CHAR_WIDTH*6}
|
||||
ldx #l_line+{CHAR_WIDTH*6}
|
||||
jsr _DrawChar
|
||||
|
||||
ldal OneSecondCounter ; reder the number of remaining seconds
|
||||
pha
|
||||
_GTEGetSeconds
|
||||
pla
|
||||
sta oneSecondCounter ; render the number of remaining seconds
|
||||
xba
|
||||
jsr _num2ascii
|
||||
ldy #r_line+{CHAR_WIDTH*5}
|
||||
ldx #r_line+{CHAR_WIDTH*5}
|
||||
jsr _DrawChar
|
||||
|
||||
ldal OneSecondCounter
|
||||
lda oneSecondCounter
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
jsr _num2ascii
|
||||
ldy #r_line+{CHAR_WIDTH*6}
|
||||
ldx #r_line+{CHAR_WIDTH*6}
|
||||
jsr _DrawChar
|
||||
|
||||
ldal OneSecondCounter
|
||||
lda oneSecondCounter
|
||||
jsr _num2ascii
|
||||
ldy #r_line+{CHAR_WIDTH*7}
|
||||
jsr _DrawChar
|
||||
ldx #r_line+{CHAR_WIDTH*7}
|
||||
jsr _DrawChar
|
||||
|
||||
rts
|
||||
|
||||
oneSecondCounter ds 2
|
||||
|
||||
; Draw the overlay
|
||||
; A = address of the left edge of the screen
|
||||
Overlay ENT
|
||||
phb ; Called via JSL
|
||||
StatusBar phb ; Called via JSL
|
||||
phd ; save the direct page register
|
||||
|
||||
phk
|
||||
plb
|
||||
|
||||
phd ; save the direct page register
|
||||
ldx MyDirectPage ; Preserve the accumulator
|
||||
phx
|
||||
pld
|
||||
|
||||
sta l_addr ; save this value (will go into D-reg later)
|
||||
clc
|
||||
|
@ -144,12 +194,12 @@ Overlay ENT
|
|||
sec
|
||||
sbc m_addr ; calculate the number of words between the two ends
|
||||
and #$FFFE
|
||||
pha
|
||||
lda #m_end
|
||||
sec
|
||||
sbc 1,s
|
||||
|
||||
eor #$FFFF
|
||||
inc
|
||||
clc
|
||||
adc #m_end
|
||||
sta m_patch+1
|
||||
pla
|
||||
|
||||
sei
|
||||
_R1W1
|
||||
|
@ -192,7 +242,7 @@ l_ovrly_rtn
|
|||
_R0W0
|
||||
cli
|
||||
|
||||
:exit
|
||||
o_exit
|
||||
pld ; restore the direct page and bank and return
|
||||
plb
|
||||
rtl
|
||||
|
@ -201,7 +251,6 @@ l_addr ds 2
|
|||
m_addr ds 2
|
||||
r_addr ds 2
|
||||
|
||||
|
||||
r_ovrly
|
||||
]idx equ 0
|
||||
lup R_CHAR_COUNT
|
||||
|
@ -247,10 +296,7 @@ m_end
|
|||
;
|
||||
; A = Tile ID
|
||||
; Y = overlay address location
|
||||
tiledata EXT
|
||||
|
||||
_DCOut rts
|
||||
|
||||
_DrawChar
|
||||
cmp #'0'
|
||||
bcc _DCOut
|
||||
|
@ -261,19 +307,122 @@ _DrawChar
|
|||
sbc #'0'
|
||||
clc
|
||||
adc #CHAR_TILE_BASE
|
||||
jsl GetTileAddr
|
||||
tax
|
||||
jsr _GetTileAddr
|
||||
tay
|
||||
|
||||
]idx equ 0
|
||||
lup 8
|
||||
ldal tiledata+32+{]idx*4},x
|
||||
sta: {]idx*OVRLY_SPAN}+MASK_OFFSET,y
|
||||
ldal tiledata+{]idx*4},x
|
||||
sta: {]idx*OVRLY_SPAN},y
|
||||
ldal tiledata+32+{]idx*4}+2,x
|
||||
sta: {]idx*OVRLY_SPAN}+MASK_OFFSET+2,y
|
||||
ldal tiledata+{]idx*4}+2,x
|
||||
sta: {]idx*OVRLY_SPAN}+2,y
|
||||
]idx equ ]idx+1
|
||||
--^
|
||||
lda [TileMaskPtr],y
|
||||
sta: {0*OVRLY_SPAN}+MASK_OFFSET,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {0*OVRLY_SPAN},x
|
||||
iny
|
||||
iny
|
||||
lda [TileMaskPtr],y
|
||||
sta: {0*OVRLY_SPAN}+MASK_OFFSET+2,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {0*OVRLY_SPAN}+2,x
|
||||
iny
|
||||
iny
|
||||
|
||||
lda [TileMaskPtr],y
|
||||
sta: {1*OVRLY_SPAN}+MASK_OFFSET,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {1*OVRLY_SPAN},x
|
||||
iny
|
||||
iny
|
||||
lda [TileMaskPtr],y
|
||||
sta: {1*OVRLY_SPAN}+MASK_OFFSET+2,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {1*OVRLY_SPAN}+2,x
|
||||
iny
|
||||
iny
|
||||
|
||||
lda [TileMaskPtr],y
|
||||
sta: {2*OVRLY_SPAN}+MASK_OFFSET,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {2*OVRLY_SPAN},x
|
||||
iny
|
||||
iny
|
||||
lda [TileMaskPtr],y
|
||||
sta: {2*OVRLY_SPAN}+MASK_OFFSET+2,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {2*OVRLY_SPAN}+2,x
|
||||
iny
|
||||
iny
|
||||
|
||||
lda [TileMaskPtr],y
|
||||
sta: {3*OVRLY_SPAN}+MASK_OFFSET,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {3*OVRLY_SPAN},x
|
||||
iny
|
||||
iny
|
||||
lda [TileMaskPtr],y
|
||||
sta: {3*OVRLY_SPAN}+MASK_OFFSET+2,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {3*OVRLY_SPAN}+2,x
|
||||
iny
|
||||
iny
|
||||
|
||||
lda [TileMaskPtr],y
|
||||
sta: {4*OVRLY_SPAN}+MASK_OFFSET,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {4*OVRLY_SPAN},x
|
||||
iny
|
||||
iny
|
||||
lda [TileMaskPtr],y
|
||||
sta: {4*OVRLY_SPAN}+MASK_OFFSET+2,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {4*OVRLY_SPAN}+2,x
|
||||
iny
|
||||
iny
|
||||
|
||||
lda [TileMaskPtr],y
|
||||
sta: {5*OVRLY_SPAN}+MASK_OFFSET,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {5*OVRLY_SPAN},x
|
||||
iny
|
||||
iny
|
||||
lda [TileMaskPtr],y
|
||||
sta: {5*OVRLY_SPAN}+MASK_OFFSET+2,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {5*OVRLY_SPAN}+2,x
|
||||
iny
|
||||
iny
|
||||
|
||||
lda [TileMaskPtr],y
|
||||
sta: {6*OVRLY_SPAN}+MASK_OFFSET,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {6*OVRLY_SPAN},x
|
||||
iny
|
||||
iny
|
||||
lda [TileMaskPtr],y
|
||||
sta: {6*OVRLY_SPAN}+MASK_OFFSET+2,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {6*OVRLY_SPAN}+2,x
|
||||
iny
|
||||
iny
|
||||
|
||||
lda [TileMaskPtr],y
|
||||
sta: {7*OVRLY_SPAN}+MASK_OFFSET,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {7*OVRLY_SPAN},x
|
||||
iny
|
||||
iny
|
||||
lda [TileMaskPtr],y
|
||||
sta: {7*OVRLY_SPAN}+MASK_OFFSET+2,x
|
||||
lda [TileDataPtr],y
|
||||
sta: {7*OVRLY_SPAN}+2,x
|
||||
|
||||
rts
|
||||
|
||||
_GetTileAddr
|
||||
asl ; Multiply by 2
|
||||
bit #2*TILE_HFLIP_BIT ; Check if the horizontal flip bit is set
|
||||
beq :no_flip
|
||||
inc ; Set the LSB
|
||||
:no_flip asl ; x4
|
||||
asl ; x8
|
||||
asl ; x16
|
||||
asl ; x32
|
||||
asl ; x64
|
||||
asl ; x128
|
||||
rts
|
|
@ -3,7 +3,7 @@
|
|||
"height": 4300,
|
||||
"width": 2
|
||||
},
|
||||
"activeFile": "tiled/world_1-1.tmx",
|
||||
"activeFile": "C:/checkout/iigs-game-engine/demos/zelda/assets/overworld.tmx",
|
||||
"expandedProjectPaths": [
|
||||
"tiled"
|
||||
],
|
||||
|
@ -26,46 +26,145 @@
|
|||
"scaleInDock": 2,
|
||||
"scaleInEditor": 4
|
||||
},
|
||||
"C:/checkout/iigs-game-engine/demos/sprites/assets/tiled/Overworld.tsx": {
|
||||
"scaleInDock": 2,
|
||||
"scaleInEditor": 4
|
||||
},
|
||||
"C:/checkout/iigs-game-engine/demos/sprites/assets/tiled/world_1-1.tmx": {
|
||||
"scale": 2,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 412,
|
||||
"y": 309
|
||||
}
|
||||
},
|
||||
"C:/checkout/iigs-game-engine/demos/zelda/assets/Zelda.tsx": {
|
||||
"scaleInDock": 4,
|
||||
"scaleInEditor": 1
|
||||
},
|
||||
"C:/checkout/iigs-game-engine/demos/zelda/assets/overworld.tmx": {
|
||||
"scale": 2,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 222.75,
|
||||
"y": 192.5
|
||||
}
|
||||
},
|
||||
"C:/checkout/tiled/examples/desert.tmx": {
|
||||
"scale": 0.5462499999999999,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 716.704805491991,
|
||||
"y": 793.5926773455379
|
||||
}
|
||||
},
|
||||
"C:/checkout/tiled/examples/desert.tsx": {
|
||||
"scaleInDock": 1
|
||||
},
|
||||
"C:/checkout/tiled/examples/hexagonal-mini.tmx": {
|
||||
"scale": 3.0067010309278346,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 159.14452254414542,
|
||||
"y": 116.90553745928342
|
||||
}
|
||||
},
|
||||
"C:/checkout/tiled/examples/hexagonal-mini.tmx#hex mini": {
|
||||
"scaleInDock": 1
|
||||
},
|
||||
"C:/checkout/tiled/examples/isometric_grass_and_water.tmx": {
|
||||
"scale": 0.4643125,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 1039.1708170682462,
|
||||
"y": 573.9668865257775
|
||||
}
|
||||
},
|
||||
"C:/checkout/tiled/examples/isometric_grass_and_water.tmx#isometric_grass_and_water": {
|
||||
"scaleInDock": 1
|
||||
},
|
||||
"C:/checkout/tiled/examples/perspective_walls.tmx": {
|
||||
"scale": 0.8369268292682926,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 497.65401876784983,
|
||||
"y": 479.7313050067028
|
||||
}
|
||||
},
|
||||
"C:/checkout/tiled/examples/perspective_walls.tsx": {
|
||||
"scaleInDock": 1
|
||||
},
|
||||
"C:/checkout/tiled/examples/rpg/beach_tileset.tsx": {
|
||||
"scaleInDock": 1
|
||||
},
|
||||
"C:/checkout/tiled/examples/rpg/island.tmx": {
|
||||
"scale": 1.0267780172413792,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 464.0730440258173,
|
||||
"y": 376.42021304507534
|
||||
}
|
||||
},
|
||||
"C:/checkout/tiled/examples/sewers.tmx": {
|
||||
"scale": 0.7148749999999999,
|
||||
"selectedLayer": 0,
|
||||
"viewCenter": {
|
||||
"x": 600.8043364224515,
|
||||
"y": 600.8043364224516
|
||||
}
|
||||
},
|
||||
"C:/checkout/tiled/examples/sewers.tmx#sewer_tileset": {
|
||||
"scaleInDock": 1
|
||||
},
|
||||
"tiled/Overworld.tsx": {
|
||||
"scaleInDock": 2,
|
||||
"scaleInEditor": 1
|
||||
"scaleInEditor": 8
|
||||
},
|
||||
"tiled/world_1-1.tmx": {
|
||||
"scale": 2,
|
||||
"selectedLayer": 1,
|
||||
"viewCenter": {
|
||||
"x": 210.5,
|
||||
"y": 107.75
|
||||
"x": 212.75,
|
||||
"y": 211.25
|
||||
}
|
||||
}
|
||||
},
|
||||
"last.exportedFilePath": "C:/checkout/iigs-game-engine/assets/tiled",
|
||||
"last.imagePath": "C:/checkout/iigs-game-engine/assets/tilesets",
|
||||
"map.height": 30,
|
||||
"frame.defaultDuration": 256,
|
||||
"last.exportedFilePath": "C:/checkout/iigs-game-engine/demos/zelda/assets",
|
||||
"last.imagePath": "C:/checkout/iigs-game-engine/demos/zelda/assets",
|
||||
"map.height": 44,
|
||||
"map.lastUsedExportFilter": "JSON map files (*.json)",
|
||||
"map.lastUsedFormat": "tmx",
|
||||
"map.renderOrder": null,
|
||||
"map.tileHeight": 8,
|
||||
"map.tileWidth": 8,
|
||||
"map.width": 256,
|
||||
"map.width": 64,
|
||||
"openFiles": [
|
||||
"tiled/world_1-1.tmx",
|
||||
"tiled/Overworld.tsx"
|
||||
"C:/checkout/iigs-game-engine/demos/zelda/assets/overworld.tmx",
|
||||
"C:/checkout/iigs-game-engine/demos/zelda/assets/Zelda.tsx"
|
||||
],
|
||||
"project": "assets.tiled-project",
|
||||
"property.type": "int",
|
||||
"property.type": "bool",
|
||||
"recentFiles": [
|
||||
"tiled/Overworld.tsx",
|
||||
"C:/checkout/iigs-game-engine/demos/zelda/assets/Zelda.tsx",
|
||||
"C:/checkout/iigs-game-engine/demos/zelda/assets/overworld.tmx",
|
||||
"C:/checkout/iigs-game-engine/demos/sprites/assets/tiled/Overworld.tsx",
|
||||
"C:/checkout/iigs-game-engine/demos/sprites/assets/tiled/world_1-1.tmx",
|
||||
"tiled/world_1-1.tmx",
|
||||
"C:/Users/lscharen/SNES - Final Fantasy 6 - South Figaro Exterior.tsx",
|
||||
"C:/Users/lscharen/Overworld.tmx",
|
||||
"C:/Users/lscharen/EUm-lfFWkAEb5fJ.tsx"
|
||||
"tiled/Overworld.tsx",
|
||||
"C:/checkout/tiled/examples/desert.tmx",
|
||||
"C:/checkout/tiled/examples/hexagonal-mini.tmx",
|
||||
"C:/checkout/tiled/examples/isometric_grass_and_water.tmx",
|
||||
"C:/checkout/tiled/examples/perspective_walls.tmx",
|
||||
"C:/checkout/tiled/examples/sewers.tmx",
|
||||
"C:/checkout/tiled/examples/rpg/island.tmx"
|
||||
],
|
||||
"resizeMap.removeObjects": true,
|
||||
"tileset.lastUsedFormat": "tsx",
|
||||
"tileset.tileSize": {
|
||||
"height": 8,
|
||||
"width": 8
|
||||
},
|
||||
"tileset.transparentColor": "#6b8cff",
|
||||
"tileset.useTransparentColor": false
|
||||
"tileset.transparentColor": "#ff00ff",
|
||||
"tileset.useTransparentColor": true
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 260 B After Width: | Height: | Size: 248 B |
Binary file not shown.
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 243 B |
|
@ -2,7 +2,7 @@
|
|||
; Palette:
|
||||
; $0000,$0777,$0F31,$0E51,$00A0,$02E3,$0BF1,$0FA4,$0FD7,$0EE6,$0F59,$068F,$01CE,$09B9,$0EDA,$0EEE
|
||||
; Converting to BG0 format...
|
||||
tiledata ENT
|
||||
TSet ENT
|
||||
|
||||
; Reserved space (tile 0 is special...
|
||||
ds 128
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
GTETestApp
|
|
@ -0,0 +1 @@
|
|||
GTETestApp=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "super-mario-bros-nes-demo",
|
||||
"version": "1.0.0",
|
||||
"description": "Wrapping the SMB 6502 ROM in GTE",
|
||||
"main": "index.js",
|
||||
"config": {
|
||||
"merlin32": "C:\\Programs\\IIgsXDev\\bin\\Merlin32-1.1.10.exe",
|
||||
"cadius": "C:\\Programs\\IIgsXDev\\bin\\Cadius.exe",
|
||||
"gsport": "C:\\Programs\\gsport\\gsport_0.31\\GSPort.exe",
|
||||
"macros": "C:\\Programs\\BrutalDeluxe\\Merlin32\\Library",
|
||||
"crossrunner": "C:\\Programs\\Crossrunner\\Crossrunner.exe"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lscharen/iigs-game-engine.git"
|
||||
},
|
||||
"author": "Lucas Scharenbroich",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/lscharen/iigs-game-engine/issues"
|
||||
},
|
||||
"homepage": "https://github.com/lscharen/iigs-game-engine#readme",
|
||||
"devDependencies": {
|
||||
}
|
||||
}
|
|
@ -1,293 +1,353 @@
|
|||
; Test driver to exercise graphics routines.
|
||||
|
||||
REL
|
||||
DSK MAINSEG
|
||||
REL
|
||||
DSK MAINSEG
|
||||
|
||||
use Locator.Macs.s
|
||||
use Misc.Macs.s
|
||||
use EDS.GSOS.MACS.s
|
||||
use Tool222.Macs.s
|
||||
use Util.Macs.s
|
||||
use CORE.MACS.s
|
||||
use ../../src/GTE.s
|
||||
use ../../src/Defs.s
|
||||
use Locator.Macs
|
||||
use Load.Macs
|
||||
use Mem.Macs
|
||||
use Misc.Macs
|
||||
use Tool222.Macs.s
|
||||
use Util.Macs
|
||||
use EDS.GSOS.Macs
|
||||
use GTE.Macs
|
||||
|
||||
mx %00
|
||||
; use ../../src/Defs.s
|
||||
|
||||
; Feature flags
|
||||
NO_INTERRUPTS equ 0 ; turn off for crossrunner debugging
|
||||
NO_MUSIC equ 1 ; turn music + tool loading off
|
||||
mx %00
|
||||
|
||||
TSet EXT ; tileset buffer
|
||||
|
||||
; Keycodes
|
||||
LEFT_ARROW equ $08
|
||||
RIGHT_ARROW equ $15
|
||||
UP_ARROW equ $0B
|
||||
DOWN_ARROW equ $0A
|
||||
LEFT_ARROW equ $08
|
||||
RIGHT_ARROW equ $15
|
||||
UP_ARROW equ $0B
|
||||
DOWN_ARROW equ $0A
|
||||
|
||||
; Typical init
|
||||
phk
|
||||
plb
|
||||
; Direct page space
|
||||
appTmp0 equ 0
|
||||
BankLoad equ 2
|
||||
StartX equ 4
|
||||
StartY equ 6
|
||||
TileMapWidth equ 8
|
||||
TileMapHeight equ 10
|
||||
ScreenWidth equ 12
|
||||
ScreenHeight equ 14
|
||||
|
||||
jsl EngineStartUp
|
||||
phk
|
||||
plb
|
||||
|
||||
lda #^MyPalette ; Fill Palette #0 with our colors
|
||||
ldx #MyPalette
|
||||
ldy #0
|
||||
jsl SetPalette
|
||||
sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program
|
||||
tdc
|
||||
sta MyDirectPage ; Keep a copy for the overlay callback
|
||||
|
||||
ldx #5 ; Mode 0 is full-screen, mode 5 is 256x160
|
||||
ldx #320
|
||||
ldy #200
|
||||
jsl SetScreenMode
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
||||
stz appTmp0
|
||||
stz BankLoad
|
||||
stz StartX
|
||||
stz StartY
|
||||
|
||||
; Initialize the graphics screen to a 256x160 playfield
|
||||
|
||||
pea #320
|
||||
pea #200
|
||||
_GTESetScreenMode
|
||||
|
||||
; Load a tileset
|
||||
|
||||
pea #^TSet
|
||||
pea #TSet
|
||||
_GTELoadTileSet
|
||||
|
||||
pea $0000
|
||||
pea #^MyPalette
|
||||
pea #MyPalette
|
||||
_GTESetPalette
|
||||
|
||||
; Set up our level data
|
||||
jsr BG0SetUp
|
||||
jsr TileAnimInit
|
||||
jsr SetLimits
|
||||
jsr BG0SetUp
|
||||
jsr TileAnimInit
|
||||
jsr SetLimits
|
||||
|
||||
jsr InitOverlay ; Initialize the status bar
|
||||
stz frameCount
|
||||
ldal OneSecondCounter
|
||||
sta oldOneSecondCounter
|
||||
jsr UdtOverlay
|
||||
jsr InitOverlay ; Initialize the status bar
|
||||
stz frameCount
|
||||
pha
|
||||
_GTEGetSeconds
|
||||
pla
|
||||
sta oldOneSecondCounter
|
||||
jsr UdtOverlay
|
||||
|
||||
; Allocate a buffer for loading files
|
||||
jsl AllocBank ; Alloc 64KB for Load/Unpack
|
||||
sta BankLoad ; Store "Bank Pointer"
|
||||
jsl AllocBank ; Alloc 64KB for Load/Unpack
|
||||
sta BankLoad ; Store "Bank Pointer"
|
||||
|
||||
; Load in the 256 color background into BG1 buffer
|
||||
brl :nobackground
|
||||
; brl :nobackground
|
||||
DoLoadBG1
|
||||
lda BankLoad
|
||||
ldx #BG1DataFile
|
||||
jsr LoadFile
|
||||
lda BankLoad
|
||||
ldx #BG1DataFile
|
||||
jsr LoadFile
|
||||
|
||||
ldx BankLoad
|
||||
lda #0
|
||||
ldy BG1DataBank
|
||||
jsl CopyPicToBG1
|
||||
lda BankLoad
|
||||
pha
|
||||
pea $0000
|
||||
_GTECopyPicToBG1
|
||||
|
||||
; Copy the palettes into place
|
||||
|
||||
stz tmp0
|
||||
stz appTmp0
|
||||
:ploop
|
||||
lda tmp0
|
||||
tay
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
clc
|
||||
adc #$7E00
|
||||
tax
|
||||
lda appTmp0
|
||||
pha ; Palette number
|
||||
ldy BankLoad
|
||||
phy ; High word pointer to palette
|
||||
|
||||
lda BankLoad
|
||||
jsl SetPalette
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
clc
|
||||
adc #$7E00
|
||||
pha ; Low word pointer to palette
|
||||
_GTESetPalette
|
||||
|
||||
inc tmp0
|
||||
lda tmp0
|
||||
cmp #16
|
||||
bcc :ploop
|
||||
inc appTmp0
|
||||
lda appTmp0
|
||||
cmp #16
|
||||
bcc :ploop
|
||||
|
||||
; Bind the SCBs
|
||||
|
||||
lda BankLoad
|
||||
ora #$8000 ; set high bit to bind to BG1 Y-position
|
||||
ldx #$7D00
|
||||
jsl SetSCBArray
|
||||
lda BankLoad
|
||||
ora #$8000 ; set high bit to bind to BG1 Y-position
|
||||
pha
|
||||
pea $7D00
|
||||
_GTEBindSCBArray
|
||||
:nobackground
|
||||
|
||||
; Initialize the sprite's global position (this is tracked outside of the tile engine)
|
||||
lda #16
|
||||
sta PlayerGlobalX
|
||||
lda MaxGlobalY
|
||||
sec
|
||||
lda #40 ; 32 for tiles, 8 for sprite
|
||||
sta PlayerGlobalY
|
||||
lda #16
|
||||
sta PlayerGlobalX
|
||||
lda MaxGlobalY
|
||||
sec
|
||||
lda #40 ; 32 for tiles, 8 for sprite
|
||||
sta PlayerGlobalY
|
||||
|
||||
stz PlayerXVel
|
||||
stz PlayerYVel
|
||||
stz PlayerXVel
|
||||
stz PlayerYVel
|
||||
|
||||
; Add a sprite to the engine and save it's sprite ID
|
||||
SPRITE_ID equ {SPRITE_16X16+145}
|
||||
MUSHROOM_ID equ {SPRITE_16X16+255}
|
||||
; Create the sprites
|
||||
HERO_ID equ {SPRITE_16X16+145}
|
||||
HERO_VBUFF equ VBUFF_SPRITE_START+0*VBUFF_SPRITE_STEP
|
||||
HERO_SLOT equ 1
|
||||
MUSHROOM_ID equ {SPRITE_16X16+255}
|
||||
MUSHROOM_VBUFF equ VBUFF_SPRITE_START+1*VBUFF_SPRITE_STEP
|
||||
MUSHROOM_SLOT equ 0
|
||||
|
||||
lda #MUSHROOM_ID ; 16x16 sprite, tile ID = 145
|
||||
ldx #80
|
||||
ldy #152
|
||||
jsl AddSprite
|
||||
pea HERO_ID ; sprint id
|
||||
pea HERO_VBUFF ; vbuff address
|
||||
_GTECreateSpriteStamp
|
||||
|
||||
jsr UpdatePlayerLocal
|
||||
lda #SPRITE_ID ; 16x16 sprite, tile ID = 145
|
||||
ldx PlayerX
|
||||
ldy PlayerY
|
||||
jsl AddSprite
|
||||
bcc :sprite_ok
|
||||
brl Exit ; If we could not allocate a sprite, exit
|
||||
:sprite_ok
|
||||
sta PlayerID
|
||||
pea MUSHROOM_ID ; sprint id
|
||||
pea MUSHROOM_VBUFF ; vbuff address
|
||||
_GTECreateSpriteStamp
|
||||
|
||||
; Draw the initial screen
|
||||
pea MUSHROOM_ID ; Put the mushroom in Slot 0
|
||||
pea #80 ; at x=80, y=152
|
||||
pea #152
|
||||
pea MUSHROOM_SLOT
|
||||
_GTEAddSprite
|
||||
|
||||
lda #DIRTY_BIT_BG0_REFRESH ; Redraw all of the tiles on the next Render
|
||||
tsb DirtyBits
|
||||
jsl Render
|
||||
pea MUSHROOM_SLOT
|
||||
pea $0000 ; with these flags (h/v flip)
|
||||
pea MUSHROOM_VBUFF ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
jsr UpdatePlayerLocal
|
||||
|
||||
pea HERO_ID
|
||||
lda PlayerX
|
||||
pha
|
||||
lda PlayerY
|
||||
pha
|
||||
pea HERO_SLOT ; Put the player in slot 1
|
||||
_GTEAddSprite
|
||||
|
||||
pea HERO_SLOT
|
||||
pea $0000
|
||||
pea HERO_VBUFF ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
; 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.
|
||||
EvtLoop
|
||||
jsl ReadControl
|
||||
pha
|
||||
_GTEReadControl
|
||||
|
||||
; Check the buttons first
|
||||
pha
|
||||
lda 1,s
|
||||
|
||||
bit #$0100
|
||||
beq :no_jump
|
||||
lda PlayerStanding
|
||||
beq :no_jump
|
||||
lda #$FFF8
|
||||
sta PlayerYVel
|
||||
bit #$0100
|
||||
beq :no_jump
|
||||
lda PlayerStanding
|
||||
beq :no_jump
|
||||
lda #$FFF8
|
||||
sta PlayerYVel
|
||||
:no_jump
|
||||
|
||||
|
||||
; Enable/disable v-sync
|
||||
lda 1,s
|
||||
bit #$0400
|
||||
beq :no_key_down
|
||||
and #$007F
|
||||
cmp #'v'
|
||||
bne :not_v
|
||||
lda #$0001
|
||||
eor vsync
|
||||
sta vsync
|
||||
lda 1,s
|
||||
bit #$0400
|
||||
beq :no_key_down
|
||||
and #$007F
|
||||
cmp #'v'
|
||||
bne :not_v
|
||||
lda #$0001
|
||||
eor vsync
|
||||
sta vsync
|
||||
:not_v
|
||||
cmp #'f'
|
||||
bne :not_f
|
||||
lda SpriteToggle
|
||||
eor #SPRITE_HIDE
|
||||
sta SpriteToggle
|
||||
bne :not_f
|
||||
stz SpriteCount
|
||||
cmp #'f'
|
||||
bne :not_f
|
||||
lda SpriteToggle
|
||||
eor #SPRITE_HIDE
|
||||
sta SpriteToggle
|
||||
bne :not_f
|
||||
stz SpriteCount
|
||||
|
||||
:not_f
|
||||
:no_key_down
|
||||
pla
|
||||
and #$007F ; Ignore the buttons for now
|
||||
|
||||
cmp #'q'
|
||||
bne :not_q
|
||||
brl Exit
|
||||
|
||||
pla
|
||||
and #$007F ; Ignore the buttons for now
|
||||
|
||||
cmp #'q'
|
||||
bne :not_q
|
||||
brl Exit
|
||||
:not_q
|
||||
|
||||
cmp #'d'
|
||||
bne :not_d
|
||||
lda StartX
|
||||
cmp MaxBG0X
|
||||
bcs :do_render
|
||||
inc
|
||||
jsl SetBG0XPos
|
||||
bra :do_render
|
||||
cmp #'d'
|
||||
bne :not_d
|
||||
lda StartX
|
||||
cmp MaxBG0X
|
||||
bcc *+5
|
||||
brl :do_render
|
||||
inc StartX
|
||||
pei StartX
|
||||
pei StartY
|
||||
_GTESetBG0Origin
|
||||
brl :do_render
|
||||
:not_d
|
||||
|
||||
cmp #'a'
|
||||
bne :not_a
|
||||
lda StartX
|
||||
beq :do_render
|
||||
dec
|
||||
jsl SetBG0XPos
|
||||
bra :do_render
|
||||
cmp #'a'
|
||||
bne :not_a
|
||||
lda StartX
|
||||
bne *+5
|
||||
brl :do_render
|
||||
dec StartX
|
||||
pei StartX
|
||||
pei StartY
|
||||
_GTESetBG0Origin
|
||||
brl :do_render
|
||||
:not_a
|
||||
|
||||
cmp #'s'
|
||||
bne :not_s
|
||||
lda StartY
|
||||
cmp MaxBG0Y
|
||||
bcs :do_render
|
||||
inc
|
||||
jsl SetBG0YPos
|
||||
bra :do_render
|
||||
cmp #'s'
|
||||
bne :not_s
|
||||
lda StartY
|
||||
cmp MaxBG0Y
|
||||
bcs :do_render
|
||||
inc StartY
|
||||
pei StartX
|
||||
pei StartY
|
||||
_GTESetBG0Origin
|
||||
bra :do_render
|
||||
:not_s
|
||||
|
||||
cmp #'w'
|
||||
bne :not_w
|
||||
lda StartY
|
||||
beq :do_render
|
||||
dec
|
||||
jsl SetBG0YPos
|
||||
bra :do_render
|
||||
cmp #'w'
|
||||
bne :not_w
|
||||
lda StartY
|
||||
beq :do_render
|
||||
dec StartY
|
||||
pei StartX
|
||||
pei StartY
|
||||
_GTESetBG0Origin
|
||||
bra :do_render
|
||||
:not_w
|
||||
|
||||
; Do j,l to move the character left/right
|
||||
cmp #'j'
|
||||
bne :not_j
|
||||
lda PlayerXVel
|
||||
bpl :pos_xvel
|
||||
cmp #$FFFA
|
||||
bcc :not_j
|
||||
:pos_xvel dec
|
||||
dec
|
||||
sta PlayerXVel
|
||||
bra :do_render
|
||||
cmp #'j'
|
||||
bne :not_j
|
||||
lda PlayerXVel
|
||||
bpl :pos_xvel
|
||||
cmp #$FFFA
|
||||
bcc :not_j
|
||||
:pos_xvel dec
|
||||
dec
|
||||
sta PlayerXVel
|
||||
bra :do_render
|
||||
:not_j
|
||||
|
||||
cmp #'l'
|
||||
bne :not_l
|
||||
lda PlayerXVel
|
||||
bmi :neg_xvel
|
||||
cmp #6
|
||||
bcs :not_l
|
||||
:neg_xvel inc
|
||||
inc
|
||||
sta PlayerXVel
|
||||
bra :do_render
|
||||
cmp #'l'
|
||||
bne :not_l
|
||||
lda PlayerXVel
|
||||
bmi :neg_xvel
|
||||
cmp #6
|
||||
bcs :not_l
|
||||
:neg_xvel inc
|
||||
inc
|
||||
sta PlayerXVel
|
||||
bra :do_render
|
||||
:not_l
|
||||
|
||||
|
||||
; Update the camera position
|
||||
|
||||
:do_render
|
||||
jsr UpdatePlayerPos ; Moves in global cordinates
|
||||
jsr UpdateCameraPos ; Moves the screen
|
||||
jsr UpdatePlayerLocal ; Gets local sprite coordinates
|
||||
jsr UpdatePlayerPos ; Moves in global cordinates
|
||||
jsr UpdateCameraPos ; Moves the screen
|
||||
jsr UpdatePlayerLocal ; Gets local sprite coordinates
|
||||
|
||||
lda PlayerID
|
||||
ldx PlayerX
|
||||
ldy PlayerY
|
||||
jsl MoveSprite ; Move the sprite to this local position
|
||||
pea HERO_SLOT
|
||||
lda PlayerX
|
||||
pha
|
||||
lda PlayerY
|
||||
pha
|
||||
_GTEMoveSprite ; Move the sprite to this local position
|
||||
|
||||
; Update the timers
|
||||
jsl DoTimers
|
||||
; jsl DoTimers
|
||||
|
||||
; Let's see what it looks like!
|
||||
|
||||
lda vsync
|
||||
beq :no_vsync
|
||||
:vsyncloop jsl GetVerticalCounter ; 8-bit value
|
||||
cmp ScreenY0
|
||||
bcc :vsyncloop
|
||||
sec
|
||||
sbc ScreenY0
|
||||
cmp #8
|
||||
bcs :vsyncloop
|
||||
lda #1
|
||||
jsl SetBorderColor
|
||||
:no_vsync
|
||||
jsl Render
|
||||
; lda vsync
|
||||
; beq :no_vsync
|
||||
;:vsyncloop jsl GetVerticalCounter ; 8-bit value
|
||||
; cmp ScreenY0
|
||||
; bcc :vsyncloop
|
||||
; sec
|
||||
; sbc ScreenY0
|
||||
; cmp #8
|
||||
; bcs :vsyncloop
|
||||
; lda #1
|
||||
; jsl SetBorderColor
|
||||
;:no_vsync
|
||||
_GTERender
|
||||
|
||||
lda vsync
|
||||
beq :no_vsync2
|
||||
lda #0
|
||||
jsl SetBorderColor
|
||||
:no_vsync2
|
||||
; lda vsync
|
||||
; beq :no_vsync2
|
||||
; lda #0
|
||||
; jsl SetBorderColor
|
||||
;:no_vsync2
|
||||
|
||||
; Update the performance counters
|
||||
|
||||
inc frameCount
|
||||
ldal OneSecondCounter
|
||||
pha
|
||||
_GTEGetSeconds
|
||||
pla
|
||||
cmp oldOneSecondCounter
|
||||
beq :noudt
|
||||
sta oldOneSecondCounter
|
||||
|
@ -298,19 +358,29 @@ EvtLoop
|
|||
|
||||
; Exit code
|
||||
Exit
|
||||
jsl EngineShutDown
|
||||
|
||||
_GTEShutDown
|
||||
_QuitGS qtRec
|
||||
|
||||
bcs Fatal
|
||||
Fatal brk $00
|
||||
|
||||
Hold
|
||||
_GTERender
|
||||
:busy
|
||||
pha
|
||||
_GTEReadControl
|
||||
pla
|
||||
and #$00FF
|
||||
cmp #'q'
|
||||
bne :busy
|
||||
jmp Exit
|
||||
|
||||
BG1DataFile strl '1/sunset.c1'
|
||||
|
||||
; Color palette
|
||||
MyPalette dw $068F,$0EDA,$0000,$0000,$0BF1,$00A0,$0EEE,$0456,$0FA4,$0F59,$0E30,$01CE,$02E3,$0870,$0F93,$0FD7
|
||||
; B&W Palette
|
||||
;MyPalette dw $0000,$0EDA,$0000,$0E51,$0BF1,$00A0,$0EEE,$0456,$0FA4,$0F59,$0E30,$01CE,$02E3,$0870,$0F93,$0FFF
|
||||
; MyPalette dw $0000,$0EDA,$0000,$0E51,$0BF1,$00A0,$0EEE,$0456,$0FA4,$0F59,$0E30,$01CE,$02E3,$0870,$0F93,$0FFF
|
||||
PlayerGlobalX ds 2
|
||||
PlayerGlobalY ds 2
|
||||
|
||||
|
@ -331,6 +401,8 @@ MaxBG0Y ds 2
|
|||
|
||||
oldOneSecondCounter ds 2
|
||||
frameCount ds 2
|
||||
MyUserId ds 2
|
||||
MyDirectPage ds 2
|
||||
|
||||
PLAYER_X_MIN equ 0
|
||||
PLAYER_X_MAX equ 160-4
|
||||
|
@ -339,22 +411,31 @@ PLAYER_Y_MAX equ 200-8
|
|||
|
||||
EMPTY_TILE equ 33 ; the tile that makes up the background
|
||||
|
||||
AdjustLocalX
|
||||
clc
|
||||
adc StartXMod164
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
rts
|
||||
AdjustLocalY
|
||||
clc
|
||||
adc StartYMod208
|
||||
cmp #208
|
||||
bcc *+5
|
||||
sbc #208
|
||||
rts
|
||||
|
||||
SetLimits
|
||||
pha ; Allocate space for width (in tiles), height (in tiles), pointer
|
||||
pha
|
||||
pha
|
||||
pha
|
||||
_GTEGetBG0TileMapInfo
|
||||
pla
|
||||
sta TileMapWidth
|
||||
pla
|
||||
sta TileMapHeight
|
||||
pla
|
||||
pla ; discard the pointer
|
||||
|
||||
pha ; Allocate space for x, y, width, height
|
||||
pha
|
||||
pha
|
||||
pha
|
||||
_GTEGetScreenInfo
|
||||
pla
|
||||
pla ; Discard screen corner
|
||||
pla
|
||||
sta ScreenWidth
|
||||
pla
|
||||
sta ScreenHeight
|
||||
|
||||
lda TileMapWidth
|
||||
asl
|
||||
asl
|
||||
|
@ -373,38 +454,44 @@ SetLimits
|
|||
sta MaxBG0Y
|
||||
rts
|
||||
|
||||
; Set the scroll position based on the global cooridinate of the player
|
||||
; Set the scroll position based on the global coordinates of the player
|
||||
; Try to center the player on the screen
|
||||
UpdateCameraPos
|
||||
lda ScreenWidth
|
||||
lsr
|
||||
sta tmp0
|
||||
sta appTmp0
|
||||
lda PlayerGlobalX
|
||||
sec
|
||||
sbc tmp0
|
||||
sbc appTmp0
|
||||
bpl :x_pos
|
||||
lda #0
|
||||
:x_pos cmp MaxBG0X
|
||||
bcc :x_ok
|
||||
lda MaxBG0X
|
||||
:x_ok jsl SetBG0XPos
|
||||
:x_ok sta StartX
|
||||
|
||||
lda ScreenHeight
|
||||
lsr
|
||||
sta tmp0
|
||||
sta appTmp0
|
||||
lda PlayerGlobalY
|
||||
sec
|
||||
sbc tmp0
|
||||
sbc appTmp0
|
||||
bpl :y_pos
|
||||
lda #0
|
||||
:y_pos cmp MaxBG0Y
|
||||
bcc :y_ok
|
||||
lda MaxBG0Y
|
||||
:y_ok jsl SetBG0YPos
|
||||
:y_ok sta StartY
|
||||
|
||||
pei StartX
|
||||
pei StartY
|
||||
_GTESetBG0Origin
|
||||
|
||||
pea $0000
|
||||
lda StartY
|
||||
lsr
|
||||
jsl SetBG1YPos
|
||||
pha
|
||||
_GTESetBG1Origin
|
||||
rts
|
||||
|
||||
; Convert the global coordinates to adjusted local coordinated (compensating for wrap-around)
|
||||
|
@ -412,13 +499,11 @@ UpdatePlayerLocal
|
|||
lda PlayerGlobalX
|
||||
sec
|
||||
sbc StartX
|
||||
; jsr AdjustLocalX
|
||||
sta PlayerX
|
||||
|
||||
lda PlayerGlobalY
|
||||
sec
|
||||
sbc StartY
|
||||
; jsr AdjustLocalY
|
||||
sta PlayerY
|
||||
rts
|
||||
|
||||
|
@ -431,13 +516,16 @@ UpdatePlayerPos
|
|||
|
||||
; Check if the player is standing on the ground at their current local position
|
||||
|
||||
ldx PlayerX
|
||||
pha ; space for result
|
||||
lda PlayerX
|
||||
pha
|
||||
lda PlayerY
|
||||
clc
|
||||
adc #16
|
||||
tay
|
||||
jsr GetTileAt
|
||||
and #$1FF
|
||||
pha
|
||||
_GTEGetTileAt
|
||||
pla
|
||||
and #TILE_ID_MASK
|
||||
cmp #EMPTY_TILE
|
||||
beq :no_ground_check
|
||||
|
||||
|
@ -501,7 +589,7 @@ UpdatePlayerPos
|
|||
|
||||
txa
|
||||
ora LastHFlip
|
||||
ora #SPRITE_ID
|
||||
ora #HERO_ID
|
||||
sta SpriteFrame
|
||||
|
||||
lda SpriteCount
|
||||
|
@ -514,7 +602,7 @@ UpdatePlayerPos
|
|||
lda PlayerXVel
|
||||
beq :frame
|
||||
|
||||
jsl GetVBLTicks
|
||||
jsr _GetVBLTicks
|
||||
and #$0003
|
||||
inc
|
||||
and #$0003
|
||||
|
@ -527,65 +615,21 @@ UpdatePlayerPos
|
|||
tax
|
||||
|
||||
lda PlayerID
|
||||
jsl UpdateSprite ; Change the tile ID and / or flags
|
||||
; jsl UpdateSprite ; Change the tile ID and / or flags
|
||||
|
||||
; pea HERO_SLOT
|
||||
; pei Flips ; with these flags (h/v flip)
|
||||
; pea VBUFF_SPRITE_START ; and use this stamp
|
||||
; _GTEUpdateSprite
|
||||
|
||||
rts
|
||||
|
||||
ToolPath str '1/Tool160'
|
||||
LastHFlip dw 0
|
||||
SpriteFrame ds 2
|
||||
SpriteCount dw 0
|
||||
SpriteToggle dw 0
|
||||
|
||||
; X = coordinate
|
||||
; Y = coordinate
|
||||
GetTileAt
|
||||
txa
|
||||
bmi :out
|
||||
clc
|
||||
adc StartXMod164
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
|
||||
tya
|
||||
bmi :out
|
||||
clc
|
||||
adc StartYMod208
|
||||
cmp #208
|
||||
bcc *+5
|
||||
sbc #208
|
||||
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tay
|
||||
|
||||
jsl GetTileStoreOffset
|
||||
tax
|
||||
ldal TileStore+TS_TILE_ID,x
|
||||
rts
|
||||
|
||||
:out
|
||||
lda #EMPTY_TILE
|
||||
rts
|
||||
|
||||
; Position the screen with the botom-left corner of the tilemap visible
|
||||
MovePlayerToOrigin
|
||||
lda #0 ; Set the player's position
|
||||
jsl SetBG0XPos
|
||||
|
||||
lda TileMapHeight
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
sec
|
||||
sbc ScreenHeight
|
||||
jsl SetBG0YPos
|
||||
rts
|
||||
|
||||
openRec dw 2 ; pCount
|
||||
ds 2 ; refNum
|
||||
|
@ -657,8 +701,91 @@ msgLine2 str 'Press a key :'
|
|||
msgLine3 str ' -> Return to Try Again'
|
||||
msgLine4 str ' -> Esc to Quit'
|
||||
|
||||
PUT ../shell/Overlay.s
|
||||
PUT gen/App.TileMapBG0.s
|
||||
PUT gen/App.TileSetAnim.s
|
||||
|
||||
ANGLEBNK ENT
|
||||
; Load the GTE User Tool and install it
|
||||
GTEStartUp
|
||||
pea $0000
|
||||
_LoaderStatus
|
||||
pla
|
||||
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000 ; result space
|
||||
|
||||
lda MyUserId
|
||||
pha
|
||||
|
||||
pea #^ToolPath
|
||||
pea #ToolPath
|
||||
pea $0001 ; do not load into special memory
|
||||
_InitialLoad
|
||||
bcc :ok1
|
||||
brk $01
|
||||
|
||||
:ok1
|
||||
ply
|
||||
pla ; Address of the loaded tool
|
||||
plx
|
||||
ply
|
||||
ply
|
||||
|
||||
pea $8000 ; User toolset
|
||||
pea $00A0 ; Set the tool set number
|
||||
phx
|
||||
pha ; Address of function pointer table
|
||||
_SetTSPtr
|
||||
bcc :ok2
|
||||
brk $02
|
||||
|
||||
:ok2
|
||||
clc ; Give GTE a page of direct page memory
|
||||
tdc
|
||||
adc #$0100
|
||||
pha
|
||||
pea #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER ; Enable Dynamic Tiles and Two Layer
|
||||
lda MyUserId ; Pass the userId for memory allocation
|
||||
pha
|
||||
_GTEStartUp
|
||||
bcc :ok3
|
||||
brk $03
|
||||
|
||||
:ok3
|
||||
rts
|
||||
|
||||
_Deref MAC
|
||||
phb ; save caller's data bank register
|
||||
pha ; push high word of handle on stack
|
||||
plb ; sets B to the bank byte of the pointer
|
||||
lda |$0002,x ; load the high word of the master pointer
|
||||
pha ; and save it on the stack
|
||||
lda |$0000,x ; load the low word of the master pointer
|
||||
tax ; and return it in X
|
||||
pla ; restore the high word in A
|
||||
plb ; pull the handle's high word high byte off the
|
||||
; stack
|
||||
plb ; restore the caller's data bank register
|
||||
<<<
|
||||
|
||||
AllocBank PushLong #0
|
||||
PushLong #$10000
|
||||
PushWord MyUserId
|
||||
PushWord #%11000000_00011100
|
||||
PushLong #0
|
||||
_NewHandle
|
||||
plx ; base address of the new handle
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
_Deref
|
||||
rts
|
||||
|
||||
_GetVBLTicks
|
||||
PushLong #0
|
||||
_GetTick
|
||||
pla
|
||||
plx
|
||||
rts
|
||||
|
||||
PUT ../shell/Overlay.s
|
||||
PUT gen/App.TileMapBG0.s
|
||||
PUT gen/App.TileSetAnim.s
|
||||
|
|
|
@ -7,31 +7,9 @@
|
|||
; Segment #1 -- Main execution block
|
||||
|
||||
ASM App.Main.s
|
||||
DS 0 ; Number of bytes of 0's to add at the end of the Segment
|
||||
KND #$1100 ; Type and Attributes ($11=Static+Bank Relative,$00=Code)
|
||||
ALI None ; Boundary Alignment (None)
|
||||
SNA Main
|
||||
|
||||
; Segment #2 -- Core GTE Code
|
||||
|
||||
ASM ..\..\src\Core.s
|
||||
SNA Core
|
||||
|
||||
; Segment #3 -- 64KB Tile Memory
|
||||
; Segment #2 -- Tileset
|
||||
|
||||
ASM gen\App.TileSet.s
|
||||
DS 0
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
SNA Tiles
|
||||
|
||||
; Segment #4 -- 64KB Sprite Plane Data
|
||||
|
||||
ASM SprData.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
SNA SPRDATA
|
||||
|
||||
; Segment #5 -- 64KB Sprite Mask Data
|
||||
|
||||
ASM SprMask.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
SNA SPRMASK
|
||||
SNA TSET
|
|
@ -1 +1,2 @@
|
|||
GTEZelda=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
GTETestSprites=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
|
|
|
@ -14,24 +14,24 @@
|
|||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,185,186,186,187,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,153,154,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,155,156,157,158,33,33,33,33,33,33,33,33,33,33,33,33,153,154,153,154,153,154,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,153,154,153,154,153,154,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,59,60,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,185,186,186,187,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,185,186,186,186,186,186,186,187,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,185,186,186,186,186,186,186,187,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,55,56,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,155,156,157,158,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,155,156,157,156,157,156,157,158,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,155,156,157,156,157,156,157,158,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,55,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,137,138,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,155,156,157,158,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,155,156,157,156,157,156,157,158,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,155,156,157,156,157,156,157,158,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,55,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,169,170,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,159,160,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,33,33,33,33,33,33,188,188,188,188,188,188,159,160,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,159,160,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,188,188,188,188,188,188,33,33,33,33,33,33,33,33,188,188,159,160,159,160,188,188,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,191,192,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,33,33,33,33,33,33,26,26,26,26,26,26,191,192,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,191,192,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,26,26,26,26,26,26,33,33,33,33,33,33,33,33,26,26,191,192,191,192,26,26,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,31,32,31,32,31,32,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,26,26,26,26,26,26,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,7,8,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,26,26,26,26,26,26,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,137,138,137,138,137,138,137,138,137,138,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,26,26,26,26,26,26,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,169,170,169,170,169,170,169,170,169,170,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,7,8,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,26,26,26,26,26,26,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,159,160,33,33,33,33,33,33,188,188,159,160,188,188,159,160,188,188,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,11,12,13,14,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,11,12,13,14,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,188,188,159,160,188,188,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,188,188,33,33,33,33,33,33,33,33,33,33,188,188,188,188,33,33,33,33,33,33,33,33,159,160,33,33,33,33,159,160,33,33,33,33,159,160,33,33,33,33,33,33,33,33,33,33,188,188,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,188,188,188,188,33,33,33,33,33,33,33,33,33,33,33,33,5,6,33,33,33,33,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,33,33,33,33,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,188,188,188,188,159,160,188,188,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,5,6,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,26,64,26,26,64,26,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,191,192,33,33,33,33,33,33,26,26,191,192,26,26,191,192,26,26,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,15,16,17,18,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,15,16,17,18,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,26,26,191,192,26,26,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,26,26,33,33,33,33,33,33,33,33,33,33,26,26,26,26,33,33,33,33,33,33,33,33,191,192,33,33,33,33,191,192,33,33,33,33,191,192,33,33,33,33,33,33,33,33,33,33,26,26,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,26,26,26,26,33,33,33,33,33,33,33,33,33,33,33,33,7,8,33,33,33,33,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,33,33,33,33,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,26,26,26,26,191,192,26,26,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,7,8,7,8,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,33,33,26,64,26,26,64,26,33,33,33,33,
|
||||
33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,11,12,13,14,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,33,33,33,33,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,33,33,33,33,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,5,6,5,6,5,6,5,6,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,9,10,33,33,33,33,33,33,31,32,24,25,24,25,24,25,31,32,33,33,
|
||||
33,33,33,33,49,50,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,15,16,17,18,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,49,50,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,49,50,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,33,33,33,33,7,8,7,8,33,33,33,33,33,33,33,33,49,50,33,33,33,33,33,33,7,8,7,8,7,8,33,33,33,33,7,8,7,8,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,7,8,7,8,7,8,7,8,33,33,33,33,33,33,33,33,49,50,33,33,33,33,33,33,9,10,33,33,33,33,33,33,26,26,26,26,57,58,26,26,26,26,33,33,
|
||||
33,33,33,48,21,54,51,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,11,12,13,14,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,48,21,54,51,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,48,21,54,51,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,33,33,33,33,5,6,5,6,5,6,33,33,33,33,33,48,21,54,51,33,33,33,5,6,5,6,5,6,5,6,33,33,33,33,5,6,5,6,5,6,33,33,33,33,33,33,33,33,33,33,11,12,13,14,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,11,12,13,14,33,33,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,33,33,33,33,33,33,33,48,21,54,51,33,33,33,33,33,9,10,33,33,33,33,33,33,26,26,26,26,64,64,26,26,26,26,33,33,
|
||||
33,33,48,21,21,21,21,51,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,49,2147483697,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,15,16,17,18,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,48,21,21,21,21,51,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,49,50,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,48,21,21,21,21,51,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,49,50,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,33,33,33,33,7,8,7,8,7,8,33,33,33,33,48,21,21,21,21,51,33,33,7,8,7,8,7,8,7,8,33,33,33,33,7,8,7,8,7,8,33,33,33,33,33,33,49,50,33,33,15,16,17,18,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,15,16,17,18,33,33,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,33,33,33,33,33,33,48,21,21,21,21,51,33,33,33,33,9,10,33,33,33,33,33,33,26,26,26,26,64,64,26,26,26,26,33,33,
|
||||
33,48,21,54,21,21,54,21,51,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,35,34,35,34,35,33,33,33,48,21,54,2147483696,33,33,87,86,87,86,87,86,87,86,33,34,35,33,33,87,86,87,86,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,34,35,34,35,33,33,33,33,19,20,21,22,33,48,21,54,21,21,54,21,51,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,34,35,34,35,34,35,33,33,33,48,21,54,51,33,33,33,33,33,33,33,33,33,33,33,34,35,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,35,34,35,33,33,33,33,33,33,33,33,33,48,21,54,21,21,54,21,51,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,35,34,35,34,35,33,33,33,48,21,54,51,33,33,33,33,33,33,33,33,33,33,33,34,35,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,5,6,34,35,34,35,5,6,5,6,5,6,5,6,33,48,21,54,21,21,54,21,5,6,5,6,5,6,5,6,5,6,33,33,33,33,5,6,5,6,5,6,5,6,33,33,33,48,21,54,51,33,19,20,21,22,33,33,33,33,0,33,34,35,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,33,33,33,33,33,48,21,54,21,21,54,21,51,33,33,33,5,6,33,33,33,33,33,33,26,26,26,26,64,64,26,26,26,26,33,33,
|
||||
48,21,21,21,21,21,21,21,21,51,33,33,33,33,33,33,33,33,33,33,33,33,33,36,37,37,37,37,37,37,38,33,48,21,21,21,21,2147483696,33,119,118,119,118,119,118,119,118,36,37,37,38,33,119,118,119,118,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,36,37,37,37,37,38,33,33,33,19,20,21,22,48,21,21,21,21,21,21,21,21,51,33,33,33,33,33,33,33,33,19,20,21,22,33,36,37,37,37,37,37,37,38,33,48,21,21,21,21,51,33,33,33,33,33,33,33,33,33,36,37,37,38,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,36,37,37,37,37,38,33,33,33,33,33,33,33,48,21,21,21,21,21,21,21,21,51,33,33,33,33,33,33,33,33,33,33,33,33,33,36,37,37,37,37,37,37,38,33,48,21,21,21,21,51,33,33,33,33,33,33,33,33,33,36,37,37,38,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,7,8,37,37,37,37,7,8,7,8,7,8,7,8,48,21,21,21,21,21,21,21,7,8,7,8,7,8,7,8,7,8,33,33,33,33,7,8,7,8,7,8,7,8,38,33,48,21,21,21,21,51,19,20,21,22,33,33,33,33,0,36,37,37,38,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,33,33,33,33,48,21,21,21,21,21,21,21,21,51,33,33,7,8,33,33,33,33,33,33,26,26,26,26,64,64,26,26,26,26,38,33,
|
||||
33,48,21,54,21,21,54,21,51,33,137,138,33,33,33,33,33,33,33,33,33,33,33,33,34,35,34,35,34,35,33,33,33,48,21,54,2147483696,33,33,87,86,87,86,87,86,87,86,33,34,35,33,33,87,86,87,86,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,33,34,35,34,35,33,33,33,33,19,20,21,22,33,48,21,54,21,21,54,21,51,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,34,35,34,35,34,35,33,33,33,48,21,54,51,33,33,33,33,33,33,33,33,33,33,33,34,35,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,35,34,35,33,33,33,33,33,33,33,33,33,48,21,54,21,21,54,21,51,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,35,34,35,34,35,33,33,33,48,21,54,51,33,33,33,33,33,33,33,33,33,33,33,34,35,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,5,6,5,6,5,6,5,6,34,35,34,35,5,6,5,6,5,6,5,6,33,48,21,54,21,21,54,21,5,6,5,6,5,6,5,6,5,6,33,33,33,33,5,6,5,6,5,6,5,6,33,33,33,48,21,54,51,33,19,20,21,22,33,33,33,33,0,33,34,35,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,33,33,33,33,33,48,21,54,21,21,54,21,51,33,33,33,5,6,33,33,33,33,33,33,26,26,26,26,64,64,26,26,26,26,33,33,
|
||||
48,21,21,21,21,21,21,21,21,51,169,170,33,33,33,33,33,33,33,33,33,33,33,36,37,37,37,37,37,37,38,33,48,21,21,21,21,2147483696,33,119,118,119,118,119,118,119,118,36,37,37,38,33,119,118,119,118,19,20,21,22,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,33,33,33,36,37,37,37,37,38,33,33,33,19,20,21,22,48,21,21,21,21,21,21,21,21,51,33,33,33,33,33,33,33,33,19,20,21,22,33,36,37,37,37,37,37,37,38,33,48,21,21,21,21,51,33,33,33,33,33,33,33,33,33,36,37,37,38,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,36,37,37,37,37,38,33,33,33,33,33,33,33,48,21,21,21,21,21,21,21,21,51,33,33,33,33,33,33,33,33,33,33,33,33,33,36,37,37,37,37,37,37,38,33,48,21,21,21,21,51,33,33,33,33,33,33,33,33,33,36,37,37,38,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,7,8,7,8,7,8,7,8,37,37,37,37,7,8,7,8,7,8,7,8,48,21,21,21,21,21,21,21,7,8,7,8,7,8,7,8,7,8,33,33,33,33,7,8,7,8,7,8,7,8,38,33,48,21,21,21,21,51,19,20,21,22,33,33,33,33,0,36,37,37,38,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,19,20,21,22,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,33,33,33,33,48,21,21,21,21,21,21,21,21,51,33,33,7,8,33,33,33,33,33,33,26,26,26,26,64,64,26,26,26,26,38,33,
|
||||
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,33,33,33,33,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,33,33,33,33,33,33,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,33,33,33,33,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
|
||||
3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,33,33,33,33,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,33,33,33,33,33,33,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,33,33,33,33,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,
|
||||
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,33,33,33,33,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,33,33,33,33,33,33,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,33,33,33,33,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
|
||||
|
|
|
@ -14,6 +14,7 @@ REM Cadius does not overwrite files, so clear the root folder first
|
|||
|
||||
REM Now copy files and folders as needed
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% .\GTETestSprites
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\src\Tool160
|
||||
|
||||
REM Copy in the image assets
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% .\assets\mario1.c1
|
||||
|
|
|
@ -5,14 +5,19 @@
|
|||
|
||||
|
||||
BG0SetUp
|
||||
lda #416
|
||||
sta TileMapWidth
|
||||
lda #30
|
||||
sta TileMapHeight
|
||||
lda #App_TileMapBG0
|
||||
sta TileMapPtr
|
||||
lda #^App_TileMapBG0
|
||||
sta TileMapPtr+2
|
||||
pea #416
|
||||
pea #30
|
||||
pea #^App_TileMapBG0
|
||||
pea #App_TileMapBG0
|
||||
_GTESetBG0TileMapInfo
|
||||
; lda #416
|
||||
; sta TileMapWidth
|
||||
; lda #30
|
||||
; sta TileMapHeight
|
||||
; lda #App_TileMapBG0
|
||||
; sta TileMapPtr
|
||||
; lda #^App_TileMapBG0
|
||||
; sta TileMapPtr+2
|
||||
rts
|
||||
|
||||
App_TileMapBG0
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
; Palette:
|
||||
; $068F,$0EDA,$0000,$0F0F,$0BF1,$00A0,$0EEE,$0456,$0FA4,$0F59,$0E30,$01CE,$02E3,$0870,$0F93,$0FD7
|
||||
; Converting to BG0 format...
|
||||
tiledata ENT
|
||||
TSet ENT
|
||||
|
||||
; Reserved space (tile 0 is special...
|
||||
ds 128
|
||||
|
|
|
@ -1,52 +1,40 @@
|
|||
|
||||
TileAnimInit ENT
|
||||
TileAnimInit
|
||||
pea #137
|
||||
pea #0
|
||||
_GTECopyTileToDynamic
|
||||
pea #138
|
||||
pea #1
|
||||
_GTECopyTileToDynamic
|
||||
pea #169
|
||||
pea #2
|
||||
_GTECopyTileToDynamic
|
||||
pea #170
|
||||
pea #3
|
||||
_GTECopyTileToDynamic
|
||||
|
||||
ldx #137
|
||||
ldy #0
|
||||
jsl CopyTileToDyn
|
||||
ldx #138
|
||||
ldy #1
|
||||
jsl CopyTileToDyn
|
||||
ldx #169
|
||||
ldy #2
|
||||
jsl CopyTileToDyn
|
||||
ldx #170
|
||||
ldy #3
|
||||
jsl CopyTileToDyn
|
||||
lda #TileAnim_136
|
||||
ldx #^TileAnim_136
|
||||
ldy #15
|
||||
jsl StartScript
|
||||
lda #TileAnim_137
|
||||
ldx #^TileAnim_137
|
||||
ldy #15
|
||||
jsl StartScript
|
||||
lda #TileAnim_168
|
||||
ldx #^TileAnim_168
|
||||
ldy #15
|
||||
jsl StartScript
|
||||
lda #TileAnim_169
|
||||
ldx #^TileAnim_169
|
||||
ldy #15
|
||||
jsl StartScript
|
||||
pea #15
|
||||
pea #^TileAnim
|
||||
pea #TileAnim
|
||||
_GTEStartScript
|
||||
rts
|
||||
TileAnim_136
|
||||
dw $8006,137,0,0
|
||||
dw $8006,139,0,0
|
||||
dw $8006,141,0,0
|
||||
dw $cd06,143,0,0
|
||||
TileAnim_137
|
||||
dw $8006,138,1,0
|
||||
dw $8006,140,1,0
|
||||
dw $8006,142,1,0
|
||||
dw $cd06,144,1,0
|
||||
TileAnim_168
|
||||
dw $8006,169,2,0
|
||||
dw $8006,171,2,0
|
||||
dw $8006,173,2,0
|
||||
dw $cd06,175,2,0
|
||||
TileAnim_169
|
||||
TileAnim
|
||||
dw $0006,137,0,0
|
||||
dw $0006,138,1,0
|
||||
dw $0006,169,2,0
|
||||
dw $8006,170,3,0
|
||||
|
||||
dw $0006,139,0,0
|
||||
dw $0006,140,1,0
|
||||
dw $0006,171,2,0
|
||||
dw $8006,172,3,0
|
||||
|
||||
dw $0006,141,0,0
|
||||
dw $0006,142,1,0
|
||||
dw $0006,173,2,0
|
||||
dw $8006,174,3,0
|
||||
dw $cd06,176,3,0
|
||||
|
||||
dw $0006,143,0,0
|
||||
dw $0006,144,1,0
|
||||
dw $0006,175,2,0
|
||||
dw $cc46,176,3,0 ; STOP; JUMP(-15) -15 = $31 (6 bit) = %110001 = 1100 0100 = C4
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
"scripts": {
|
||||
"test": "npm run build && build-image.bat %npm_package_config_cadius% && %npm_package_config_gsport%",
|
||||
"debug": "%npm_package_config_crossrunner% GTETestSprites -Source GTETestSprites_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"build": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
|
||||
"build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
|
||||
"build:map": "node %npm_package_config_tiled2iigs% ./assets/tiled/world_1-1.json --output-dir ./gen",
|
||||
"build:map:masked": "node %npm_package_config_tiled2iigs% ./assets/tiled/world_1-1.json --force-masked --empty-tile 33 --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "node %npm_package_config_png2iigs% ../shell/assets/tilesets/smb-256-128-4bpp.png --max-tiles 360 --as-tile-data --transparent-color FF00FF --background-color 6B8CFF > ./gen/App.TileSet.s",
|
||||
"build:tiles:1bpp": "node %npm_package_config_png2iigs% ../shell/assets/tilesets/smb-256-128-1bpp.png --max-tiles 360 --as-tile-data --transparent-color FF00FF --palette 010102,00000,000000,000000,000000,000000,000000,000000,000000,000000,000000,000000,000000,000000,000000,FDFEFE > ./gen/App.TileSet.s"
|
||||
"build:tiles:1bpp": "node %npm_package_config_png2iigs% ../shell/assets/tilesets/smb-256-128-1bpp.png --max-tiles 360 --as-tile-data --transparent-color FF00FF --palette 010102,00000,000000,000000,000000,000000,000000,000000,000000,000000,000000,000000,000000,000000,000000,FDFEFE > ./gen/App.TileSet.s",
|
||||
"build": "npm run build:tool && npm run build:sys16",
|
||||
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../src/Master.s"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
GTEToolDemo
|
|
@ -0,0 +1,654 @@
|
|||
REL
|
||||
DSK MAINSEG
|
||||
|
||||
use Locator.Macs
|
||||
use Load.Macs
|
||||
use Mem.Macs
|
||||
use Misc.Macs
|
||||
use Util.Macs
|
||||
use EDS.GSOS.Macs
|
||||
use GTE.Macs
|
||||
|
||||
mx %00
|
||||
|
||||
TSZelda EXT ; tileset buffer
|
||||
|
||||
MAX_SPRITES equ 16
|
||||
|
||||
ScreenX equ 0
|
||||
ScreenY equ 2
|
||||
Tmp0 equ 4
|
||||
Tmp1 equ 6
|
||||
KeyState equ 8
|
||||
Selected equ 10
|
||||
Flips equ 12
|
||||
DTile equ 14
|
||||
Tmp2 equ 16
|
||||
|
||||
; Typical init
|
||||
phk
|
||||
plb
|
||||
|
||||
sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize the graphics screen to a 256x160 playfield
|
||||
|
||||
pea #320
|
||||
pea #200
|
||||
_GTESetScreenMode
|
||||
|
||||
; Load a tileset
|
||||
|
||||
pea #^TSZelda
|
||||
pea #TSZelda
|
||||
_GTELoadTileSet
|
||||
|
||||
; Set the palette
|
||||
ldx #11*2
|
||||
:ploop
|
||||
lda palette,x
|
||||
stal $E19E00,x
|
||||
dex
|
||||
dex
|
||||
bpl :ploop
|
||||
bra sprt
|
||||
|
||||
palette dw $0000,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$023E
|
||||
sprt
|
||||
|
||||
; Create stamps for the sprites we are going to use
|
||||
HERO_SPRITE equ SPRITE_16X16+1
|
||||
|
||||
pea HERO_SPRITE ; sprint id
|
||||
pea VBUFF_SPRITE_START ; vbuff address
|
||||
_GTECreateSpriteStamp
|
||||
|
||||
; Create sprites
|
||||
stz Tmp0
|
||||
stz Tmp1
|
||||
|
||||
ldx Tmp0
|
||||
:sloop
|
||||
pea HERO_SPRITE ; sprite id
|
||||
lda PlayerX,x
|
||||
pha
|
||||
lda PlayerY,x
|
||||
pha
|
||||
pei Tmp1
|
||||
_GTEAddSprite
|
||||
|
||||
pei Tmp1 ; update the sprite in this slot
|
||||
pea $0000 ; with these flags (h/v flip)
|
||||
pea VBUFF_SPRITE_START ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
inc Tmp1
|
||||
ldx Tmp0
|
||||
inx
|
||||
inx
|
||||
stx Tmp0
|
||||
cpx #MAX_SPRITES*2
|
||||
bcc :sloop
|
||||
|
||||
; Manually fill in the 41x26 tiles of the TileStore with a test pattern of trees
|
||||
|
||||
; lda #TILE_DYN_BIT+TILE_PRIORITY_BIT+0 ; fill the screen the the dynamic tile slot 0
|
||||
lda #TILE_DYN_BIT+0 ; fill the screen the the dynamic tile slot 0
|
||||
jsr _fillTileStore
|
||||
; brl :no_trees
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
jsr _drawTree
|
||||
|
||||
ldx #3
|
||||
ldy #0
|
||||
jsr _drawTreeH
|
||||
|
||||
ldx #0
|
||||
ldy #3
|
||||
jsr _drawTreeV
|
||||
|
||||
ldx #3
|
||||
ldy #3
|
||||
jsr _drawTreeHV
|
||||
|
||||
ldx #9
|
||||
ldy #0
|
||||
jsr _drawTree
|
||||
|
||||
ldx #9
|
||||
ldy #3
|
||||
jsr _drawTree
|
||||
|
||||
ldx #12
|
||||
ldy #0
|
||||
jsr _drawTree
|
||||
|
||||
ldx #12
|
||||
ldy #3
|
||||
jsr _drawTree
|
||||
|
||||
ldx #6
|
||||
ldy #0
|
||||
jsr _drawTreeFront
|
||||
|
||||
ldx #6
|
||||
ldy #3
|
||||
jsr _drawTreeFront
|
||||
|
||||
ldx #6
|
||||
ldy #6
|
||||
jsr _drawTreeFront
|
||||
|
||||
ldx #3
|
||||
ldy #6
|
||||
jsr _drawTreeFront
|
||||
|
||||
ldx #0
|
||||
ldy #6
|
||||
jsr _drawTreeFront
|
||||
:no_trees
|
||||
; Set up the dynamic tile
|
||||
lda #65
|
||||
sta DTile
|
||||
|
||||
pei DTile
|
||||
pea $0000
|
||||
_GTECopyTileToDynamic ; Copy DTile into the first dynamic tile slot
|
||||
|
||||
; Initialize the frame counter
|
||||
|
||||
stz FrameCount
|
||||
|
||||
; Set the screen coordinates
|
||||
|
||||
lda #128
|
||||
sta ScreenX
|
||||
lda #128
|
||||
sta ScreenY
|
||||
|
||||
stz Selected
|
||||
stz Flips
|
||||
|
||||
; Very simple actions
|
||||
:evt_loop
|
||||
pha ; space for result, with pattern
|
||||
_GTEReadControl
|
||||
pla
|
||||
and #$00FF
|
||||
cmp #'q'
|
||||
bne :2
|
||||
brl :exit
|
||||
:2
|
||||
; cmp KeyState
|
||||
; beq :evt_loop
|
||||
; sta KeyState
|
||||
; cmp #0
|
||||
; beq :evt_loop
|
||||
|
||||
; cmp #' '
|
||||
; bne :evt_loop ; only advance one frame at a time
|
||||
; brl :next
|
||||
|
||||
:3
|
||||
cmp #'1'
|
||||
bcc :3a
|
||||
cmp #'9'
|
||||
bcs :3a
|
||||
sec
|
||||
sbc #'1'
|
||||
asl
|
||||
sta Selected
|
||||
brl :next
|
||||
|
||||
:3a
|
||||
cmp #'r'
|
||||
bne :3b
|
||||
lda Flips
|
||||
clc
|
||||
adc #SPRITE_HFLIP
|
||||
and #SPRITE_VFLIP+SPRITE_HFLIP
|
||||
sta Flips
|
||||
|
||||
pei Selected ; update the sprite in this slot
|
||||
pei Flips ; with these flags (h/v flip)
|
||||
pea VBUFF_SPRITE_START ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
:3b
|
||||
cmp #'x'
|
||||
bne :3d
|
||||
ldx Selected
|
||||
lda PlayerX,x
|
||||
clc
|
||||
adc PlayerU,x
|
||||
sta PlayerX,x
|
||||
|
||||
lda PlayerY,x
|
||||
clc
|
||||
adc PlayerV,x
|
||||
sta PlayerY,x
|
||||
brl :next
|
||||
:3d
|
||||
cmp #'z'
|
||||
bne :3e
|
||||
ldx Selected
|
||||
lda PlayerX,x
|
||||
sec
|
||||
sbc PlayerU,x
|
||||
sta PlayerX,x
|
||||
|
||||
lda PlayerY,x
|
||||
sec
|
||||
sbc PlayerV,x
|
||||
sta PlayerY,x
|
||||
brl :next
|
||||
:3e
|
||||
cmp #'s'
|
||||
bne :4
|
||||
ldx Selected
|
||||
inc PlayerY,x
|
||||
brl :next
|
||||
:4
|
||||
cmp #'w'
|
||||
bne :5
|
||||
ldx Selected
|
||||
dec PlayerY,x
|
||||
brl :next
|
||||
:5
|
||||
cmp #'d'
|
||||
bne :6
|
||||
ldx Selected
|
||||
inc PlayerX,x
|
||||
brl :next
|
||||
:6
|
||||
cmp #'a'
|
||||
bne :7
|
||||
ldx Selected
|
||||
dec PlayerX,x
|
||||
brl :next
|
||||
:7
|
||||
cmp #$15 ; left = $08, right = $15, up = $0B, down = $0A
|
||||
bne :8
|
||||
inc ScreenX
|
||||
bra :next
|
||||
|
||||
:8 cmp #$08
|
||||
bne :9
|
||||
dec ScreenX
|
||||
brl :next
|
||||
|
||||
:9 cmp #$0B
|
||||
bne :10
|
||||
inc ScreenY
|
||||
brl :next
|
||||
|
||||
:10 cmp #$0A
|
||||
bne :11
|
||||
dec ScreenY
|
||||
brl :next
|
||||
|
||||
:11 cmp #'y'
|
||||
bne :12
|
||||
lda DTile
|
||||
inc
|
||||
and #$007F
|
||||
sta DTile
|
||||
pha
|
||||
pea $0000
|
||||
_GTECopyTileToDynamic
|
||||
brl :next
|
||||
|
||||
:12 cmp #'f'
|
||||
bne :13
|
||||
pea $0000
|
||||
_GTEFillTileStore
|
||||
brl :next
|
||||
|
||||
:13 cmp #'m'
|
||||
bne :next
|
||||
_GTERefresh
|
||||
|
||||
:next
|
||||
; inc ScreenX
|
||||
|
||||
pei ScreenX
|
||||
pei ScreenY
|
||||
_GTESetBG0Origin
|
||||
|
||||
; brl no_animate
|
||||
|
||||
stz Tmp0
|
||||
stz Tmp1
|
||||
|
||||
ldx Tmp0
|
||||
loopX
|
||||
lda PlayerX,x
|
||||
clc
|
||||
adc PlayerU,x
|
||||
sta PlayerX,x
|
||||
bpl is_posx
|
||||
cmp #-15
|
||||
bcs do_y
|
||||
lda PlayerU,x
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerU,x
|
||||
bra do_y
|
||||
is_posx cmp #128
|
||||
bcc do_y
|
||||
lda PlayerU,x
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerU,x
|
||||
|
||||
do_y
|
||||
lda PlayerY,x
|
||||
clc
|
||||
adc PlayerV,x
|
||||
sta PlayerY,x
|
||||
bpl is_posy
|
||||
cmp #-15
|
||||
bcs do_z
|
||||
lda PlayerV,x
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerV,x
|
||||
bra do_z
|
||||
is_posy cmp #160
|
||||
bcc do_z
|
||||
lda PlayerV,x
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerV,x
|
||||
do_z
|
||||
inc Tmp1
|
||||
ldx Tmp0
|
||||
inx
|
||||
inx
|
||||
stx Tmp0
|
||||
cpx #MAX_SPRITES*2
|
||||
bcc loopX
|
||||
|
||||
no_animate
|
||||
stz Tmp0
|
||||
stz Tmp1
|
||||
ldx Tmp0
|
||||
loopY
|
||||
pei Tmp1
|
||||
lda PlayerX,x
|
||||
pha
|
||||
lda PlayerY,x
|
||||
pha
|
||||
_GTEMoveSprite
|
||||
|
||||
inc Tmp1
|
||||
ldx Tmp0
|
||||
inx
|
||||
inx
|
||||
stx Tmp0
|
||||
cpx #MAX_SPRITES*2
|
||||
bcc loopY
|
||||
|
||||
_GTERender
|
||||
inc FrameCount
|
||||
|
||||
; Debug stuff
|
||||
pha
|
||||
_GTEGetSeconds
|
||||
pla
|
||||
cmp LastSecond
|
||||
beq :no_fps
|
||||
sta LastSecond
|
||||
|
||||
lda FrameCount
|
||||
ldx #0
|
||||
ldy #$FFFF
|
||||
jsr DrawWord
|
||||
|
||||
stz FrameCount
|
||||
:no_fps
|
||||
|
||||
; tdc
|
||||
; ldx #160*32
|
||||
; jsr DrawWord
|
||||
|
||||
brl :evt_loop
|
||||
|
||||
; Shut down everything
|
||||
:exit
|
||||
_GTEShutDown
|
||||
_QuitGS qtRec
|
||||
qtRec adrl $0000
|
||||
da $00
|
||||
|
||||
; Array of sprite positions and velocities
|
||||
PlayerX dw 8,14,29,34,45,67,81,83,92,101,39,22,7,74,111,9
|
||||
PlayerY dw 72,24,13,56,35,72,23,8,93,123,134,87,143,14,46,65
|
||||
PlayerU dw 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4
|
||||
PlayerV dw 1,1,1,1,2,2,2,4,3,3,3,3,4,4,4,4
|
||||
|
||||
; Load the GTE User Tool and install it
|
||||
GTEStartUp
|
||||
pea $0000
|
||||
_LoaderStatus
|
||||
pla
|
||||
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000 ; result space
|
||||
|
||||
lda MyUserId
|
||||
pha
|
||||
|
||||
pea #^ToolPath
|
||||
pea #ToolPath
|
||||
pea $0001 ; do not load into special memory
|
||||
_InitialLoad
|
||||
bcc :ok1
|
||||
brk $01
|
||||
|
||||
:ok1
|
||||
ply
|
||||
pla ; Address of the loaded tool
|
||||
plx
|
||||
ply
|
||||
ply
|
||||
|
||||
pea $8000 ; User toolset
|
||||
pea $00A0 ; Set the tool set number
|
||||
phx
|
||||
pha ; Address of function pointer table
|
||||
_SetTSPtr
|
||||
bcc :ok2
|
||||
brk $02
|
||||
|
||||
:ok2
|
||||
clc ; Give GTE a page of direct page memory
|
||||
tdc
|
||||
adc #$0100
|
||||
pha
|
||||
pea #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER ; Enable Dynamic Tiles and Two Layer
|
||||
lda MyUserId ; Pass the userId for memory allocation
|
||||
pha
|
||||
_GTEStartUp
|
||||
bcc :ok3
|
||||
brk $03
|
||||
|
||||
:ok3
|
||||
rts
|
||||
|
||||
_fillTileStore
|
||||
sta Tmp2
|
||||
stz Tmp0
|
||||
:oloop
|
||||
stz Tmp1
|
||||
:iloop
|
||||
pei Tmp1
|
||||
pei Tmp0
|
||||
pei Tmp2
|
||||
_GTESetTile
|
||||
|
||||
lda Tmp2
|
||||
eor #TILE_PRIORITY_BIT
|
||||
sta Tmp2
|
||||
|
||||
lda Tmp1
|
||||
inc
|
||||
sta Tmp1
|
||||
cmp #41
|
||||
bcc :iloop
|
||||
|
||||
lda Tmp0
|
||||
inc
|
||||
sta Tmp0
|
||||
cmp #26
|
||||
bcc :oloop
|
||||
rts
|
||||
|
||||
; Tile 65 Tile 66
|
||||
; Tile 97 Tile 98
|
||||
|
||||
_drawTreeFront
|
||||
phx
|
||||
phy
|
||||
pea #65+TILE_PRIORITY_BIT
|
||||
|
||||
inx
|
||||
phx
|
||||
phy
|
||||
pea #66+TILE_PRIORITY_BIT
|
||||
|
||||
iny
|
||||
phx
|
||||
phy
|
||||
pea #98+TILE_PRIORITY_BIT
|
||||
|
||||
dex
|
||||
phx
|
||||
phy
|
||||
pea #97+TILE_PRIORITY_BIT
|
||||
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
rts
|
||||
|
||||
_drawTree
|
||||
phx
|
||||
phy
|
||||
pea #65
|
||||
|
||||
inx
|
||||
phx
|
||||
phy
|
||||
pea #66
|
||||
|
||||
iny
|
||||
phx
|
||||
phy
|
||||
pea #98
|
||||
|
||||
dex
|
||||
phx
|
||||
phy
|
||||
pea #97
|
||||
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
rts
|
||||
|
||||
_drawTreeH
|
||||
phx
|
||||
phy
|
||||
pea #66+TILE_HFLIP_BIT
|
||||
|
||||
inx
|
||||
phx
|
||||
phy
|
||||
pea #65+TILE_HFLIP_BIT
|
||||
|
||||
iny
|
||||
phx
|
||||
phy
|
||||
pea #97+TILE_HFLIP_BIT
|
||||
|
||||
dex
|
||||
phx
|
||||
phy
|
||||
pea #98+TILE_HFLIP_BIT
|
||||
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
rts
|
||||
|
||||
_drawTreeV
|
||||
phx
|
||||
phy
|
||||
pea #97+TILE_VFLIP_BIT
|
||||
|
||||
inx
|
||||
phx
|
||||
phy
|
||||
pea #98+TILE_VFLIP_BIT
|
||||
|
||||
iny
|
||||
phx
|
||||
phy
|
||||
pea #66+TILE_VFLIP_BIT
|
||||
|
||||
dex
|
||||
phx
|
||||
phy
|
||||
pea #65+TILE_VFLIP_BIT
|
||||
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
rts
|
||||
|
||||
_drawTreeHV
|
||||
phx
|
||||
phy
|
||||
pea #98+TILE_VFLIP_BIT+TILE_HFLIP_BIT
|
||||
|
||||
inx
|
||||
phx
|
||||
phy
|
||||
pea #97+TILE_VFLIP_BIT+TILE_HFLIP_BIT
|
||||
|
||||
iny
|
||||
phx
|
||||
phy
|
||||
pea #65+TILE_VFLIP_BIT+TILE_HFLIP_BIT
|
||||
|
||||
dex
|
||||
phx
|
||||
phy
|
||||
pea #66+TILE_VFLIP_BIT+TILE_HFLIP_BIT
|
||||
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
_GTESetTile
|
||||
rts
|
||||
|
||||
MyUserId ds 2
|
||||
ToolPath str '1/Tool160'
|
||||
FrameCount ds 2
|
||||
LastSecond dw 0
|
||||
|
||||
PUT App.Msg.s
|
||||
PUT font.s
|
|
@ -0,0 +1,105 @@
|
|||
HexToChar dfb '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
|
||||
|
||||
; Convert a byte (Acc) into a string and store at (Y)
|
||||
ByteToString and #$00FF
|
||||
sep #$20
|
||||
pha
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
and #$0F
|
||||
tax
|
||||
ldal HexToChar,x
|
||||
sta: $0000,y
|
||||
|
||||
pla
|
||||
and #$0F
|
||||
tax
|
||||
ldal HexToChar,x
|
||||
sta: $0001,y
|
||||
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; Convert a word (Acc) into a hexadecimal string and store at (Y)
|
||||
WordToString pha
|
||||
bra Addr2ToString
|
||||
|
||||
; Pass in Acc = High, X = low
|
||||
Addr3ToString phx
|
||||
jsr ByteToString
|
||||
iny
|
||||
iny
|
||||
lda 1,s
|
||||
Addr2ToString xba
|
||||
jsr ByteToString
|
||||
iny
|
||||
iny
|
||||
pla
|
||||
jsr ByteToString
|
||||
rts
|
||||
|
||||
; A=Value
|
||||
; X=Screen offset
|
||||
DrawWord phx ; Save register value
|
||||
phy
|
||||
ldy #WordBuff+1
|
||||
jsr WordToString
|
||||
ply
|
||||
plx
|
||||
lda #WordBuff
|
||||
jsr DrawString
|
||||
rts
|
||||
|
||||
WordBuff str '0000'
|
||||
Addr3Buff str '000000' ; str adds leading length byte
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
; IIgs Sprite Testbed
|
||||
|
||||
TYP $B3 ; S16 file
|
||||
DSK GTEToolDemo
|
||||
XPL
|
||||
|
||||
; Segment #1 -- Main execution block
|
||||
|
||||
ASM App.Main.s
|
||||
SNA Main
|
||||
|
||||
; Segment #2 -- Tileset
|
||||
|
||||
ASM Zelda.TileSet.s
|
||||
SNA TSET
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
GTEToolDemo=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
|
@ -0,0 +1,19 @@
|
|||
echo off
|
||||
|
||||
REM Copy all of the assets into the ProDOS image for emulator testing
|
||||
REM
|
||||
REM Pass the path of the Cadius tool as the first argument (%1)
|
||||
|
||||
set CADIUS="%1"
|
||||
set IMAGE="..\\..\\emu\\Target.2mg"
|
||||
set FOLDER="/GTEDEV/Tool"
|
||||
|
||||
REM Cadius does not overwrite files, so clear the root folder first
|
||||
%CADIUS% DELETEFOLDER %IMAGE% %FOLDER%
|
||||
%CADIUS% CREATEFOLDER %IMAGE% %FOLDER%
|
||||
|
||||
REM Now copy files and folders as needed
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% .\GTEToolDemo
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\src\Tool160
|
||||
|
||||
REM Copy in the image assets
|
|
@ -0,0 +1,668 @@
|
|||
****************************************
|
||||
* FONT ENGINE (v3?) *
|
||||
* *
|
||||
* Dagen Brock <dagenbrock@gmail.com> *
|
||||
* 2013-07-20 *
|
||||
****************************************
|
||||
* A= ptr to string preceded by length *
|
||||
* X= screen location *
|
||||
****************************************
|
||||
; each char:
|
||||
; draw char at loc
|
||||
; update loc
|
||||
; see if length hit - no? back to draw char
|
||||
rel
|
||||
mx %00
|
||||
]F_Length ds 2 ;length of string (only one byte currently used)
|
||||
]F_CharIdx ds 2 ;index of current character
|
||||
]F_CurrentPos ds 2 ;current top left char position
|
||||
]F_StrPtr equ $01 ;pointer to string (including length byte) / DP
|
||||
]F_StrClr equ $03
|
||||
|
||||
DrawString
|
||||
pha ; local variable space
|
||||
pha
|
||||
tsc
|
||||
phd
|
||||
tcd
|
||||
|
||||
; sta ]F_StrPtr ; (done in pha init above) store at dp 0 ($00) for indirect loads
|
||||
stx ]F_CurrentPos
|
||||
sty ]F_StrClr
|
||||
stz ]F_CharIdx
|
||||
lda (]F_StrPtr)
|
||||
and #$00ff ;strip off first char (len is only one byte)
|
||||
sta ]F_Length ;get our length byte
|
||||
|
||||
NextChar lda ]F_CharIdx
|
||||
cmp ]F_Length
|
||||
bne :notDone
|
||||
ldy ]F_StrClr ;restore the color pattern
|
||||
pld
|
||||
pla
|
||||
pla
|
||||
rts ;DONE! Return to caller
|
||||
|
||||
:notDone inc ]F_CharIdx
|
||||
ldy ]F_CharIdx
|
||||
lda (]F_StrPtr),y ;get next char!
|
||||
and #$00FF ;mask high byte
|
||||
sec
|
||||
sbc #' ' ;our table starts with space ' '
|
||||
asl ;*2
|
||||
tay
|
||||
ldx ]F_CurrentPos
|
||||
jsr :drawChar
|
||||
inc ]F_CurrentPos ;compare to addition time (?)
|
||||
inc ]F_CurrentPos
|
||||
inc ]F_CurrentPos
|
||||
inc ]F_CurrentPos ;update screen pos (2 words=8 pixels)
|
||||
bra NextChar
|
||||
|
||||
;x = TopLeft screen pos
|
||||
;y = char table offset
|
||||
:drawChar lda FontTable,y ;get real address of char data
|
||||
sec
|
||||
sbc #FontData ;pivot offset - now a is offset of fontdata
|
||||
tay ;so we'll index with that
|
||||
|
||||
lda FontData,y
|
||||
and ]F_StrClr
|
||||
stal $E12000,x
|
||||
|
||||
lda FontData+2,y
|
||||
and ]F_StrClr
|
||||
stal $E12000+2,x
|
||||
|
||||
lda FontData+4,y
|
||||
and ]F_StrClr
|
||||
stal $E12000+160,x
|
||||
|
||||
lda FontData+6,y
|
||||
and ]F_StrClr
|
||||
stal $E12000+160+2,x
|
||||
|
||||
lda FontData+8,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*2},x
|
||||
|
||||
lda FontData+10,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*2+2},x
|
||||
|
||||
lda FontData+12,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*3},x
|
||||
|
||||
lda FontData+14,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*3+2},x
|
||||
|
||||
lda FontData+16,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*4},x
|
||||
|
||||
lda FontData+18,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*4+2},x
|
||||
|
||||
lda FontData+20,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*5},x
|
||||
|
||||
lda FontData+22,y
|
||||
and ]F_StrClr
|
||||
stal {$E12000+160*5+2},x
|
||||
rts
|
||||
|
||||
FontTable dw s_Space
|
||||
dw s_Exclaim
|
||||
dw s_Quote
|
||||
dw s_Number
|
||||
dw s_Dollar
|
||||
dw s_Percent
|
||||
dw s_Amper
|
||||
dw s_Single
|
||||
dw s_OpenParen
|
||||
dw s_CloseParen
|
||||
dw s_Asterix
|
||||
dw s_Plus
|
||||
dw s_Comma
|
||||
dw s_Minus
|
||||
dw s_Period
|
||||
dw s_Slash
|
||||
dw s_N0
|
||||
dw s_N1
|
||||
dw s_N2
|
||||
dw s_N3
|
||||
dw s_N4
|
||||
dw s_N5
|
||||
dw s_N6
|
||||
dw s_N7
|
||||
dw s_N8
|
||||
dw s_N9
|
||||
dw s_Colon
|
||||
dw s_Semi
|
||||
dw s_LAngle
|
||||
dw s_Equal
|
||||
dw s_RAngle
|
||||
dw s_Question
|
||||
dw s_At
|
||||
dw s_A
|
||||
dw s_B
|
||||
dw s_C
|
||||
dw s_D
|
||||
dw s_E
|
||||
dw s_F
|
||||
dw s_G
|
||||
dw s_H
|
||||
dw s_I
|
||||
dw s_J
|
||||
dw s_K
|
||||
dw s_L
|
||||
dw s_M
|
||||
dw s_N
|
||||
dw s_O
|
||||
dw s_P
|
||||
dw s_Q
|
||||
dw s_R
|
||||
dw s_S
|
||||
dw s_T
|
||||
dw s_U
|
||||
dw s_V
|
||||
dw s_W
|
||||
dw s_X
|
||||
dw s_Y
|
||||
dw s_Z
|
||||
dw s_LBracket
|
||||
dw s_BackSlash
|
||||
dw s_RBracket
|
||||
dw s_Carot
|
||||
dw s_UnderLine
|
||||
|
||||
FontData = *
|
||||
s_Space hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
|
||||
s_Exclaim hex 000FF000
|
||||
hex 000FF000
|
||||
hex 000FF000
|
||||
hex 000FF000
|
||||
hex 00000000
|
||||
hex 000FF000
|
||||
|
||||
s_Quote hex 0FF00FF0
|
||||
hex 00F000F0
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
|
||||
s_Number hex 00000000
|
||||
hex 00F00F00
|
||||
hex 0FFFFFF0
|
||||
hex 00F00F00
|
||||
hex 0FFFFFF0
|
||||
hex 00F00F00
|
||||
|
||||
s_Dollar hex 000F0F00
|
||||
hex 00FFFFF0
|
||||
hex 0F0F0F00
|
||||
hex 00FFFF00
|
||||
hex 000F0FF0
|
||||
hex 0FFFFF00
|
||||
|
||||
s_Percent hex 0FF000F0
|
||||
hex 00000F00
|
||||
hex 0000F000
|
||||
hex 000F0000
|
||||
hex 00F00000
|
||||
hex 0F000FF0
|
||||
|
||||
s_Amper hex 000FF000
|
||||
hex 00F00F00
|
||||
hex 0F00F000
|
||||
hex 00F000F0
|
||||
hex 0F0FFF00
|
||||
hex 00F0F000
|
||||
|
||||
s_Single hex 000FF000
|
||||
hex 0000F000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
|
||||
s_OpenParen hex 000FF000
|
||||
hex 00FF0000
|
||||
hex 0FF00000
|
||||
hex 0FF00000
|
||||
hex 00FF0000
|
||||
hex 000FF000
|
||||
|
||||
s_CloseParen hex 000FF000
|
||||
hex 0000FF00
|
||||
hex 00000FF0
|
||||
hex 00000FF0
|
||||
hex 0000FF00
|
||||
hex 000FF000
|
||||
|
||||
|
||||
s_Asterix hex 00000000
|
||||
hex 00F0F0F0
|
||||
hex 000FFF00
|
||||
hex 00FFFFF0
|
||||
hex 000FFF00
|
||||
hex 00F0F0F0
|
||||
|
||||
s_Plus hex 000F0000
|
||||
hex 000F0000
|
||||
hex 0FFFFF00
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 00000000
|
||||
|
||||
s_Comma hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 0000FF00
|
||||
hex 0000F000
|
||||
|
||||
s_Minus hex 00000000
|
||||
hex 00000000
|
||||
hex 0FFFFF00
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
|
||||
|
||||
s_Period hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 0000FF00
|
||||
hex 0000FF00
|
||||
|
||||
s_Slash hex 000000F0
|
||||
hex 00000F00
|
||||
hex 0000F000
|
||||
hex 000F0000
|
||||
hex 00F00000
|
||||
hex 0F000000
|
||||
|
||||
s_N0 hex 00FFFF00
|
||||
hex 0F000FF0
|
||||
hex 0F00F0F0
|
||||
hex 0F0F00F0
|
||||
hex 0FF000F0
|
||||
hex 00FFFF00
|
||||
|
||||
s_N1 hex 000F0000
|
||||
hex 00FF0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 00FFF000
|
||||
|
||||
s_N2 hex 00FFFF00
|
||||
hex 0F0000F0
|
||||
hex 00000F00
|
||||
hex 000FF000
|
||||
hex 00F00000
|
||||
hex 0FFFFFF0
|
||||
|
||||
s_N3 hex 00FFFF00
|
||||
hex 000000F0
|
||||
hex 000FFF00
|
||||
hex 000000F0
|
||||
hex 000000F0
|
||||
hex 00FFFF00
|
||||
|
||||
s_N4 hex 0000FF00
|
||||
hex 000F0F00
|
||||
hex 00F00F00
|
||||
hex 0FFFFFF0
|
||||
hex 00000F00
|
||||
hex 00000F00
|
||||
|
||||
s_N5 hex 0FFFFFF0
|
||||
hex 0F000000
|
||||
hex 0FFFFF00
|
||||
hex 000000F0
|
||||
hex 0F0000F0
|
||||
hex 00FFFF00
|
||||
|
||||
s_N6 hex 000FFF00
|
||||
hex 00F00000
|
||||
hex 0F000000
|
||||
hex 0FFFFF00
|
||||
hex 0F0000F0
|
||||
hex 00FFFFF0
|
||||
|
||||
s_N7 hex 0FFFFFF0
|
||||
hex 000000F0
|
||||
hex 00000F00
|
||||
hex 0000F000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
|
||||
s_N8 hex 00FFFF00
|
||||
hex 0F0000F0
|
||||
hex 00FFFF00
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 00FFFF00
|
||||
|
||||
s_N9 hex 00FFFF00
|
||||
hex 0F0000F0
|
||||
hex 00FFFF00
|
||||
hex 0000F000
|
||||
hex 000F0000
|
||||
hex 00F00000
|
||||
|
||||
s_Colon hex 000FF000
|
||||
hex 000FF000
|
||||
hex 00000000
|
||||
hex 000FF000
|
||||
hex 000FF000
|
||||
hex 00000000
|
||||
|
||||
s_Semi hex 00000000
|
||||
hex 000FF000
|
||||
hex 000FF000
|
||||
hex 00000000
|
||||
hex 000FF000
|
||||
hex 000F0000
|
||||
|
||||
s_LAngle hex 0000F000
|
||||
hex 000F0000
|
||||
hex 00F00000
|
||||
hex 000F0000
|
||||
hex 0000F000
|
||||
hex 00000000
|
||||
|
||||
s_Equal hex 00000000
|
||||
hex 00000000
|
||||
hex 0FFFFF00
|
||||
hex 00000000
|
||||
hex 0FFFFF00
|
||||
hex 00000000
|
||||
|
||||
s_RAngle hex 0000F000
|
||||
hex 00000F00
|
||||
hex 000000F0
|
||||
hex 00000F00
|
||||
hex 0000F000
|
||||
hex 00000000
|
||||
|
||||
s_Question hex 00FFF000
|
||||
hex 0F000F00
|
||||
hex 00000F00
|
||||
hex 000FF000
|
||||
hex 00000000
|
||||
hex 000FF000
|
||||
|
||||
s_At hex 00FFFF00
|
||||
hex 0F0000F0
|
||||
hex 0F00F0F0
|
||||
hex 0FFFF0F0
|
||||
hex 000000F0
|
||||
hex 0FFFFF00
|
||||
|
||||
s_A hex 000FF000
|
||||
hex 00F00F00
|
||||
hex 0F0000F0
|
||||
hex 0FFFFFF0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
|
||||
s_B hex 0FFFFF00
|
||||
hex 0F0000F0
|
||||
hex 0FFFFF00
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0FFFFF00
|
||||
|
||||
s_C hex 00FFFFF0
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 00FFFFF0
|
||||
|
||||
s_D hex 0FFFFF00
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0FFFFF00
|
||||
|
||||
s_E hex 0FFFFFF0
|
||||
hex 0F000000
|
||||
hex 0FFFF000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0FFFFFF0
|
||||
|
||||
s_F hex 0FFFFFF0
|
||||
hex 0F000000
|
||||
hex 0FFFF000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
|
||||
s_G hex 00FFFFF0
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0F00FFF0
|
||||
hex 0F0000F0
|
||||
hex 00FFFF00
|
||||
|
||||
s_H hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0FFFFFF0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
|
||||
s_I hex 0FFFFF00
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 0FFFFF00
|
||||
|
||||
s_J hex 000000F0
|
||||
hex 000000F0
|
||||
hex 000000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 00FFFF00
|
||||
|
||||
s_K hex 0F000F00
|
||||
hex 0F00F000
|
||||
hex 0FFF0000
|
||||
hex 0F00F000
|
||||
hex 0F000F00
|
||||
hex 0F000F00
|
||||
|
||||
s_L hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0FFFFFF0
|
||||
|
||||
s_M hex 0F0000F0
|
||||
hex 0FF00FF0
|
||||
hex 0F0FF0F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
|
||||
s_N hex 0F0000F0
|
||||
hex 0FF000F0
|
||||
hex 0F0F00F0
|
||||
hex 0F00F0F0
|
||||
hex 0F000FF0
|
||||
hex 0F0000F0
|
||||
|
||||
s_O hex 00FFFF00
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 00FFFF00
|
||||
|
||||
s_P hex 0FFFFF00
|
||||
hex 0F0000F0
|
||||
hex 0FFFFF00
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
hex 0F000000
|
||||
|
||||
s_Q hex 00FFFF00
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F00F0F0
|
||||
hex 0F000FF0
|
||||
hex 00FFFFF0
|
||||
|
||||
s_R hex 0FFFFF00
|
||||
hex 0F0000F0
|
||||
hex 0FFFFF00
|
||||
hex 0F000F00
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
|
||||
s_S hex 00FFFFF0
|
||||
hex 0F000000
|
||||
hex 00FFFF00
|
||||
hex 000000F0
|
||||
hex 000000F0
|
||||
hex 0FFFFF00
|
||||
|
||||
s_T hex 0FFFFF00
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
|
||||
s_U hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 00FFFF00
|
||||
|
||||
s_V hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 00F00F00
|
||||
hex 000FF000
|
||||
|
||||
s_W hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0000F0
|
||||
hex 0F0FF0F0
|
||||
hex 0FF00FF0
|
||||
hex 0F0000F0
|
||||
|
||||
s_X hex 0F0000F0
|
||||
hex 00F00F00
|
||||
hex 000FF000
|
||||
hex 000FF000
|
||||
hex 00F00F00
|
||||
hex 0F0000F0
|
||||
|
||||
s_Y hex F00000F0
|
||||
hex 0F000F00
|
||||
hex 00F0F000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
|
||||
s_Z hex 0FFFFFF0
|
||||
hex 00000F00
|
||||
hex 0000F000
|
||||
hex 000F0000
|
||||
hex 00F00000
|
||||
hex 0FFFFFF0
|
||||
|
||||
s_LBracket hex 000FFF00
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000F0000
|
||||
hex 000FFF00
|
||||
|
||||
s_BackSlash hex 0F000000
|
||||
hex 00F00000
|
||||
hex 000F0000
|
||||
hex 0000F000
|
||||
hex 00000F00
|
||||
hex 000000F0
|
||||
|
||||
s_RBracket hex 00FFF000
|
||||
hex 0000F000
|
||||
hex 0000F000
|
||||
hex 0000F000
|
||||
hex 0000F000
|
||||
hex 00FFF000
|
||||
|
||||
s_Carot hex 0000F000
|
||||
hex 000F0F00
|
||||
hex 00F000F0
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
|
||||
s_UnderLine hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex FFFFFFF0
|
||||
|
||||
s_Template hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "gte-toolbox-demo",
|
||||
"version": "1.0.0",
|
||||
"description": "A testbed for developing a toolbox wrapper around the GTE library",
|
||||
"main": "index.js",
|
||||
"config": {
|
||||
"merlin32": "C:\\Programs\\IIgsXDev\\bin\\Merlin32-1.1.10.exe",
|
||||
"cadius": "C:\\Programs\\IIgsXDev\\bin\\Cadius.exe",
|
||||
"gsport": "C:\\Programs\\gsport\\gsport_0.31\\GSPort.exe",
|
||||
"macros": "../../macros",
|
||||
"crossrunner": "C:\\Programs\\Crossrunner\\Crossrunner.exe"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run build && build-image.bat %npm_package_config_cadius% && %npm_package_config_gsport%",
|
||||
"debug": "%npm_package_config_crossrunner% GTEToolDemo -Source MAINSEG_Output.txt -Debug -CompatibilityLayer -Map App.s",
|
||||
"build": "npm run build:tool && npm run build:sys16",
|
||||
"build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
|
||||
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../src/Master.s"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lscharen/iigs-game-engine.git"
|
||||
},
|
||||
"author": "Lucas Scharenbroich",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/lscharen/iigs-game-engine/issues"
|
||||
},
|
||||
"homepage": "https://github.com/lscharen/iigs-game-engine#readme",
|
||||
"devDependencies": {
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
GTEZelda
|
|
@ -69,9 +69,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"nan": {
|
||||
|
|
|
@ -325,3 +325,57 @@ transparent
|
|||
sta: ]3+1,y
|
||||
next
|
||||
eom
|
||||
|
||||
; Large code blocks that can be used in sprite blitters
|
||||
; ]1: line number
|
||||
OneSpriteToCodeField mac
|
||||
lda blttmp+{]1*4}
|
||||
andl spritemask+{]1*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]1*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]1*$1000},y
|
||||
|
||||
lda blttmp+{]1*4}+2
|
||||
andl spritemask+{]1*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]1*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]1*$1000},y
|
||||
eom
|
||||
|
||||
TwoSpritesToCodeField mac
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}
|
||||
lda blttmp+{]1*4}
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0004+{]1*$1000},x
|
||||
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}+2
|
||||
lda blttmp+{]1*4}+2
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0001+{]1*$1000},x
|
||||
eom
|
||||
|
||||
ThreeSpritesToCodeField mac
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}
|
||||
lda blttmp+{]1*4}
|
||||
andl [spritemask_2],y
|
||||
oral [spritedata_2],y
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0004+{]1*$1000},x
|
||||
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}+2
|
||||
lda blttmp+{]1*4}+2
|
||||
andl [spritemask_2],y
|
||||
oral [spritedata_2],y
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0001+{]1*$1000},x
|
||||
eom
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
* Generic Tile Engine Macros
|
||||
* by Lucas Scharenbroich
|
||||
|
||||
GTEToolNum equ $A0
|
||||
|
||||
_GTEBootInit MAC
|
||||
UserTool $0100+GTEToolNum
|
||||
<<<
|
||||
_GTEStartUp MAC
|
||||
UserTool $0200+GTEToolNum
|
||||
<<<
|
||||
_GTEShutDown MAC
|
||||
UserTool $0300+GTEToolNum
|
||||
<<<
|
||||
_GTEVersion MAC
|
||||
UserTool $0400+GTEToolNum
|
||||
<<<
|
||||
_GTEReset MAC
|
||||
UserTool $0500+GTEToolNum
|
||||
<<<
|
||||
_GTEStatus MAC
|
||||
UserTool $0600+GTEToolNum
|
||||
<<<
|
||||
_GTEReadControl MAC
|
||||
UserTool $0900+GTEToolNum
|
||||
<<<
|
||||
_GTESetScreenMode MAC
|
||||
UserTool $0A00+GTEToolNum
|
||||
<<<
|
||||
_GTESetTile MAC
|
||||
UserTool $0B00+GTEToolNum
|
||||
<<<
|
||||
_GTESetBG0Origin MAC
|
||||
UserTool $0C00+GTEToolNum
|
||||
<<<
|
||||
_GTERender MAC
|
||||
UserTool $0D00+GTEToolNum
|
||||
<<<
|
||||
_GTELoadTileSet MAC
|
||||
UserTool $0E00+GTEToolNum
|
||||
<<<
|
||||
_GTECreateSpriteStamp MAC
|
||||
UserTool $0F00+GTEToolNum
|
||||
<<<
|
||||
_GTEAddSprite MAC
|
||||
UserTool $1000+GTEToolNum
|
||||
<<<
|
||||
_GTEMoveSprite MAC
|
||||
UserTool $1100+GTEToolNum
|
||||
<<<
|
||||
_GTEUpdateSprite MAC
|
||||
UserTool $1200+GTEToolNum
|
||||
<<<
|
||||
_GTERemoveSprite MAC
|
||||
UserTool $1300+GTEToolNum
|
||||
<<<
|
||||
_GTEGetSeconds MAC
|
||||
UserTool $1400+GTEToolNum
|
||||
<<<
|
||||
_GTECopyTileToDynamic MAC
|
||||
UserTool $1500+GTEToolNum
|
||||
<<<
|
||||
_GTESetPalette MAC
|
||||
UserTool $1600+GTEToolNum
|
||||
<<<
|
||||
_GTECopyPicToBG1 MAC
|
||||
UserTool $1700+GTEToolNum
|
||||
<<<
|
||||
_GTEBindSCBArray MAC
|
||||
UserTool $1800+GTEToolNum
|
||||
<<<
|
||||
_GTEGetBG0TileMapInfo MAC
|
||||
UserTool $1900+GTEToolNum
|
||||
<<<
|
||||
_GTEGetScreenInfo MAC
|
||||
UserTool $1A00+GTEToolNum
|
||||
<<<
|
||||
_GTESetBG1Origin MAC
|
||||
UserTool $1B00+GTEToolNum
|
||||
<<<
|
||||
_GTEGetTileAt MAC
|
||||
UserTool $1C00+GTEToolNum
|
||||
<<<
|
||||
_GTESetBG0TileMapInfo MAC
|
||||
UserTool $1D00+GTEToolNum
|
||||
<<<
|
||||
_GTESetBG1TileMapInfo MAC
|
||||
UserTool $1E00+GTEToolNum
|
||||
<<<
|
||||
_GTEAddTimer MAC
|
||||
UserTool $1F00+GTEToolNum
|
||||
<<<
|
||||
_GTERemoveTimer MAC
|
||||
UserTool $2000+GTEToolNum
|
||||
<<<
|
||||
_GTEStartScript MAC
|
||||
UserTool $2100+GTEToolNum
|
||||
<<<
|
||||
_GTESetOverlay MAC
|
||||
UserTool $2200+GTEToolNum
|
||||
<<<
|
||||
_GTEClearOverlay MAC
|
||||
UserTool $2300+GTEToolNum
|
||||
<<<
|
||||
_GTEGetTileDataAddr MAC
|
||||
UserTool $2400+GTEToolNum
|
||||
<<<
|
||||
_GTEFillTileStore MAC
|
||||
UserTool $2500+GTEToolNum
|
||||
<<<
|
||||
_GTERefresh MAC
|
||||
UserTool $2600+GTEToolNum
|
||||
<<<
|
||||
|
||||
; EngineMode definitions
|
||||
; Script definition
|
||||
YIELD equ $8000
|
||||
JUMP equ $4000
|
||||
|
||||
SET_PALETTE_ENTRY equ $0002
|
||||
SWAP_PALETTE_ENTRY equ $0004
|
||||
SET_DYN_TILE equ $0006
|
||||
CALLBACK equ $0010
|
||||
|
||||
; ReadControl return value bits
|
||||
PAD_BUTTON_B equ $01
|
||||
PAD_BUTTON_A equ $02
|
||||
PAD_KEY_DOWN equ $04
|
||||
ENGINE_MODE_TWO_LAYER equ $0001
|
||||
ENGINE_MODE_DYN_TILES equ $0002
|
||||
ENGINE_MODE_BNK0_BUFF equ $0004
|
||||
|
||||
; Tile constants
|
||||
; TILE_RESERVED_BIT equ $8000
|
||||
TILE_PRIORITY_BIT equ $4000 ; Put tile on top of sprite
|
||||
TILE_FRINGE_BIT equ $2000 ; Unused
|
||||
TILE_SOLID_BIT equ $1000 ; Hint bit used in TWO_LAYER_MODE to optimize rendering
|
||||
TILE_DYN_BIT equ $0800 ; Is this a Dynamic Tile?
|
||||
TILE_VFLIP_BIT equ $0400
|
||||
TILE_HFLIP_BIT equ $0200
|
||||
TILE_ID_MASK equ $01FF
|
||||
TILE_CTRL_MASK equ $FE00
|
||||
|
||||
|
||||
; Sprite constants
|
||||
SPRITE_HIDE equ $2000
|
||||
SPRITE_16X16 equ $1800
|
||||
SPRITE_16X8 equ $1000
|
||||
SPRITE_8X16 equ $0800
|
||||
SPRITE_8X8 equ $0000
|
||||
SPRITE_VFLIP equ $0400
|
||||
SPRITE_HFLIP equ $0200
|
||||
|
||||
; Stamp storage parameters
|
||||
VBUFF_STRIDE_BYTES equ {12*4} ; Each line has 4 slots of 16 pixels + 8 buffer pixels
|
||||
VBUFF_TILE_ROW_BYTES equ {8*VBUFF_STRIDE_BYTES} ; Each row is comprised of 8 lines
|
||||
VBUFF_TILE_COL_BYTES equ 4
|
||||
VBUFF_SPRITE_STEP equ {VBUFF_TILE_ROW_BYTES*3} ; Allocate space for 16 rows + 8 rows of buffer
|
||||
VBUFF_SPRITE_START equ {VBUFF_TILE_ROW_BYTES+4} ; Start at an offset so $0000 can be used as an empty value
|
||||
VBUFF_SLOT_COUNT equ 48 ; Have space for this many stamps
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "generic-tile-engine",
|
||||
"version": "1.0.0",
|
||||
"description": "A tile-base game engine for the Apple IIgs",
|
||||
"main": "index.js",
|
||||
"config": {
|
||||
"merlin32": "C:\\Programs\\IIgsXDev\\bin\\Merlin32-1.1.10.exe",
|
||||
"cadius": "C:\\Programs\\IIgsXDev\\bin\\Cadius.exe",
|
||||
"gsport": "C:\\Programs\\gsport\\gsport_0.31\\GSPort.exe",
|
||||
"macros": "./macros",
|
||||
"crossrunner": "C:\\Programs\\Crossrunner\\Crossrunner.exe"
|
||||
},
|
||||
"scripts": {
|
||||
"archive": "%npm_package_config_cadius% EXTRACTFILE ./emu/Target.2mg /GTEDev/Tool160.SHK .",
|
||||
"test": "npm run build && build-image.bat %npm_package_config_cadius% && %npm_package_config_gsport%",
|
||||
"build": "%npm_package_config_merlin32% -V %npm_package_config_macros% ./src/Master.s",
|
||||
"build:debug": "%npm_package_config_merlin32% -V %npm_package_config_macros% ./src/Debug.s",
|
||||
"debug": "%npm_package_config_crossrunner% ./src/Debug160 -Source ./src/Debug160_S02__Output.txt -Debug -CompatibilityLayer"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lscharen/iigs-game-engine.git"
|
||||
},
|
||||
"author": "Lucas Scharenbroich",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/lscharen/iigs-game-engine/issues"
|
||||
},
|
||||
"homepage": "https://github.com/lscharen/iigs-game-engine#readme",
|
||||
"devDependencies": {
|
||||
}
|
||||
}
|
407
src/Core.s
407
src/Core.s
|
@ -8,94 +8,6 @@
|
|||
|
||||
use .\Defs.s
|
||||
|
||||
; Feature flags
|
||||
NO_INTERRUPTS equ 1 ; turn off for crossrunner debugging
|
||||
NO_MUSIC equ 1 ; turn music + tool loading off
|
||||
|
||||
; 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
|
||||
Overlay EXT
|
||||
|
||||
; Core engine functionality. The idea is that that source file can be PUT into
|
||||
; a main source file and all of the functionality will be available.
|
||||
;
|
||||
; There are some constancts that must be externally defined that can affect how
|
||||
; the GTE runtime works
|
||||
;
|
||||
; NO_MUSIC : Set to non-zero to avoid using any source
|
||||
; NO_INTERRUPTS : Set to non-zero to avoid installing custom interrupt handlers
|
||||
|
||||
mx %00
|
||||
|
||||
; High-Level StartUp and ShutDown functions
|
||||
EngineStartUp ENT
|
||||
phb
|
||||
phk
|
||||
|
@ -103,41 +15,23 @@ EngineStartUp ENT
|
|||
|
||||
jsr ToolStartUp ; Start up the toolbox tools we rely on
|
||||
jsr _CoreStartUp
|
||||
jsr SoundStartUp ; Start up any sound/music tools
|
||||
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CoreStartUp
|
||||
jsr SoundStartUp ; Start up any sound/music tools
|
||||
jsr IntStartUp ; Enable certain iterrupts
|
||||
|
||||
jsr InitMemory ; Allocate and initialize memory for the engine
|
||||
jsr EngineReset ; All of the resources are allocated, put the engine in a known state
|
||||
|
||||
jsr InitGraphics ; Initialize all of the graphics-related data
|
||||
nop
|
||||
jsr InitSprites ; Initialize the sprite subsystem
|
||||
jsr InitTiles ; Initialize the tile subsystem
|
||||
|
||||
jsr InitTimers ; Initialize the timer subsystem
|
||||
rts
|
||||
|
||||
EngineShutDown ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
|
||||
jsr SoundShutDown
|
||||
jsr _CoreShutDown
|
||||
jsr ToolShutDown
|
||||
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CoreShutDown
|
||||
jsr IntShutDown
|
||||
jsr SoundShutDown
|
||||
rts
|
||||
|
||||
ToolStartUp
|
||||
_TLStartUp ; normal tool initialization
|
||||
pha
|
||||
|
@ -152,7 +46,6 @@ ToolStartUp
|
|||
rts
|
||||
|
||||
MasterId ds 2
|
||||
UserId ds 2
|
||||
|
||||
; Fatal error handler invoked by the _Err macro
|
||||
PgmDeath tax
|
||||
|
@ -168,9 +61,6 @@ PgmDeath0 pha
|
|||
ContDeath ldx #$1503
|
||||
jsl $E10000
|
||||
|
||||
ToolShutDown
|
||||
rts
|
||||
|
||||
; Use Tool222 (NinjaTrackerPlus) for music playback
|
||||
SoundStartUp
|
||||
lda #NO_MUSIC
|
||||
|
@ -194,299 +84,10 @@ SoundShutDown
|
|||
:no_music
|
||||
rts
|
||||
|
||||
; Install interrupt handlers. We use the VBL interrupt to keep animations
|
||||
; moving at a consistent rate, regarless of the rendered frame rate. The
|
||||
; one-second timer is generally just used for counters and as a handy
|
||||
; frames-per-second trigger.
|
||||
IntStartUp
|
||||
lda #NO_INTERRUPTS
|
||||
bne :no_interrupts
|
||||
PushLong #0
|
||||
pea $0015 ; Get the existing 1-second interrupt handler and save
|
||||
_GetVector
|
||||
PullLong OldOneSecVec
|
||||
|
||||
pea $0015 ; Set the new handler and enable interrupts
|
||||
PushLong #OneSecHandler
|
||||
_SetVector
|
||||
|
||||
pea $0006
|
||||
_IntSource
|
||||
|
||||
PushLong #VBLTASK ; Also register a Heart Beat Task
|
||||
_SetHeartBeat
|
||||
|
||||
:no_interrupts
|
||||
rts
|
||||
|
||||
IntShutDown
|
||||
lda #NO_INTERRUPTS
|
||||
bne :no_interrupts
|
||||
|
||||
pea $0007 ; disable 1-second interrupts
|
||||
_IntSource
|
||||
|
||||
PushLong #VBLTASK ; Remove our heartbeat task
|
||||
_DelHeartBeat
|
||||
|
||||
pea $0015
|
||||
PushLong OldOneSecVec ; Reset the interrupt vector
|
||||
_SetVector
|
||||
|
||||
:no_interrupts
|
||||
rts
|
||||
|
||||
|
||||
; Interrupt handlers. We install a heartbeat (1/60th second and a 1-second timer)
|
||||
OneSecHandler mx %11
|
||||
phb
|
||||
pha
|
||||
phk
|
||||
plb
|
||||
|
||||
rep #$20
|
||||
inc OneSecondCounter
|
||||
sep #$20
|
||||
|
||||
ldal $E0C032
|
||||
and #%10111111 ;clear IRQ source
|
||||
stal $E0C032
|
||||
|
||||
pla
|
||||
plb
|
||||
clc
|
||||
rtl
|
||||
mx %00
|
||||
|
||||
OneSecondCounter ENT
|
||||
dw 0
|
||||
OldOneSecVec ds 4
|
||||
|
||||
VBLTASK hex 00000000
|
||||
dw 0
|
||||
hex 5AA5
|
||||
|
||||
; Reset the engine to a known state
|
||||
; Blitter initialization
|
||||
EngineReset
|
||||
stz ScreenHeight
|
||||
stz ScreenWidth
|
||||
stz ScreenY0
|
||||
stz ScreenY1
|
||||
stz ScreenX0
|
||||
stz ScreenX1
|
||||
stz ScreenTileHeight
|
||||
stz ScreenTileWidth
|
||||
stz StartX
|
||||
stz OldStartX
|
||||
stz StartXMod164
|
||||
|
||||
stz StartY
|
||||
stz OldStartY
|
||||
stz StartYMod208
|
||||
|
||||
stz EngineMode
|
||||
stz DirtyBits
|
||||
stz LastRender
|
||||
stz LastPatchOffset
|
||||
stz BG1StartX
|
||||
stz BG1StartXMod164
|
||||
stz BG1StartY
|
||||
stz BG1StartYMod208
|
||||
stz BG1OffsetIndex
|
||||
|
||||
stz BG0TileOriginX
|
||||
stz BG0TileOriginY
|
||||
stz OldBG0TileOriginX
|
||||
stz OldBG0TileOriginY
|
||||
|
||||
stz BG1TileOriginX
|
||||
stz BG1TileOriginY
|
||||
stz OldBG1TileOriginX
|
||||
stz OldBG1TileOriginY
|
||||
|
||||
stz TileMapWidth
|
||||
stz TileMapHeight
|
||||
stz TileMapPtr
|
||||
stz TileMapPtr+2
|
||||
stz FringeMapPtr
|
||||
stz FringeMapPtr+2
|
||||
|
||||
stz BG1TileMapWidth
|
||||
stz BG1TileMapHeight
|
||||
stz BG1TileMapPtr
|
||||
stz BG1TileMapPtr+2
|
||||
|
||||
stz SCBArrayPtr
|
||||
stz SCBArrayPtr+2
|
||||
|
||||
stz SpriteBanks
|
||||
stz SpriteMap
|
||||
stz ActiveSpriteCount
|
||||
|
||||
stz OneSecondCounter
|
||||
|
||||
lda #13
|
||||
sta tmp15
|
||||
stz tmp14
|
||||
|
||||
:loop
|
||||
ldx #BlitBuff
|
||||
lda #^BlitBuff
|
||||
ldy tmp14
|
||||
jsr BuildBank
|
||||
|
||||
lda tmp14
|
||||
clc
|
||||
adc #4
|
||||
sta tmp14
|
||||
|
||||
dec tmp15
|
||||
bne :loop
|
||||
|
||||
rts
|
||||
|
||||
; Allow the user to dynamically select one of the pre-configured screen sizes, or pass
|
||||
; in a specific width and height. The screen is automatically centered. If this is
|
||||
; not desired, then SetScreenRect should be used directly
|
||||
;
|
||||
; 0. Full Screen : 40 x 25 320 x 200 (32,000 bytes (100.0%))
|
||||
; 1. Sword of Sodan : 34 x 24 272 x 192 (26,112 bytes ( 81.6%))
|
||||
; 2. ~NES : 32 x 25 256 x 200 (25,600 bytes ( 80.0%))
|
||||
; 3. Task Force : 32 x 22 256 x 176 (22,528 bytes ( 70.4%))
|
||||
; 4. Defender of the World : 35 x 20 280 x 160 (22,400 bytes ( 70.0%))
|
||||
; 5. Rastan : 32 x 20 256 x 160 (20,480 bytes ( 64.0%))
|
||||
; 6. Game Boy Advanced : 30 x 20 240 x 160 (19,200 bytes ( 60.0%))
|
||||
; 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,288,160,320
|
||||
ScreenModeHeight dw 200,192,200,176,160,160,160,128,144,192,102,1
|
||||
|
||||
SetScreenMode ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _SetScreenMode
|
||||
plb
|
||||
rtl
|
||||
|
||||
_SetScreenMode
|
||||
cpx #11
|
||||
bcs :direct ; if x > 10, then assume X and Y are the dimensions
|
||||
|
||||
txa
|
||||
asl
|
||||
tax
|
||||
|
||||
ldy ScreenModeHeight,x
|
||||
lda ScreenModeWidth,x
|
||||
tax
|
||||
|
||||
:direct cpy #201
|
||||
bcs :exit
|
||||
|
||||
cpx #321
|
||||
bcs :exit
|
||||
|
||||
txa
|
||||
lsr
|
||||
pha ; Save X (width / 2) and Y (height)
|
||||
phy
|
||||
|
||||
lda #160 ; Center the screen
|
||||
sec
|
||||
sbc 3,s
|
||||
lsr
|
||||
xba
|
||||
pha ; Save half the origin coordinate
|
||||
|
||||
lda #200
|
||||
sec
|
||||
sbc 3,s ; This is now Y because of the PHA above
|
||||
lsr
|
||||
ora 1,s
|
||||
|
||||
plx ; Throw-away to pop the stack
|
||||
ply
|
||||
plx
|
||||
|
||||
jsr SetScreenRect
|
||||
jmp FillScreen ; tail return
|
||||
:exit
|
||||
rts
|
||||
|
||||
|
||||
WaitForKey sep #$20
|
||||
stal KBD_STROBE_REG ; clear the strobe
|
||||
:WFK ldal KBD_REG
|
||||
bpl :WFK
|
||||
rep #$20
|
||||
and #$007F
|
||||
rts
|
||||
|
||||
ClearKbdStrobe sep #$20
|
||||
stal KBD_STROBE_REG
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; Read the keyboard and paddle controls and return in a game-controller-like format
|
||||
LastKey db 0
|
||||
ReadControl ENT
|
||||
jsr _ReadControl
|
||||
rtl
|
||||
|
||||
_ReadControl
|
||||
pea $0000 ; low byte = key code, high byte = %------AB
|
||||
|
||||
sep #$20
|
||||
ldal OPTION_KEY_REG ; 'B' button
|
||||
and #$80
|
||||
beq :BNotDown
|
||||
|
||||
lda #PAD_BUTTON_B
|
||||
ora 2,s
|
||||
sta 2,s
|
||||
|
||||
:BNotDown
|
||||
ldal COMMAND_KEY_REG
|
||||
and #$80
|
||||
beq :ANotDown
|
||||
|
||||
lda #PAD_BUTTON_A
|
||||
ora 2,s
|
||||
sta 2,s
|
||||
|
||||
:ANotDown
|
||||
ldal KBD_STROBE_REG ; read the keyboard
|
||||
bit #$80
|
||||
beq :KbdNotDwn ; check the key-down status
|
||||
and #$7f
|
||||
ora 1,s
|
||||
sta 1,s
|
||||
|
||||
cmpl LastKey
|
||||
beq :KbdDown
|
||||
stal LastKey
|
||||
|
||||
lda #PAD_KEY_DOWN ; set the keydown flag
|
||||
ora 2,s
|
||||
sta 2,s
|
||||
bra :KbdDown
|
||||
|
||||
:KbdNotDwn
|
||||
lda #0
|
||||
stal LastKey
|
||||
:KbdDown
|
||||
rep #$20
|
||||
pla
|
||||
ToolShutDown
|
||||
rts
|
||||
|
||||
put CoreImpl.s
|
||||
put blitter/Template.s
|
||||
|
||||
put Memory.s
|
||||
|
|
|
@ -0,0 +1,353 @@
|
|||
; Feature flags
|
||||
NO_INTERRUPTS equ 0 ; turn off for crossrunner debugging
|
||||
NO_MUSIC equ 1 ; turn music + tool loading off
|
||||
|
||||
; External data space provided by the main program segment
|
||||
tiledata EXT
|
||||
TileStore EXT
|
||||
|
||||
; Sprite plane data and mask banks are provided as an external 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
|
||||
|
||||
; Core engine functionality. The idea is that that source file can be PUT into
|
||||
; a main source file and all of the functionality will be available.
|
||||
;
|
||||
; There are some constancts that must be externally defined that can affect how
|
||||
; the GTE runtime works
|
||||
;
|
||||
; NO_MUSIC : Set to non-zero to avoid using any source
|
||||
; NO_INTERRUPTS : Set to non-zero to avoid installing custom interrupt handlers
|
||||
|
||||
mx %00
|
||||
|
||||
; Assumes the direct page is set and EngineMode and UserId has been initialized
|
||||
_CoreStartUp
|
||||
jsr IntStartUp ; Enable certain interrupts
|
||||
|
||||
jsr InitMemory ; Allocate and initialize memory for the engine
|
||||
jsr EngineReset ; All of the resources are allocated, put the engine in a known state
|
||||
|
||||
jsr InitGraphics ; Initialize all of the graphics-related data
|
||||
jsr InitSprites ; Initialize the sprite subsystem
|
||||
jsr InitTiles ; Initialize the tile subsystem
|
||||
|
||||
jsr InitTimers ; Initialize the timer subsystem
|
||||
rts
|
||||
|
||||
_CoreShutDown
|
||||
jsr IntShutDown
|
||||
rts
|
||||
|
||||
; Install interrupt handlers. We use the VBL interrupt to keep animations
|
||||
; moving at a consistent rate, regarless of the rendered frame rate. The
|
||||
; one-second timer is generally just used for counters and as a handy
|
||||
; frames-per-second trigger.
|
||||
IntStartUp
|
||||
lda #NO_INTERRUPTS
|
||||
bne :no_interrupts
|
||||
PushLong #0
|
||||
pea $0015 ; Get the existing 1-second interrupt handler and save
|
||||
_GetVector
|
||||
PullLong OldOneSecVec
|
||||
|
||||
pea $0015 ; Set the new handler and enable interrupts
|
||||
PushLong #OneSecHandler
|
||||
_SetVector
|
||||
|
||||
pea $0006
|
||||
_IntSource
|
||||
|
||||
PushLong #VBLTASK ; Also register a Heart Beat Task
|
||||
_SetHeartBeat
|
||||
|
||||
:no_interrupts
|
||||
rts
|
||||
|
||||
IntShutDown
|
||||
lda #NO_INTERRUPTS
|
||||
bne :no_interrupts
|
||||
|
||||
pea $0007 ; disable 1-second interrupts
|
||||
_IntSource
|
||||
|
||||
PushLong #VBLTASK ; Remove our heartbeat task
|
||||
_DelHeartBeat
|
||||
|
||||
pea $0015
|
||||
PushLong OldOneSecVec ; Reset the interrupt vector
|
||||
_SetVector
|
||||
|
||||
:no_interrupts
|
||||
rts
|
||||
|
||||
|
||||
; Interrupt handlers. We install a heartbeat (1/60th second and a 1-second timer)
|
||||
OneSecHandler mx %11
|
||||
phb
|
||||
pha
|
||||
|
||||
jsr _SetDataBank
|
||||
|
||||
rep #$20
|
||||
inc OneSecondCounter
|
||||
sep #$20
|
||||
|
||||
ldal $E0C032
|
||||
and #%10111111 ;clear IRQ source
|
||||
stal $E0C032
|
||||
|
||||
pla
|
||||
plb
|
||||
clc
|
||||
rtl
|
||||
mx %00
|
||||
|
||||
; This is OK, it's referenced by a long address
|
||||
VBLTASK hex 00000000
|
||||
dw 0
|
||||
hex 5AA5
|
||||
|
||||
; Reset the engine to a known state
|
||||
; Blitter initialization
|
||||
EngineReset
|
||||
stz ScreenHeight
|
||||
stz ScreenWidth
|
||||
stz ScreenY0
|
||||
stz ScreenY1
|
||||
stz ScreenX0
|
||||
stz ScreenX1
|
||||
stz ScreenTileHeight
|
||||
stz ScreenTileWidth
|
||||
stz StartX
|
||||
stz OldStartX
|
||||
stz StartXMod164
|
||||
|
||||
stz StartY
|
||||
stz OldStartY
|
||||
stz StartYMod208
|
||||
|
||||
; stz EngineMode
|
||||
stz DirtyBits
|
||||
stz LastRender
|
||||
stz LastPatchOffset
|
||||
stz BG1StartX
|
||||
stz BG1StartXMod164
|
||||
stz BG1StartY
|
||||
stz BG1StartYMod208
|
||||
stz BG1OffsetIndex
|
||||
|
||||
stz BG0TileOriginX
|
||||
stz BG0TileOriginY
|
||||
stz OldBG0TileOriginX
|
||||
stz OldBG0TileOriginY
|
||||
|
||||
stz BG1TileOriginX
|
||||
stz BG1TileOriginY
|
||||
stz OldBG1TileOriginX
|
||||
stz OldBG1TileOriginY
|
||||
|
||||
stz TileMapWidth
|
||||
stz TileMapHeight
|
||||
stz TileMapPtr
|
||||
stz TileMapPtr+2
|
||||
stz FringeMapPtr
|
||||
stz FringeMapPtr+2
|
||||
|
||||
stz BG1TileMapWidth
|
||||
stz BG1TileMapHeight
|
||||
stz BG1TileMapPtr
|
||||
stz BG1TileMapPtr+2
|
||||
|
||||
stz SCBArrayPtr
|
||||
stz SCBArrayPtr+2
|
||||
|
||||
stz SpriteBanks
|
||||
stz SpriteMap
|
||||
stz ActiveSpriteCount
|
||||
|
||||
stz OneSecondCounter
|
||||
|
||||
lda #13
|
||||
sta tmp15
|
||||
stz tmp14
|
||||
|
||||
:loop
|
||||
ldx #BlitBuff
|
||||
lda #^BlitBuff
|
||||
ldy tmp14
|
||||
jsr BuildBank
|
||||
|
||||
lda tmp14
|
||||
clc
|
||||
adc #4
|
||||
sta tmp14
|
||||
|
||||
dec tmp15
|
||||
bne :loop
|
||||
|
||||
rts
|
||||
|
||||
|
||||
WaitForKey sep #$20
|
||||
stal KBD_STROBE_REG ; clear the strobe
|
||||
:WFK ldal KBD_REG
|
||||
bpl :WFK
|
||||
rep #$20
|
||||
and #$007F
|
||||
rts
|
||||
|
||||
ClearKbdStrobe sep #$20
|
||||
stal KBD_STROBE_REG
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; Read the keyboard and paddle controls and return in a game-controller-like format
|
||||
_ReadControl pea $0000 ; low byte = key code, high byte = %------AB
|
||||
|
||||
sep #$20
|
||||
ldal OPTION_KEY_REG ; 'B' button
|
||||
and #$80
|
||||
beq :BNotDown
|
||||
|
||||
lda #PAD_BUTTON_B
|
||||
ora 2,s
|
||||
sta 2,s
|
||||
|
||||
:BNotDown
|
||||
ldal COMMAND_KEY_REG
|
||||
and #$80
|
||||
beq :ANotDown
|
||||
|
||||
lda #PAD_BUTTON_A
|
||||
ora 2,s
|
||||
sta 2,s
|
||||
|
||||
:ANotDown
|
||||
ldal KBD_STROBE_REG ; read the keyboard
|
||||
bit #$80
|
||||
beq :KbdNotDwn ; check the key-down status
|
||||
and #$7f
|
||||
ora 1,s
|
||||
sta 1,s
|
||||
|
||||
cmp LastKey
|
||||
beq :KbdDown
|
||||
sta LastKey
|
||||
|
||||
lda #PAD_KEY_DOWN ; set the keydown flag
|
||||
ora 2,s
|
||||
sta 2,s
|
||||
bra :KbdDown
|
||||
|
||||
:KbdNotDwn
|
||||
stz LastKey
|
||||
:KbdDown
|
||||
rep #$20
|
||||
pla
|
||||
rts
|
||||
|
||||
|
||||
; Helper function to take a local pixel coordinate [0, ScreenWidth-1],[0, ScreenHeight-1] and return the
|
||||
; row and column in the tile store that is corresponds to. This takes into consideration the StartX and
|
||||
; StartY offsets.
|
||||
;
|
||||
; This is more specialized than the code in the _MarkDirtySprite routine below since it does not deal with
|
||||
; negative or off-screen values.
|
||||
_OriginToTileStore
|
||||
lda StartYMod208
|
||||
lsr
|
||||
lsr
|
||||
and #$FFFE ; Store the pre-multiplied by 2 for indexing
|
||||
tay
|
||||
lda StartXMod164
|
||||
lsr
|
||||
and #$FFFE ; Same pre-multiply by 2 for later
|
||||
tax
|
||||
rts
|
||||
|
||||
; X = local x-coordinate (0, playfield width)
|
||||
; Y = local y-coordinate (0, playfield height)
|
||||
_LocalToTileStore
|
||||
clc
|
||||
tya
|
||||
adc StartYMod208 ; Adjust for the scroll offset
|
||||
cmp #208 ; check if we went too far positive
|
||||
bcc *+5
|
||||
sbc #208
|
||||
lsr
|
||||
lsr
|
||||
and #$FFFE ; Store the pre-multiplied by 2 for indexing
|
||||
tay
|
||||
|
||||
clc
|
||||
txa
|
||||
adc StartXMod164
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
lsr
|
||||
and #$FFFE ; Same pre-multiply by 2 for later
|
||||
tax
|
||||
rts
|
135
src/Defs.s
135
src/Defs.s
|
@ -34,6 +34,8 @@ StartX equ 16 ; Which code buffer byte is the left ed
|
|||
StartY equ 18 ; Which code buffer line is the top of the screen. Range = 0 to 207
|
||||
EngineMode equ 20 ; Defined the mode/capabilities that are enabled
|
||||
; bit 0: 0 = Single Background, 1 = Parallax
|
||||
; bit 1: 0 = No Dynamic Tiles, 1 = Allocate Bank 00 space for dynamic tiles
|
||||
; bit 2: 0 = No static buffer, 1 = Allocation Bank 00 space for a static screen buffer
|
||||
DirtyBits equ 22 ; Identify values that have changed between frames
|
||||
|
||||
BG1DataBank equ 24 ; Data bank that holds BG1 layer data
|
||||
|
@ -80,18 +82,25 @@ 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
|
||||
LastRender equ 96 ; Record which render function was last executed
|
||||
; gap
|
||||
SpriteMap equ 100 ; Bitmap of open sprite slots.
|
||||
ActiveSpriteCount equ 102
|
||||
BankLoad equ 104
|
||||
TileStoreBankAndBank01 equ 106
|
||||
TileStoreBankAndTileDataBank equ 108
|
||||
Next equ 110
|
||||
TileStoreBankDoubled equ 110
|
||||
UserId equ 112 ; Memory manager user Id to use
|
||||
ToolNum equ 114 ; Tool number assigned to us
|
||||
LastKey equ 116
|
||||
LastTick equ 118
|
||||
ForceSpriteFlag equ 120
|
||||
SpriteRemovedFlag equ 122 ; Indicate if any sprites were removed this frame
|
||||
|
||||
|
||||
|
||||
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
|
||||
; tiletmp equ 178 ; 16 bytes of temp storage for the tile renderers
|
||||
blttmp equ 192 ; 32 bytes of local cache/scratch space for blitter
|
||||
|
||||
tmp8 equ 224 ; another 16 bytes of temporary space to be used as scratch
|
||||
|
@ -112,6 +121,50 @@ tmp5 equ 250
|
|||
tmp6 equ 252
|
||||
tmp7 equ 254
|
||||
|
||||
; Defines for the second direct page (used in the tile blitters)
|
||||
|
||||
sprite_ptr0 equ 0 ; Each tile can render up to 4 sprite blocks. The sprite
|
||||
sprite_ptr1 equ 4 ; data and mask values live in different banks, but have a
|
||||
sprite_ptr2 equ 8 ; parallel structure. The high word of each point is set to
|
||||
sprite_ptr3 equ 12 ; the mask bank. With the Bank register set, both data and mask
|
||||
; ; can be accessed through the same pointer, e.g. lda (sprite_ptr0)
|
||||
; ; and [sprite_ptr0]
|
||||
|
||||
tmp_sprite_data equ 16 ; 32 byte temporary buffer to build up sprite data values
|
||||
tmp_sprite_mask equ 48 ; 32 byte temporary buffer to build up sprite mask values
|
||||
tmp_tile_data equ 80 ; 32 byte temporary buffer to build up tile data values
|
||||
tmp_tile_mask equ 112 ; 32 byte temporary buffer to build up tile mask values
|
||||
|
||||
; Temporary direct page locations used by some of the complex tile renderers
|
||||
_X_REG equ 144
|
||||
_Y_REG equ 146
|
||||
_T_PTR equ 148 ; Copy of the tile address pointer
|
||||
_OP_CACHE2 equ 148 ; CAche of second opcode
|
||||
_BASE_ADDR equ 150 ; Copy of BTableLow for this tile
|
||||
_SPR_X_REG equ 152 ; Cache address of sprite plane source for a tile
|
||||
_JTBL_CACHE equ 154 ; Cache the offset to the exception handler for a column
|
||||
_OP_CACHE equ 156 ; Cache of a relevant operand / oeprator
|
||||
_TILE_ID equ 158 ; Copy of the tile descriptor
|
||||
|
||||
; Define free space the the application to use
|
||||
; FREE_SPACE_DP2 equ 160
|
||||
DP2_DIRTY_TILE_COUNT equ 160 ; Local copy of dirty tile count to avoid banking
|
||||
DP2_DIRTY_TILE_CALLBACK equ 162
|
||||
|
||||
; Some pre-defined bank values
|
||||
DP2_TILEDATA_AND_TILESTORE_BANKS equ 164
|
||||
DP2_SPRITEDATA_AND_TILESTORE_BANKS equ 166
|
||||
DP2_TILEDATA_AND_SPRITEDATA_BANKS equ 168
|
||||
|
||||
SPRITE_VBUFF_PTR equ 224 ; 32 bytes of adjusted pointers to VBuffArray addresses
|
||||
; End direct page values
|
||||
|
||||
; EngineMode definitions
|
||||
ENGINE_MODE_TWO_LAYER equ $0001
|
||||
ENGINE_MODE_DYN_TILES equ $0002
|
||||
ENGINE_MODE_BNK0_BUFF equ $0004
|
||||
|
||||
; DirtyBits definitions
|
||||
DIRTY_BIT_BG0_X equ $0001
|
||||
DIRTY_BIT_BG0_Y equ $0002
|
||||
DIRTY_BIT_BG1_X equ $0004
|
||||
|
@ -135,14 +188,16 @@ PAD_BUTTON_A equ $02
|
|||
PAD_KEY_DOWN equ $04
|
||||
|
||||
; Tile constants
|
||||
TILE_ID_MASK equ $01FF
|
||||
TILE_SPRITE_BIT equ $8000 ; Set if this tile intersects an active sprite
|
||||
; TILE_RESERVED_BIT equ $8000
|
||||
TILE_PRIORITY_BIT equ $4000 ; Put tile on top of sprite
|
||||
TILE_FRINGE_BIT equ $2000
|
||||
TILE_MASK_BIT equ $1000
|
||||
TILE_DYN_BIT equ $0800
|
||||
TILE_FRINGE_BIT equ $2000 ; Unused
|
||||
TILE_SOLID_BIT equ $1000 ; Hint bit used in TWO_LAYER_MODE to optimize rendering
|
||||
TILE_DYN_BIT equ $0800 ; Is this a Dynamic Tile?
|
||||
TILE_VFLIP_BIT equ $0400
|
||||
TILE_HFLIP_BIT equ $0200
|
||||
TILE_ID_MASK equ $01FF
|
||||
TILE_CTRL_MASK equ $FE00
|
||||
; TILE_PROC_MASK equ $F800 ; Select tile proc for rendering
|
||||
|
||||
; Sprite constants
|
||||
SPRITE_HIDE equ $2000
|
||||
|
@ -153,17 +208,53 @@ SPRITE_8X8 equ $0000
|
|||
SPRITE_VFLIP equ $0400
|
||||
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
|
||||
; Stamp storage parameters
|
||||
VBUFF_STRIDE_BYTES equ {12*4} ; Each line has 4 slots of 16 pixels + 8 buffer pixels
|
||||
VBUFF_TILE_ROW_BYTES equ {8*VBUFF_STRIDE_BYTES} ; Each row is comprised of 8 lines
|
||||
VBUFF_TILE_COL_BYTES equ 4
|
||||
VBUFF_SPRITE_STEP equ {VBUFF_TILE_ROW_BYTES*3} ; Allocate space for 16 rows + 8 rows of buffer
|
||||
VBUFF_SPRITE_START equ {VBUFF_TILE_ROW_BYTES+4} ; Start at an offset so $0000 can be used as an empty value
|
||||
VBUFF_SLOT_COUNT equ 48 ; Have space for this many stamps
|
||||
|
||||
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 queued 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 ; 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
|
||||
TS_TILE_DISP equ TILE_STORE_SIZE*10 ; derived from TS_TILE_ID to optimize tile dispatch in the Render function
|
||||
; This is 13 blocks wide
|
||||
SPRITE_PLANE_SPAN equ VBUFF_STRIDE_BYTES
|
||||
|
||||
; External references to data bank
|
||||
TileStore EXT
|
||||
DirtyTileCount EXT
|
||||
DirtyTiles EXT
|
||||
_Sprites EXT
|
||||
TileStore EXT
|
||||
TileStoreLookupYTable EXT
|
||||
TileStoreLookup EXT
|
||||
Col2CodeOffset EXT
|
||||
JTableOffset EXT
|
||||
CodeFieldEvenBRA EXT
|
||||
CodeFieldOddBRA EXT
|
||||
ScreenAddr EXT
|
||||
TileStoreYTable EXT
|
||||
NextCol EXT
|
||||
RTable EXT
|
||||
BlitBuff EXT
|
||||
BTableHigh EXT
|
||||
BTableLow EXT
|
||||
BRowTableHigh EXT
|
||||
BRowTableLow EXT
|
||||
BG1YTable EXT
|
||||
BG1YOffsetTable EXT
|
||||
OldOneSecVec EXT
|
||||
OneSecondCounter EXT
|
||||
Timers EXT
|
||||
DefaultPalette EXT
|
||||
ScreenModeWidth EXT
|
||||
ScreenModeHeight EXT
|
||||
_SpriteBits EXT
|
||||
_SpriteBitsNot EXT
|
||||
VBuffArray EXT
|
||||
_stamp_step EXT
|
||||
VBuffVertTableSelect EXT
|
||||
VBuffHorzTableSelect EXT
|
||||
Overlays EXT
|
||||
|
||||
; Tool error codes
|
||||
NO_TIMERS_AVAILABLE equ 10
|
||||
|
|
22
src/GTE.s
22
src/GTE.s
|
@ -20,12 +20,10 @@ SetBG1XPos EXT
|
|||
SetBG1YPos EXT
|
||||
CopyBG0Tile EXT
|
||||
CopyBG1Tile EXT
|
||||
CopyTileToDyn EXT
|
||||
Render EXT
|
||||
|
||||
; SCB/Palette binding (high bit of array point indicates whether to bind to BG0 Y position (0)
|
||||
; or BG1 Y position (1).
|
||||
SetSCBArray EXT
|
||||
; SetSCBArray EXT
|
||||
BltSCB EXT
|
||||
|
||||
; Rotation
|
||||
|
@ -73,21 +71,3 @@ AllocBank EXT
|
|||
ScreenAddr EXT
|
||||
OneSecondCounter EXT
|
||||
BlitBuff EXT
|
||||
|
||||
;; Helper function to load the GTE User Toolset
|
||||
;GTEInstall
|
||||
; php
|
||||
; ~InitialLoad userId;localToolPath;#0
|
||||
|
||||
; pea $8000 ; User tool
|
||||
; pea $00A5 ; Tool 165
|
||||
; PushLong toolPtr
|
||||
; _SetTSPtr
|
||||
|
||||
; plp
|
||||
; rtl
|
||||
|
||||
; Look for the tool set in the System Tools folder and then next to the application
|
||||
;sysToolPath strl '*:System:Tools:ToolGTE'
|
||||
;localToolPath strl '9:ToolGTE'
|
||||
;toolPtr adrl 0
|
220
src/Graphics.s
220
src/Graphics.s
|
@ -11,18 +11,81 @@ InitGraphics
|
|||
lda #0
|
||||
jsr _SetPalette
|
||||
|
||||
jsr _InitBG0 ; Initialize the background layers
|
||||
jsr _InitBG1
|
||||
jsr _InitBG0 ; Initialize the background layer
|
||||
|
||||
lda EngineMode
|
||||
bit #ENGINE_MODE_TWO_LAYER
|
||||
beq :no_bg1
|
||||
|
||||
jsr _InitBG1
|
||||
lda #0
|
||||
jsr _ClearBG1Buffer
|
||||
|
||||
:no_bg1
|
||||
rts
|
||||
|
||||
DefaultPalette dw $0000,$007F,$0090,$0FF0
|
||||
dw $000F,$0080,$0f70,$0FFF
|
||||
dw $0fa9,$0ff0,$00e0,$04DF
|
||||
dw $0d00,$078f,$0ccc,$0FFF
|
||||
; Allow the user to dynamically select one of the pre-configured screen sizes, or pass
|
||||
; in a specific width and height. The screen is automatically centered. If this is
|
||||
; not desired, then SetScreenRect should be used directly
|
||||
;
|
||||
; 0. Full Screen : 40 x 25 320 x 200 (32,000 bytes (100.0%))
|
||||
; 1. Sword of Sodan : 34 x 24 272 x 192 (26,112 bytes ( 81.6%))
|
||||
; 2. ~NES : 32 x 25 256 x 200 (25,600 bytes ( 80.0%))
|
||||
; 3. Task Force : 32 x 22 256 x 176 (22,528 bytes ( 70.4%))
|
||||
; 4. Defender of the World : 35 x 20 280 x 160 (22,400 bytes ( 70.0%))
|
||||
; 5. Rastan : 32 x 20 256 x 160 (20,480 bytes ( 64.0%))
|
||||
; 6. Game Boy Advanced : 30 x 20 240 x 160 (19,200 bytes ( 60.0%))
|
||||
; 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)
|
||||
_SetScreenMode
|
||||
cpx #11
|
||||
bcs :direct ; if x > 10, then assume X and Y are the dimensions
|
||||
|
||||
txa
|
||||
asl
|
||||
tax
|
||||
|
||||
ldy ScreenModeHeight,x
|
||||
lda ScreenModeWidth,x
|
||||
tax
|
||||
|
||||
:direct cpy #201
|
||||
bcs :exit
|
||||
|
||||
cpx #321
|
||||
bcs :exit
|
||||
|
||||
txa
|
||||
lsr
|
||||
pha ; Save X (width / 2) and Y (height)
|
||||
phy
|
||||
|
||||
lda #160 ; Center the screen
|
||||
sec
|
||||
sbc 3,s
|
||||
lsr
|
||||
xba
|
||||
pha ; Save half the origin coordinate
|
||||
|
||||
lda #200
|
||||
sec
|
||||
sbc 3,s ; This is now Y because of the PHA above
|
||||
lsr
|
||||
ora 1,s
|
||||
|
||||
plx ; Throw-away to pop the stack
|
||||
ply
|
||||
plx
|
||||
|
||||
jsr SetScreenRect
|
||||
jmp FillScreen ; tail return
|
||||
:exit
|
||||
rts
|
||||
|
||||
; Return the current border color ($0 - $F) in the accumulator
|
||||
_GetBorderColor lda #0000
|
||||
|
@ -33,10 +96,6 @@ _GetBorderColor lda #0000
|
|||
rts
|
||||
|
||||
; Set the border color to the accumulator value.
|
||||
SetBorderColor ENT
|
||||
jsr _SetBorderColor
|
||||
rtl
|
||||
|
||||
_SetBorderColor sep #$20 ; ACC = $X_Y, REG = $W_Z
|
||||
eorl BORDER_REG ; ACC = $(X^Y)_(Y^Z)
|
||||
and #$0F ; ACC = $0_(Y^Z)
|
||||
|
@ -55,17 +114,6 @@ _ClearToColor
|
|||
rts
|
||||
|
||||
; Set a palette values
|
||||
; A = high word of palette data pointer, X = low word of palette data pointer, Y = palette number
|
||||
SetPalette ENT
|
||||
phb ; save old data bank
|
||||
pha ; push 16-bit value
|
||||
plb ; pop 8-bit bank register
|
||||
tya
|
||||
jsr _SetPalette
|
||||
plb ; pop the other half of the 16-bit push off
|
||||
plb ; restore the original data bank
|
||||
rtl
|
||||
|
||||
; A = palette number, X = palette address
|
||||
_SetPalette
|
||||
and #$000F ; palette values are 0 - 15 and each palette is 32 bytes
|
||||
|
@ -148,9 +196,139 @@ _WaitForVBL
|
|||
rep #$20
|
||||
rts
|
||||
|
||||
; Set the physical location of the virtual screen on the physical screen. The
|
||||
; screen size must by a multiple of 8
|
||||
;
|
||||
; A = XXYY where XX is the left edge [0, 159] and YY is the top edge [0, 199]
|
||||
; X = width (in bytes)
|
||||
; Y = height (in lines)
|
||||
;
|
||||
; This subroutine stores the screen positions in the direct page space and fills
|
||||
; in the double-length ScreenAddrR table that holds the address of the right edge
|
||||
; of the playfield. This table is used to set addresses in the code banks when the
|
||||
; virtual origin is changed.
|
||||
;
|
||||
; We are not concerned about the raw performance of this function because it should
|
||||
; usually only be executed once during app initialization. It doesn't get called
|
||||
; with any significant frequency.
|
||||
|
||||
SetScreenRect sty ScreenHeight ; Save the screen height and width
|
||||
stx ScreenWidth
|
||||
|
||||
tax ; Temp save of the accumulator
|
||||
and #$00FF
|
||||
sta ScreenY0
|
||||
clc
|
||||
adc ScreenHeight
|
||||
sta ScreenY1
|
||||
|
||||
txa ; Restore the accumulator
|
||||
xba
|
||||
and #$00FF
|
||||
sta ScreenX0
|
||||
clc
|
||||
adc ScreenWidth
|
||||
sta ScreenX1
|
||||
|
||||
lda ScreenHeight ; Divide the height in scanlines by 8 to get the number tiles
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
sta ScreenTileHeight
|
||||
|
||||
lda ScreenWidth ; Divide width in bytes by 4 to get the number of tiles
|
||||
lsr
|
||||
lsr
|
||||
sta ScreenTileWidth
|
||||
|
||||
lda ScreenY0 ; Calculate the address of the first byte
|
||||
asl ; of the right side of the playfield
|
||||
tax
|
||||
lda ScreenAddr,x ; This is the address for the edge of the physical screen
|
||||
clc
|
||||
adc ScreenX1
|
||||
dec
|
||||
pha ; Save for second loop
|
||||
|
||||
ldx #0
|
||||
ldy ScreenHeight
|
||||
:loop clc
|
||||
sta RTable,x
|
||||
adc #160
|
||||
inx
|
||||
inx
|
||||
dey
|
||||
bne :loop
|
||||
|
||||
ldy ScreenHeight
|
||||
pla ; Reset the address and continue filling in the
|
||||
:loop2 clc
|
||||
sta RTable,x
|
||||
adc #160
|
||||
inx
|
||||
inx
|
||||
dey
|
||||
bne :loop2
|
||||
|
||||
; Calculate the screen locations for each tile corner
|
||||
|
||||
lda ScreenY0 ; Calculate the address of the first byte
|
||||
asl ; of the right side of the playfield
|
||||
tax
|
||||
lda ScreenAddr,x ; This is the address for the left edge of the physical screen
|
||||
clc
|
||||
adc ScreenX0
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
:tsloop
|
||||
sta TileStore+TS_SCREEN_ADDR,x
|
||||
|
||||
clc
|
||||
adc #4 ; Go to the next tile
|
||||
|
||||
iny
|
||||
cpy #41 ; If we've done 41 columns, move to the next line
|
||||
bcc :nohop
|
||||
ldy #0
|
||||
clc
|
||||
adc #{8*160}-{4*41}
|
||||
:nohop
|
||||
|
||||
inx
|
||||
inx
|
||||
cpx #TILE_STORE_SIZE-2
|
||||
bcc :tsloop
|
||||
|
||||
rts
|
||||
|
||||
; Clear the SHR screen and then infill the defined field
|
||||
FillScreen lda #0
|
||||
jsr _ClearToColor
|
||||
|
||||
ldy ScreenY0
|
||||
:yloop
|
||||
tya
|
||||
asl a
|
||||
tax
|
||||
lda ScreenAddr,x
|
||||
clc
|
||||
adc ScreenX0
|
||||
tax
|
||||
phy
|
||||
|
||||
lda ScreenWidth
|
||||
lsr
|
||||
tay
|
||||
lda #$FFFF
|
||||
:xloop stal $E10000,x ; X is the absolute address
|
||||
inx
|
||||
inx
|
||||
dey
|
||||
bne :xloop
|
||||
|
||||
ply
|
||||
iny
|
||||
cpy ScreenY1
|
||||
bcc :yloop
|
||||
rts
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
; IIgs Generic Tile Engine User Toolset
|
||||
|
||||
TYP $BA ; Tool set file
|
||||
DSK Tool160
|
||||
XPL
|
||||
|
||||
; Main toolbox interface and code
|
||||
|
||||
ASM Tool.s
|
||||
SNA Main
|
||||
|
||||
; 64KB Tile Memory
|
||||
|
||||
ASM static\TileData.s
|
||||
KND #$1001 ; Type and Attributes ($10=Static,$01=Data)
|
||||
ALI BANK
|
||||
SNA TDATA
|
||||
|
||||
; 64KB Sprite Plane Data
|
||||
|
||||
ASM static\SprData.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA SDATA
|
||||
|
||||
; 64KB Sprite Mask Data
|
||||
|
||||
ASM static\SprMask.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA SMASK
|
||||
|
||||
; 64KB Tile Store
|
||||
|
||||
ASM static\TileStore.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA TSTORE
|
|
@ -0,0 +1,88 @@
|
|||
; Math-y functions
|
||||
|
||||
mx %00
|
||||
|
||||
; Special subroutine to divide the accumulator by 164 and return remainder in the Accumulator
|
||||
;
|
||||
; 164 = $A4 = 1010_0100
|
||||
Mod164 cmp #%1010010000000000
|
||||
bcc *+5
|
||||
sbc #%1010010000000000
|
||||
|
||||
cmp #%0101001000000000
|
||||
bcc *+5
|
||||
sbc #%0101001000000000
|
||||
|
||||
cmp #%0010100100000000
|
||||
bcc *+5
|
||||
sbc #%0010100100000000
|
||||
|
||||
cmp #%0001010010000000
|
||||
bcc *+5
|
||||
sbc #%0001010010000000
|
||||
|
||||
cmp #%0000101001000000
|
||||
bcc *+5
|
||||
sbc #%0000101001000000
|
||||
|
||||
cmp #%0000010100100000
|
||||
bcc *+5
|
||||
sbc #%0000010100100000
|
||||
|
||||
cmp #%0000001010010000
|
||||
bcc *+5
|
||||
sbc #%0000001010010000
|
||||
|
||||
cmp #%0000000101001000
|
||||
bcc *+5
|
||||
sbc #%0000000101001000
|
||||
|
||||
cmp #%0000000010100100
|
||||
bcc *+5
|
||||
sbc #%0000000010100100
|
||||
rts
|
||||
|
||||
; Special subroutine to divide the accumulator by 208 and return remainder in the Accumulator
|
||||
;
|
||||
; 208 = $D0 = 1101_0000
|
||||
;
|
||||
; There are probably faster hacks to divide a 16-bit unsigned value by 208
|
||||
; https://www.drdobbs.com/parallel/optimizing-integer-division-by-a-constan/184408499
|
||||
; https://embeddedgurus.com/stack-overflow/2009/06/division-of-integers-by-constants/
|
||||
|
||||
Mod208 cmp #%1101000000000000
|
||||
bcc *+5
|
||||
sbc #%1101000000000000
|
||||
|
||||
cmp #%0110100000000000
|
||||
bcc *+5
|
||||
sbc #%0110100000000000
|
||||
|
||||
cmp #%0011010000000000
|
||||
bcc *+5
|
||||
sbc #%0011010000000000
|
||||
|
||||
cmp #%0001101000000000
|
||||
bcc *+5
|
||||
sbc #%0001101000000000
|
||||
|
||||
cmp #%0000110100000000
|
||||
bcc *+5
|
||||
sbc #%0000110100000000
|
||||
|
||||
cmp #%0000011010000000
|
||||
bcc *+5
|
||||
sbc #%0000011010000000
|
||||
|
||||
cmp #%0000001101000000
|
||||
bcc *+5
|
||||
sbc #%0000001101000000
|
||||
|
||||
cmp #%0000000110100000
|
||||
bcc *+5
|
||||
sbc #%0000000110100000
|
||||
|
||||
cmp #%0000000011010000
|
||||
bcc *+5
|
||||
sbc #%0000000011010000
|
||||
rts
|
52
src/Memory.s
52
src/Memory.s
|
@ -16,7 +16,11 @@
|
|||
|
||||
mx %00
|
||||
|
||||
InitMemory PushLong #0 ; space for result
|
||||
InitMemory lda EngineMode
|
||||
bit #ENGINE_MODE_BNK0_BUFF
|
||||
beq :no_bnk0_buff
|
||||
|
||||
PushLong #0 ; space for result
|
||||
PushLong #$008000 ; size (32k)
|
||||
PushWord UserId
|
||||
PushWord #%11000000_00010111 ; Fixed location
|
||||
|
@ -24,9 +28,10 @@ InitMemory PushLong #0 ; space for result
|
|||
_NewHandle ; returns LONG Handle on stack
|
||||
plx ; base address of the new handle
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
_Deref
|
||||
stx Buff00
|
||||
sta Buff00+2
|
||||
; _Deref
|
||||
; stx Buff00
|
||||
; sta Buff00+2
|
||||
:no_bnk0_buff
|
||||
|
||||
PushLong #0 ; space for result
|
||||
PushLong #$008000 ; size (32k)
|
||||
|
@ -36,12 +41,20 @@ InitMemory PushLong #0 ; space for result
|
|||
_NewHandle ; returns LONG Handle on stack
|
||||
plx ; base address of the new handle
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
_Deref
|
||||
stx Buff01
|
||||
sta Buff01+2
|
||||
; _Deref
|
||||
; stx Buff01
|
||||
; sta Buff01+2
|
||||
|
||||
PushLong #0 ; space for result
|
||||
PushLong #$000A00 ; size (10 pages)
|
||||
|
||||
pea #0000 ; size (2 or 10 pages)
|
||||
lda EngineMode
|
||||
bit #ENGINE_MODE_DYN_TILES
|
||||
beq :no_dyn_tiles
|
||||
pea #$0A00 ; 10 pages if dynamic tiles are enabled
|
||||
bra :dyn_done
|
||||
:no_dyn_tiles pea #$0200 ; 2 pages if dynamic tiles are disabled
|
||||
:dyn_done
|
||||
PushWord UserId
|
||||
PushWord #%11000000_00010101 ; Page-aligned, fixed bank
|
||||
PushLong #$000000
|
||||
|
@ -52,11 +65,15 @@ InitMemory PushLong #0 ; space for result
|
|||
stx BlitterDP
|
||||
|
||||
; Allocate banks of memory for BG1
|
||||
lda EngineMode
|
||||
bit #ENGINE_MODE_TWO_LAYER
|
||||
beq :no_bg1
|
||||
jsr AllocOneBank2
|
||||
sta BG1DataBank
|
||||
|
||||
jsr AllocOneBank2
|
||||
sta BG1AltBank
|
||||
:no_bg1
|
||||
|
||||
; Allocate the 13 banks of memory we need and store in double-length array
|
||||
]step equ 0
|
||||
|
@ -80,6 +97,7 @@ InitMemory PushLong #0 ; space for result
|
|||
sta BTableHigh+]step+{208*2},x ; 16 lines per bank
|
||||
]step equ ]step+2
|
||||
--^
|
||||
|
||||
lda BlitBuff,y
|
||||
sta BTableLow,x
|
||||
sta BTableLow+{208*2},x
|
||||
|
@ -93,10 +111,12 @@ InitMemory PushLong #0 ; space for result
|
|||
--^
|
||||
|
||||
txa
|
||||
clc
|
||||
adc #16*2 ; move to the next chunk of BTableHigh and BTableLow
|
||||
tax
|
||||
|
||||
tya
|
||||
clc
|
||||
adc #4 ; move to the next bank address
|
||||
tay
|
||||
cmp #4*13
|
||||
|
@ -104,6 +124,7 @@ InitMemory PushLong #0 ; space for result
|
|||
brl :bloop
|
||||
:exit1
|
||||
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
:bloop2
|
||||
|
@ -135,9 +156,6 @@ InitMemory PushLong #0 ; space for result
|
|||
:exit
|
||||
rts
|
||||
|
||||
Buff00 ds 4
|
||||
Buff01 ds 4
|
||||
|
||||
; Bank allocator (for one full, fixed bank of memory. Can be immediately deferenced)
|
||||
|
||||
AllocOneBank PushLong #0
|
||||
|
@ -149,19 +167,11 @@ AllocOneBank PushLong #0
|
|||
plx ; base address of the new handle
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
xba ; swap accumulator bytes to XX00
|
||||
sta :bank+2 ; store as bank for next op (overwrite $XX00)
|
||||
stal :bank+2 ; store as bank for next op (overwrite $XX00)
|
||||
:bank ldal $000001,X ; recover the bank address in A=XX/00
|
||||
rts
|
||||
|
||||
; Variation that returns the pointer in the X/A registers (X = low, A = high)
|
||||
AllocBank ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr AllocOneBank2
|
||||
plb
|
||||
rtl
|
||||
|
||||
AllocOneBank2 PushLong #0
|
||||
PushLong #$10000
|
||||
PushWord UserId
|
||||
|
@ -172,5 +182,3 @@ AllocOneBank2 PushLong #0
|
|||
pla ; high address 00XX of the new handle (bank)
|
||||
_Deref
|
||||
rts
|
||||
|
||||
|
||||
|
|
1194
src/Render.s
1194
src/Render.s
File diff suppressed because it is too large
Load Diff
49
src/Script.s
49
src/Script.s
|
@ -33,18 +33,13 @@
|
|||
;
|
||||
; A pointer to the current command instruction is stored in the first 4 bytes of the
|
||||
; timer's user data section.
|
||||
StartScript ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
|
||||
phx ; Save the script array address
|
||||
_StartScript phx ; Save the script array address
|
||||
pha
|
||||
|
||||
lda #_DoScriptSeq ; Try to create a timer for this script
|
||||
ldx #^_DoScriptSeq
|
||||
clc
|
||||
jsl AddTimer
|
||||
jsr _AddTimer
|
||||
bcs :err ; No timer slots available :(
|
||||
|
||||
tax ; Initialize the UserData with the command pointer
|
||||
|
@ -52,15 +47,12 @@ StartScript ENT
|
|||
sta Timers+8,x
|
||||
pla
|
||||
sta Timers+10,x
|
||||
|
||||
plb
|
||||
rtl
|
||||
rts
|
||||
|
||||
:err
|
||||
pla ; Pop the values and return with the carry flag set
|
||||
pla
|
||||
plb
|
||||
rtl
|
||||
rts
|
||||
|
||||
; This routine executes script command until it encounters one with the STOP bit set. In some
|
||||
; sense, the stop bit acts like a "yield" in high-level languages.
|
||||
|
@ -69,14 +61,6 @@ ARG1 equ 2
|
|||
ARG2 equ 4
|
||||
ARG3 equ 6
|
||||
|
||||
DoScriptSeq ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsl _DoScriptSeq ; Yes, this is a special JSL, because _DoScriptSeq is a time callback
|
||||
plb
|
||||
rtl
|
||||
|
||||
_DoScriptSeq
|
||||
phx ; save the timer index; will need to update user data at the end
|
||||
phb ; save the current data bank
|
||||
|
@ -99,6 +83,7 @@ _dss_loop phx ; Save the command address
|
|||
txy ; Cache in the y-register
|
||||
|
||||
lda: 0,x ; Load the command word
|
||||
|
||||
pha ; Stash it
|
||||
|
||||
and #$001E ; Only have 16 built-in commands. Use the _UserCallback
|
||||
|
@ -116,18 +101,20 @@ _dss_cmd_rtn
|
|||
; to the next entry.
|
||||
bit #JUMP ; Just do a fall through and set the jump offset to
|
||||
bne :move_addr ; a hard-coded value of 1 if the jump bit is not set
|
||||
:retry lda #$0100
|
||||
:move_addr and #$0F00 ; mask out the number of commands to move
|
||||
:retry lda #$0040
|
||||
:move_addr and #$0FC0 ; mask out the number of commands to move
|
||||
beq :retry ; Don't allow zeros; will cause infinite loop. Just advance by one.
|
||||
|
||||
xba ; put it in the low byte
|
||||
cmp #$0008 ; Sign-extend the 4-bit value
|
||||
cmp #$0800 ; Sign-extend the 6-bit value
|
||||
bcc *+5
|
||||
ora #$FFF0
|
||||
ora #$F000
|
||||
|
||||
asl ; multiply by 8
|
||||
asl
|
||||
asl
|
||||
cmp #$8000 ; make it a multiple of 8 (preserve sign)
|
||||
ror
|
||||
cmp #$8000
|
||||
ror
|
||||
cmp #$8000
|
||||
ror
|
||||
clc
|
||||
adc 3,s ; add it to the saved command address
|
||||
sta 3,s
|
||||
|
@ -175,14 +162,14 @@ _SetDTile
|
|||
ldx: ARG1,y
|
||||
lda: ARG2,y
|
||||
tay
|
||||
jsl CopyTileToDyn
|
||||
jsr CopyTileToDyn
|
||||
brl _dss_cmd_rtn
|
||||
|
||||
_UserCallback
|
||||
lda: ARG1,y
|
||||
sta :dispatch+1
|
||||
stal :dispatch+1
|
||||
lda: ARG1+1,y
|
||||
sta :dispatch+2
|
||||
stal :dispatch+2
|
||||
lda: ARG3,y
|
||||
:dispatch jsl $000000
|
||||
brl _dss_cmd_rtn
|
||||
|
|
959
src/Sprite.s
959
src/Sprite.s
File diff suppressed because it is too large
Load Diff
702
src/Sprite2.s
702
src/Sprite2.s
|
@ -1,63 +1,20 @@
|
|||
; Scratch space to lay out idealized _MakeDirtySprite
|
||||
; On input, X register = Sprite Array Index
|
||||
;Left equ tmp1
|
||||
;Right equ tmp2
|
||||
;Top equ tmp3
|
||||
;Bottom equ tmp4
|
||||
|
||||
Origin equ tmp4
|
||||
TileTop equ tmp5
|
||||
RowTop equ tmp6
|
||||
AreaIndex equ tmp7
|
||||
SpriteBit equ tmp8 ; set the bit of the value that if the current sprite index
|
||||
|
||||
TileLeft equ tmp8
|
||||
ColLeft equ tmp9
|
||||
|
||||
SpriteBit equ tmp10 ; set the bit of the value that if the current sprite index
|
||||
VBuffOrigin equ tmp11
|
||||
|
||||
; Helper function to take a local pixel coordinate [0, ScreenWidth-1],[0, ScreenHeight-1] and return the
|
||||
; row and column in the tile store that is corresponds to. This takes into consideration the StartX and
|
||||
; StartY offsets.
|
||||
;
|
||||
; This is more specialized than the code in the _MarkDirtySprite routine below since it does not deal with
|
||||
; negative or off-screen values.
|
||||
_OriginToTileStore
|
||||
lda StartYMod208
|
||||
lsr
|
||||
lsr
|
||||
and #$FFFE ; Store the pre-multiplied by 2 for indexing
|
||||
tay
|
||||
lda StartXMod164
|
||||
lsr
|
||||
and #$FFFE ; Same pre-multiply by 2 for later
|
||||
tax
|
||||
rts
|
||||
|
||||
; X = local x-coordinate (0, playfield width)
|
||||
; Y = local y-coordinate (0, playfield height)
|
||||
_LocalToTileStore
|
||||
clc
|
||||
tya
|
||||
adc StartYMod208 ; Adjust for the scroll offset
|
||||
cmp #208 ; check if we went too far positive
|
||||
bcc *+5
|
||||
sbc #208
|
||||
lsr
|
||||
lsr
|
||||
and #$FFFE ; Store the pre-multiplied by 2 for indexing
|
||||
tay
|
||||
|
||||
clc
|
||||
txa
|
||||
adc StartXMod164
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
lsr
|
||||
and #$FFFE ; Same pre-multiply by 2 for later
|
||||
tax
|
||||
rts
|
||||
; Table of pre-multiplied vbuff strides
|
||||
vbuff_mul
|
||||
dw 0*VBUFF_STRIDE_BYTES
|
||||
dw 1*VBUFF_STRIDE_BYTES
|
||||
dw 2*VBUFF_STRIDE_BYTES
|
||||
dw 3*VBUFF_STRIDE_BYTES
|
||||
dw 4*VBUFF_STRIDE_BYTES
|
||||
dw 5*VBUFF_STRIDE_BYTES
|
||||
dw 6*VBUFF_STRIDE_BYTES
|
||||
dw 7*VBUFF_STRIDE_BYTES
|
||||
|
||||
; Marks a sprite as dirty. The work here is mapping from local screen coordinates to the
|
||||
; tile store indices. The first step is to adjust the sprite coordinates based on the current
|
||||
|
@ -80,454 +37,307 @@ _LocalToTileStore
|
|||
; 8 10 2 8
|
||||
; ...
|
||||
;
|
||||
; For the Y-coordinate, we just use "mod 8" instead of "mod 4"
|
||||
mdsOut rts
|
||||
_MarkDirtySprite
|
||||
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y ; Clear this sprite's dirty tile list in case of an early exit
|
||||
lda _SpriteBits,y ; Cache its bit flag to mark in the tile slots
|
||||
sta SpriteBit
|
||||
; For the Y-coordinate, we use "mod 8" instead of "mod 4"
|
||||
;
|
||||
; When this subroutine is completed, the following values will be calculated
|
||||
;
|
||||
; _Sprites+TS_COVERAGE_SIZE : The number of horizontal and vertical playfield tiles covered by the sprite
|
||||
; _Sprites+TS_LOOKUP_INDEX : TileStore index of the upper-left corner of the sprite
|
||||
; _Sprites+TS_VBUFF_BASE : Address of the top-left corner of the sprite in the VBUFF sprite stamp memory
|
||||
;
|
||||
; The clipped sprite coordinates are used to calculate the tiles that are visible, but the actual
|
||||
; sprite coordinates (including handling negative values) are used to calculate the VBUFF offset
|
||||
; values.
|
||||
mdsOut2
|
||||
lda #6 ; Pick a value for a 0x0 tile sprite
|
||||
sta _Sprites+TS_COVERAGE_SIZE,y ; zero the list of tile store addresses
|
||||
rts
|
||||
|
||||
_CalcDirtySprite
|
||||
lda _Sprites+IS_OFF_SCREEN,y ; Check if the sprite is visible in the playfield
|
||||
bne mdsOut
|
||||
bne mdsOut2
|
||||
|
||||
; 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
|
||||
; Part 1: Calculate the visible tiles that the sprite covers. If the sprite is partially
|
||||
; off-screen, then the visible tiles may be different than the set of tiles
|
||||
; covered by the sprite. In particular, the upper-left corner tile which defines
|
||||
; relative offset values will change.
|
||||
;
|
||||
; So, we do some calculations with the CLIPPED values and some with the actual
|
||||
; sprite values. There is an optimization opportunity here to share calculations
|
||||
; when the x or y position of the sprite is positive.
|
||||
|
||||
; Add the first visible row of the sprite to the Y-scroll offset to find the first line in the
|
||||
; code field that needs to be drawn. The range of values is 0 to 199+207 = [0, 406]. This
|
||||
; value is dividede by 8, so the range of lookup values is [0, 50], so 51 possible values.
|
||||
|
||||
clc
|
||||
lda _Sprites+SPRITE_CLIP_TOP,y
|
||||
adc StartYMod208 ; Adjust for the scroll offset
|
||||
tax ; cache
|
||||
cmp #208 ; check if we went too far positive
|
||||
bcc *+5
|
||||
sbc #208
|
||||
pha ; Cache
|
||||
and #$FFF8 ; mask first to ensure LSR will clear the carry
|
||||
lsr
|
||||
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
|
||||
lsr
|
||||
tax
|
||||
lda TileStoreLookupYTable,x
|
||||
sta RowTop ; Even numbers from [0, 100] (51 elements)
|
||||
|
||||
; 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
|
||||
; Get the position of the top edge within the tile and then add it to the sprite's height
|
||||
; to calculate the number of tiles that are overlapped. We use the actual width and height
|
||||
; values here so small sprites (like 4x4 bullets) only force an update to the actual tiles
|
||||
; that are intersected, rather than assuming an 8x8 sprite always takes up that amount of
|
||||
; space.
|
||||
|
||||
txa
|
||||
pla
|
||||
and #$0007
|
||||
sta tmp0 ; save to adjust sprite origin
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_HEIGHT,y ; Nominal value between 0 and 16+7 = 23 = 10111
|
||||
adc _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
|
||||
; Add the horizontal position to the horizontal offset to find the first column in the
|
||||
; code field that needs to be drawn. The range of values is 0 to 159+163 = [0, 322].
|
||||
; This value is divided by 4, so 81 possible values
|
||||
|
||||
clc
|
||||
lda _Sprites+SPRITE_CLIP_LEFT,y
|
||||
adc StartXMod164
|
||||
tax
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
lsr
|
||||
and #$FFFE ; Same pre-multiply by 2 for later
|
||||
sta ColLeft
|
||||
pha
|
||||
and #$FFFC
|
||||
lsr ; Even numbers from [0, 160] (81 elements)
|
||||
adc RowTop
|
||||
sta _Sprites+TS_LOOKUP_INDEX,y ; This is the index into the TileStoreLookup table
|
||||
|
||||
txa
|
||||
|
||||
; Calculate the final amount of visible tiles that need to be refreshed and use that to
|
||||
; set the coverage size index.
|
||||
|
||||
pla
|
||||
and #$0003
|
||||
sta tmp1 ; save to adjust sprite origin
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_WIDTH,y ; max width = 8 = 0x08
|
||||
adc _Sprites+SPRITE_CLIP_WIDTH,y ; max width = 8 = 0x08
|
||||
dec
|
||||
clc
|
||||
adc tmp1
|
||||
and #$000C
|
||||
lsr ; max value = 4 = 0x04
|
||||
and #$0006
|
||||
ora AreaIndex
|
||||
sta AreaIndex
|
||||
ora AreaIndex ; merge into the area index
|
||||
sta _Sprites+TS_COVERAGE_SIZE,y ; Save this value as a key to the coverage size of the sprite
|
||||
|
||||
; 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
|
||||
; Part 2: Redo some calculation with the actual (signed) sprite positions that take into
|
||||
; account negative coordinates to set the VBuff offset values.
|
||||
|
||||
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
|
||||
lda _Sprites+SPRITE_Y,y
|
||||
adc StartYMod208
|
||||
bpl :y_ok
|
||||
clc
|
||||
adc #208 ; Wrap the actual coordinat around
|
||||
:y_ok and #$FFF8 ; mask first to ensure LSR will clear the carry
|
||||
lsr
|
||||
lsr
|
||||
tax ; Tile store lookup index
|
||||
|
||||
; Dispatch to cover the tiles
|
||||
lda _Sprites+SPRITE_X,y
|
||||
adc StartXMod164
|
||||
bpl :x_ok
|
||||
clc
|
||||
adc #164
|
||||
:x_ok and #$FFFC
|
||||
lsr ; Even numbers from [0, 160] (81 elements)
|
||||
sta tmp3
|
||||
adc TileStoreLookupYTable,x
|
||||
pha ; will be PLX later
|
||||
|
||||
ldx AreaIndex
|
||||
jmp (:mark,x)
|
||||
:mark dw :mark1x1,:mark1x2,:mark1x3,mdsOut
|
||||
clc ; Carry should still be clear here....
|
||||
lda StartYMod208
|
||||
adc _Sprites+SPRITE_Y,y
|
||||
bpl :pos_y
|
||||
clc
|
||||
adc #208
|
||||
:pos_y
|
||||
and #$0007
|
||||
asl ; Multiply by 48. Would be nice to use a
|
||||
asl ; table lookup, but the values can be negative
|
||||
asl ; so do the calculation
|
||||
asl
|
||||
sta tmp0
|
||||
asl
|
||||
clc
|
||||
adc tmp0
|
||||
sta tmp0
|
||||
|
||||
; Calculate the final address of the sprite data in the stamp buffer. We have to move earlier
|
||||
; in the buffer based on the horizontal offset and move up for each vertical offset.
|
||||
;
|
||||
; For a negative value we need to adjust the vbuff by the number of off-screen tiles plus
|
||||
; the alignment adjustment.
|
||||
|
||||
clc
|
||||
lda StartXMod164
|
||||
adc _Sprites+SPRITE_X,y
|
||||
bpl :pos_x
|
||||
clc
|
||||
adc #164
|
||||
:pos_x
|
||||
and #$0003
|
||||
clc
|
||||
adc tmp0 ; add to the vertical offset
|
||||
|
||||
; Subtract this value from the SPRITE_DISP address
|
||||
|
||||
eor #$FFFF ; A = -X - 1
|
||||
sec ; C = 1
|
||||
adc _Sprites+SPRITE_DISP,y ; A = SPRITE_DISP + (-X - 1) + 1 = SPRITE_DISP - X
|
||||
sta _Sprites+TS_VBUFF_BASE,y
|
||||
|
||||
; Create an offset value for loading the calculated VBUFF addresses within the core renderer by
|
||||
; subtracting the actual TileStore offset from the sprite's vbuff address array
|
||||
;
|
||||
; The X-register still has the TileStoreLookupYTable index, which we re-use to get a VBuff
|
||||
; array selector for the vertical location
|
||||
|
||||
lda VBuffVertTableSelect,x ; A bunch of 0, 12 or 24 values
|
||||
clc
|
||||
ldx tmp3
|
||||
adc VBuffHorzTableSelect,x ; A bunch of 0, 4 or 8 values
|
||||
clc
|
||||
adc #VBuffArray
|
||||
plx
|
||||
; ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
sec
|
||||
sbc TileStoreLookup,x
|
||||
sta tmp1 ; Spill this value to direct page temp space
|
||||
|
||||
; Last task. Since we don't need to use the X-register to cache values; load the direct page 2
|
||||
; offset for the SPRITE_VBUFF_PTR and save it
|
||||
|
||||
tmp_out
|
||||
tya
|
||||
ora #$100
|
||||
tax
|
||||
lda tmp1
|
||||
sta SPRITE_VBUFF_PTR,x
|
||||
|
||||
mdsOut rts
|
||||
|
||||
|
||||
; NOTE: The VBuffArray table is set up so that each sprite's vbuff address is stored in a
|
||||
; parallel structure to the Tile Store. This allows up to use the same TileStoreLookup
|
||||
; offset to index into the array of 16 sprite VBUFF addresses that are bound to a given tile
|
||||
_MarkDirtySpriteTiles
|
||||
lda _SpriteBits,y
|
||||
sta SpriteBit
|
||||
|
||||
clc
|
||||
ldx _Sprites+TS_COVERAGE_SIZE,y
|
||||
jmp (mdsmark,x)
|
||||
|
||||
mdsmark 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
|
||||
; Pair of macros to make the unrolled loop more concise
|
||||
;
|
||||
; 1. Load the tile store address from a fixed offset
|
||||
; 2. Set the sprite bit from the TS_SPRITE_FLAG location
|
||||
; 3. Checks if the tile is dirty and marks it
|
||||
; 4. If the tile was dirty, save the tile store address to be added to the DirtyTiles list later
|
||||
; 5. Sets the VBUFF address for the current sprite slot
|
||||
;
|
||||
; The second macro is the same as the first, but the VBUFF calculation is moved up so that the value
|
||||
; from the previous step can be reused and save a load every other step.
|
||||
TSSetSprite mac
|
||||
ldy TileStoreLookup+{]1},x
|
||||
|
||||
lda SpriteBit
|
||||
ora TileStore+TS_SPRITE_FLAG,y
|
||||
sta TileStore+TS_SPRITE_FLAG,y
|
||||
|
||||
lda TileStore+TS_DIRTY,y
|
||||
bne next
|
||||
|
||||
inc
|
||||
sta TileStore+TS_DIRTY,y
|
||||
|
||||
tya
|
||||
ldy DirtyTileCount
|
||||
sta DirtyTiles,y
|
||||
iny
|
||||
iny
|
||||
sty DirtyTileCount
|
||||
next
|
||||
<<<
|
||||
|
||||
ROW equ TILE_STORE_WIDTH*2 ; This many bytes to the next row in TileStore coordinates
|
||||
COL equ 2 ; This many bytes for each element
|
||||
|
||||
; 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.
|
||||
;
|
||||
; These functions are a trade off of being composable versus fast. Having to pay for multiple JSR/RTS invocations
|
||||
; in the hot sprite path isn't great, but we're at a point of diminishing returns.
|
||||
;
|
||||
; There *might* be some speed gained by pushing a list of :mark_R_C addressed onto the stack in the clipping routing
|
||||
; and dispatching that way, but probably not...
|
||||
:mark1x1
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}
|
||||
rts
|
||||
|
||||
; NOTE: If we rework the _PushDirtyTile to use the Y register instead of the X register, we can
|
||||
; optimize all of these :mark routines as
|
||||
;
|
||||
; :mark1x1
|
||||
; jsr :mark_0_0
|
||||
; sty _Sprites+TILE_STORE_ADDR_1,x
|
||||
; stz _Sprites+TILE_STORE_ADDR_2,y
|
||||
; rts
|
||||
|
||||
:mark1x2
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
jsr :mark_0_1
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_3,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
|
||||
rts
|
||||
|
||||
:mark1x3
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
jsr :mark_0_1
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
jsr :mark_0_2
|
||||
sta _Sprites+TILE_STORE_ADDR_3,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_4,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+4
|
||||
rts
|
||||
|
||||
:mark2x1
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
jsr :mark_1_0
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_3,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+0
|
||||
rts
|
||||
|
||||
:mark2x2
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
jsr :mark_0_1
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
jsr :mark_1_0
|
||||
sta _Sprites+TILE_STORE_ADDR_3,y
|
||||
jsr :mark_1_1
|
||||
sta _Sprites+TILE_STORE_ADDR_4,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_5,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+2
|
||||
rts
|
||||
|
||||
:mark2x3
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
jsr :mark_0_1
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
jsr :mark_0_2
|
||||
sta _Sprites+TILE_STORE_ADDR_3,y
|
||||
jsr :mark_1_0
|
||||
sta _Sprites+TILE_STORE_ADDR_4,y
|
||||
jsr :mark_1_1
|
||||
sta _Sprites+TILE_STORE_ADDR_5,y
|
||||
jsr :mark_1_2
|
||||
sta _Sprites+TILE_STORE_ADDR_6,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_7,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+4
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+4
|
||||
rts
|
||||
|
||||
:mark3x1
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
jsr :mark_1_0
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
jsr :mark_2_0
|
||||
sta _Sprites+TILE_STORE_ADDR_3,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_4,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 2*{TS_LOOKUP_SPAN*2}+0
|
||||
rts
|
||||
|
||||
:mark3x2
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
jsr :mark_1_0
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
jsr :mark_2_0
|
||||
sta _Sprites+TILE_STORE_ADDR_3,y
|
||||
jsr :mark_0_1
|
||||
sta _Sprites+TILE_STORE_ADDR_4,y
|
||||
jsr :mark_1_1
|
||||
sta _Sprites+TILE_STORE_ADDR_5,y
|
||||
jsr :mark_2_1
|
||||
sta _Sprites+TILE_STORE_ADDR_6,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_7,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 2*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 2*{TS_LOOKUP_SPAN*2}+2
|
||||
rts
|
||||
|
||||
:mark3x3
|
||||
jsr :mark_0_0
|
||||
sta _Sprites+TILE_STORE_ADDR_1,y
|
||||
jsr :mark_1_0
|
||||
sta _Sprites+TILE_STORE_ADDR_2,y
|
||||
jsr :mark_2_0
|
||||
sta _Sprites+TILE_STORE_ADDR_3,y
|
||||
jsr :mark_0_1
|
||||
sta _Sprites+TILE_STORE_ADDR_4,y
|
||||
jsr :mark_1_1
|
||||
sta _Sprites+TILE_STORE_ADDR_5,y
|
||||
jsr :mark_2_1
|
||||
sta _Sprites+TILE_STORE_ADDR_6,y
|
||||
jsr :mark_0_2
|
||||
sta _Sprites+TILE_STORE_ADDR_7,y
|
||||
jsr :mark_1_2
|
||||
sta _Sprites+TILE_STORE_ADDR_8,y
|
||||
jsr :mark_2_2
|
||||
sta _Sprites+TILE_STORE_ADDR_9,y
|
||||
lda #0
|
||||
sta _Sprites+TILE_STORE_ADDR_10,y
|
||||
ldx _Sprites+TS_LOOKUP_INDEX,y
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 0*{TS_LOOKUP_SPAN*2}+4
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 1*{TS_LOOKUP_SPAN*2}+4
|
||||
TSSetSprite 2*{TS_LOOKUP_SPAN*2}+0
|
||||
TSSetSprite 2*{TS_LOOKUP_SPAN*2}+2
|
||||
TSSetSprite 2*{TS_LOOKUP_SPAN*2}+4
|
||||
rts
|
||||
|
||||
; Begin List of subroutines to mark each tile offset
|
||||
:mark_0_0
|
||||
ldx RowTop
|
||||
lda ColLeft
|
||||
clc
|
||||
adc TileStoreYTable,x ; Fixed offset to the next row
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
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
|
||||
; 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
|
||||
; the sprites. If the screen is not scrolling and the sprites are not
|
||||
; 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 SpriteBit
|
||||
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
|
||||
|
||||
:mark_1_0
|
||||
lda ColLeft
|
||||
ldx RowTop
|
||||
clc
|
||||
adc TileStoreYTable+2,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{0*4}+{1*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
:mark_2_0
|
||||
lda ColLeft
|
||||
ldx RowTop
|
||||
clc
|
||||
adc TileStoreYTable+4,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{0*4}+{2*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
:mark_0_1
|
||||
ldx ColLeft
|
||||
lda NextCol+2,x
|
||||
ldx RowTop
|
||||
clc
|
||||
adc TileStoreYTable,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{1*4}+{0*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
:mark_1_1
|
||||
ldx ColLeft
|
||||
lda NextCol+2,x
|
||||
ldx RowTop
|
||||
clc
|
||||
adc TileStoreYTable+2,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{1*4}+{1*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
:mark_2_1
|
||||
ldx ColLeft
|
||||
lda NextCol+2,x
|
||||
ldx RowTop
|
||||
clc
|
||||
adc TileStoreYTable+4,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{1*4}+{2*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
:mark_0_2
|
||||
ldx ColLeft
|
||||
lda NextCol+4,x
|
||||
ldx RowTop
|
||||
clc
|
||||
adc TileStoreYTable,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{2*4}+{0*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
:mark_1_2
|
||||
ldx ColLeft
|
||||
lda NextCol+4,x
|
||||
ldx RowTop
|
||||
clc
|
||||
adc TileStoreYTable+2,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{2*4}+{1*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
:mark_2_2
|
||||
ldx ColLeft
|
||||
lda NextCol+4,x
|
||||
ldx RowTop
|
||||
clc
|
||||
adc TileStoreYTable+4,x
|
||||
tax
|
||||
|
||||
ldal TileStore+TS_VBUFF_ARRAY_ADDR,x
|
||||
sta tmp0
|
||||
|
||||
lda VBuffOrigin
|
||||
adc #{2*4}+{2*8*SPRITE_PLANE_SPAN}
|
||||
sta [tmp0],y
|
||||
|
||||
lda SpriteBit
|
||||
oral TileStore+TS_SPRITE_FLAG,x
|
||||
stal TileStore+TS_SPRITE_FLAG,x
|
||||
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
; End list of subroutines to mark dirty tiles
|
||||
|
||||
; Range-check and clamp the vertical part of the sprite. When this routine returns we will have valid
|
||||
; values for the tile-top and row-top. Also, the accumulator will return the number of rows to render,
|
||||
; 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
|
||||
|
||||
; 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
|
||||
_SpriteBitsNot dw $FFFE,$FFFD,$FFFB,$FFF7,$FFEF,$FFDF,$FFBF,$FF7F,$FEFF,$FDFF,$FBFF,$F7FF,$EFFF,$DFFF,$BFFF,$7FFF
|
||||
|
|
|
@ -1,28 +1,27 @@
|
|||
; Function to render a sprite from a sprite definition into the internal data buffers
|
||||
; Alternate entry point that takes arguments in registers instead of using a _Sprite
|
||||
; record
|
||||
;
|
||||
; X = sprite index
|
||||
_DrawSpriteSheet
|
||||
; Y = VBUFF address
|
||||
; X = Tile Data address
|
||||
; A = Sprite Flags
|
||||
DISP_VFLIP equ $0004 ; hard code these because they are internal values
|
||||
DISP_HFLIP equ $0002
|
||||
DISP_MASK equ $0018 ; Isolate the size bits
|
||||
DISP_MASK equ $0018 ; Preserve the size bits
|
||||
|
||||
phx
|
||||
|
||||
lda _Sprites+VBUFF_ADDR,x
|
||||
sta tmp1
|
||||
|
||||
lda _Sprites+TILE_DATA_OFFSET,x
|
||||
sta tmp2
|
||||
|
||||
lda _Sprites+SPRITE_DISP,x
|
||||
_DrawSpriteStamp
|
||||
sty tmp1
|
||||
stx tmp2
|
||||
xba
|
||||
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
|
||||
|
||||
; X = sprite ID
|
||||
; Y = Tile Data
|
||||
; A = VBUFF address
|
||||
ldx tmp3
|
||||
ldy tmp2
|
||||
lda tmp1
|
||||
|
@ -34,7 +33,7 @@ DISP_MASK equ $0018 ; Isolate the size bits
|
|||
ldy tmp2
|
||||
lda tmp1
|
||||
clc
|
||||
adc #4*3
|
||||
adc #3*4
|
||||
jsr _DrawSprite
|
||||
|
||||
lda tmp3
|
||||
|
@ -43,7 +42,7 @@ DISP_MASK equ $0018 ; Isolate the size bits
|
|||
ldy tmp2
|
||||
lda tmp1
|
||||
clc
|
||||
adc #4*6
|
||||
adc #6*4
|
||||
jsr _DrawSprite
|
||||
|
||||
lda tmp3
|
||||
|
@ -52,19 +51,16 @@ DISP_MASK equ $0018 ; Isolate the size bits
|
|||
ldy tmp2
|
||||
lda tmp1
|
||||
clc
|
||||
adc #4*9
|
||||
adc #9*4
|
||||
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
|
||||
|
@ -166,6 +162,9 @@ draw_16x8hv
|
|||
ply
|
||||
jmp _DrawTile8x8V
|
||||
|
||||
; X = sprite ID
|
||||
; Y = Tile Data
|
||||
; A = VBUFF address
|
||||
draw_16x16
|
||||
clc
|
||||
tax
|
||||
|
@ -262,7 +261,7 @@ draw_16x16hv
|
|||
tax
|
||||
tya
|
||||
pha
|
||||
adc #128+{128*32} ; Bottom-right source to top-left
|
||||
adc #{128*{32+1}}+64 ; Bottom-right source to top-left
|
||||
tay
|
||||
jsr _DrawTile8x8V
|
||||
|
||||
|
@ -270,7 +269,7 @@ draw_16x16hv
|
|||
adc #4
|
||||
tax
|
||||
lda 1,s
|
||||
adc #{128*32}
|
||||
adc #{128*32}+64
|
||||
tay
|
||||
jsr _DrawTile8x8V
|
||||
|
||||
|
@ -278,14 +277,16 @@ draw_16x16hv
|
|||
adc #{8*SPRITE_PLANE_SPAN}-4
|
||||
tax
|
||||
lda 1,s
|
||||
adc #128
|
||||
adc #128+64
|
||||
tay
|
||||
jsr _DrawTile8x8V
|
||||
|
||||
txa
|
||||
adc #4
|
||||
tax
|
||||
ply
|
||||
pla
|
||||
adc #64
|
||||
tay
|
||||
jmp _DrawTile8x8V
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
; Old code the was in Version 1, but is not needed. May be adapted for Verions 2.
|
||||
|
||||
; Y = _Sprites array offset
|
||||
_EraseSpriteY
|
||||
lda _Sprites+OLD_VBUFF_ADDR,y
|
||||
beq :noerase
|
||||
ldx _Sprites+SPRITE_DISP,y ; get the dispatch index for this sprite (32 values)
|
||||
jmp (:do_erase,x)
|
||||
:noerase rts
|
||||
:do_erase dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8
|
||||
dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16
|
||||
dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8
|
||||
dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16
|
||||
dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8
|
||||
dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16
|
||||
dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8
|
||||
dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16
|
||||
|
||||
; A = bank address
|
||||
_EraseTileSprite8x8
|
||||
tax
|
||||
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
|
||||
]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
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
_EraseTileSprite8x16
|
||||
tax
|
||||
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
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb ; pop the mask bank (high byte)
|
||||
lda #$FFFF
|
||||
]line equ 0
|
||||
lup 16
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
_EraseTileSprite16x8
|
||||
tax
|
||||
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
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+4,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+6,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
_EraseTileSprite16x16
|
||||
tax
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
|
||||
; First, if there is only one sprite, then we can skip any overhead and do a single lda/and/ora/sta to put the
|
||||
; sprite data on the screen.
|
||||
;
|
||||
; Second, if there are 4 or less, then we "stack" the sprite data using an unrolled loop that allows each
|
||||
; sprite to just be a single and/ora pair and the final result is not written to any intermediate memory buffer.
|
||||
;
|
||||
; Third, if there are 5 or more sprites, then we assume that the sprites are "dense" and that there will be a
|
||||
; non-trivial amount of overdraw. In this case we do a series of optimized copies of the sprite data *and*
|
||||
; masks into a direct page buffer in *reverse order*. Once a mask value becomes zero, then nothing else can
|
||||
; show through and that value can be skipped. Once all of the mask values are zero, then the render is terminated
|
||||
; and the data buffer copied to the final destination.
|
||||
;
|
||||
; Note that these rendering algorithms impose a priority ordering on the sprites where lower sprite IDs are drawn
|
||||
; underneath higher sprite IDs.
|
||||
RenderActiveSpriteTiles
|
||||
cmp #0 ; Is there only one active sprite? If so optimise
|
||||
bne :many
|
||||
|
||||
ldx vbuff ; load the address to the (adjusted) sprite tile
|
||||
lda TileStore+TS_SCREEN_ADDR,y
|
||||
tay
|
||||
|
||||
lda tiledata+0,y
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
sta 00,s
|
||||
|
||||
lda tiledata+2,y
|
||||
andl spritemask+2,x
|
||||
oral spritedata+2,x
|
||||
sta 02,s
|
||||
|
||||
...
|
||||
tsc
|
||||
adc #320
|
||||
tcs
|
||||
...
|
||||
|
||||
lda tiledata+{line*4},y
|
||||
andl spritemask+{line*SPAN},x
|
||||
oral spritedata+{line*SPAN},x
|
||||
sta 160,s
|
||||
|
||||
lda tiledata+{line*4}+2,y
|
||||
andl spritemask+{line*SPAN}+2,x
|
||||
oral spritedata+{line*SPAN}+2,x
|
||||
sta 162,s
|
||||
|
||||
rts
|
||||
|
||||
|
||||
:many
|
||||
lda TileStore+TS_SCREEN_ADDR,y
|
||||
tcs
|
||||
lda TileStore+TS_TILE_ADDR,y
|
||||
tay
|
||||
|
||||
ldx count
|
||||
jmp (:arr,x)
|
||||
lda tiledata+0,y
|
||||
ldx vbuff
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
ldx vbuff+2
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
ldx vbuff+4
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
...
|
||||
sta 00,s
|
||||
|
||||
ldx count
|
||||
jmp (:arr,x)
|
||||
lda tiledata+0,y
|
||||
ldx vbuff
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
ldx vbuff+2
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
ldx vbuff+4
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
...
|
||||
sta 02,s
|
||||
|
||||
sta 160,s
|
||||
|
||||
sta 162,s
|
||||
|
||||
tsc
|
||||
adc #320
|
|
@ -10,12 +10,6 @@
|
|||
; in actual games since the primary background is often large empty areas, or runs
|
||||
; of repeating tiles.
|
||||
|
||||
; Debug locations
|
||||
LastTop ds 2
|
||||
LastBottom ds 2
|
||||
LastLeft ds 2
|
||||
LastRight ds 2
|
||||
|
||||
; The ranges are [:Left, :Right] and [:Top, :Bottom], so :Right can be, at most, 40
|
||||
; if we are drawing all 41 tiles (Index 0 through 40). The :Bottom value can be
|
||||
; at most 25.
|
||||
|
@ -222,17 +216,6 @@ _UpdateBG0TileMap
|
|||
:NoXUpdate
|
||||
rts
|
||||
|
||||
;:Debug
|
||||
; lda :Top ; Debugging
|
||||
; sta LastTop
|
||||
; lda :Bottom
|
||||
; sta LastBottom
|
||||
; lda :Left
|
||||
; sta LastLeft
|
||||
; lda :Right
|
||||
; sta LastRight
|
||||
; rts
|
||||
|
||||
; This is a private subroutine that draws in tiles into the code fields using the
|
||||
; data from the tilemap and the local :Top, :Left, :Bottom and :Right parameters.
|
||||
:DrawRectBG0
|
||||
|
@ -639,7 +622,7 @@ _DrawRectBG1
|
|||
|
||||
ldx :BlkX
|
||||
ldy :BlkY
|
||||
jsr _CopyBG1Tile
|
||||
; jsr _CopyBG1Tile
|
||||
|
||||
lda :BlkX
|
||||
inc
|
||||
|
@ -676,4 +659,3 @@ _DrawRectBG1
|
|||
pla
|
||||
|
||||
rts
|
||||
|
||||
|
|
|
@ -0,0 +1,628 @@
|
|||
; Basic tile functions
|
||||
|
||||
; Copy tileset data from a pointer in memory to the tiledata back
|
||||
; X = high word
|
||||
; A = low word
|
||||
_LoadTileSet
|
||||
sta tmp0
|
||||
stx tmp1
|
||||
ldy #0
|
||||
tyx
|
||||
:loop lda [tmp0],y
|
||||
stal tiledata,x
|
||||
dex
|
||||
dex
|
||||
dey
|
||||
dey
|
||||
bne :loop
|
||||
rts
|
||||
|
||||
|
||||
; Low-level function to take a tile descriptor and return the address in the tiledata
|
||||
; bank. This is not too useful in the fast-path because the fast-path does more
|
||||
; incremental calculations, but it is handy for other utility functions
|
||||
;
|
||||
; A = tile descriptor
|
||||
;
|
||||
; The address is the TileID * 128 + (HFLIP * 64)
|
||||
_GetTileAddr
|
||||
asl ; Multiply by 2
|
||||
bit #2*TILE_HFLIP_BIT ; Check if the horizontal flip bit is set
|
||||
beq :no_flip
|
||||
inc ; Set the LSB
|
||||
:no_flip asl ; x4
|
||||
asl ; x8
|
||||
asl ; x16
|
||||
asl ; x32
|
||||
asl ; x64
|
||||
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
|
||||
|
||||
|
||||
; Helper function to get the address offset into the tile cachce / tile backing store
|
||||
; X = tile column [0, 40] (41 columns)
|
||||
; Y = tile row [0, 25] (26 rows)
|
||||
_GetTileStoreOffset
|
||||
phx ; preserve the registers
|
||||
phy
|
||||
|
||||
jsr _GetTileStoreOffset0
|
||||
|
||||
ply
|
||||
plx
|
||||
rts
|
||||
|
||||
_GetTileStoreOffset0
|
||||
tya
|
||||
asl
|
||||
tay
|
||||
txa
|
||||
asl
|
||||
clc
|
||||
adc TileStoreYTable,y
|
||||
rts
|
||||
|
||||
; Initialize the tile storage data structures. This takes care of populating the tile records with the
|
||||
; appropriate constant values.
|
||||
InitTiles
|
||||
:col equ tmp0
|
||||
:row equ tmp1
|
||||
:vbuff equ tmp2
|
||||
:base equ tmp3
|
||||
|
||||
; Initialize the Tile Store
|
||||
|
||||
ldx #TILE_STORE_SIZE-2
|
||||
lda #25
|
||||
sta :row
|
||||
lda #40
|
||||
sta :col
|
||||
lda #$8000
|
||||
sta :vbuff
|
||||
|
||||
:loop
|
||||
|
||||
; The first set of values in the Tile Store that are changed during each frame based on the actions
|
||||
; that are happening
|
||||
|
||||
lda #0
|
||||
sta TileStore+TS_TILE_ID,x ; clear the tile store with the special zero tile
|
||||
sta TileStore+TS_TILE_ADDR,x
|
||||
sta TileStore+TS_SPRITE_FLAG,x ; no sprites are set at the beginning
|
||||
sta TileStore+TS_DIRTY,x ; none of the tiles are dirty
|
||||
|
||||
; Set the default tile rendering functions
|
||||
|
||||
lda EngineMode
|
||||
bit #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER
|
||||
beq :fast
|
||||
bit #ENGINE_MODE_TWO_LAYER
|
||||
beq :dyn
|
||||
; ldal TileProcs
|
||||
; sta TileStore+TS_BASE_TILE_DISP,x
|
||||
bra :out
|
||||
:fast
|
||||
lda #0 ; Initialize with Tile 0
|
||||
ldy #FastProcs
|
||||
jsr _SetTileProcs
|
||||
bra :out
|
||||
|
||||
:dyn lda #0 ; Initialize with Tile 0
|
||||
ldy #FastProcs
|
||||
jsr _SetTileProcs
|
||||
|
||||
:out
|
||||
|
||||
; lda DirtyTileProcs ; Fill in with the first dispatch address
|
||||
; stal TileStore+TS_DIRTY_TILE_DISP,x
|
||||
;
|
||||
; lda TileProcs ; Same for non-dirty, non-sprite base case
|
||||
; stal TileStore+TS_BASE_TILE_DISP,x
|
||||
|
||||
|
||||
; 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
|
||||
|
||||
lda :row ; Set the long address of where this tile
|
||||
asl ; exists in the code fields
|
||||
tay
|
||||
lda #>TileStore ; get middle 16 bits: "00 -->BBHH<-- LL"
|
||||
and #$FF00 ; merge with code field bank
|
||||
ora BRowTableHigh,y
|
||||
sta TileStore+TS_CODE_ADDR_HIGH,x ; High word of the tile address (just the bank)
|
||||
|
||||
lda BRowTableLow,y
|
||||
sta :base
|
||||
; sta 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
|
||||
|
||||
tay
|
||||
lda Col2CodeOffset+2,y
|
||||
clc
|
||||
adc :base
|
||||
; adc TileStore+TS_BASE_ADDR,x
|
||||
sta TileStore+TS_CODE_ADDR_LOW,x ; Low word of the tile address in the code field
|
||||
|
||||
lda JTableOffset,y
|
||||
clc
|
||||
adc :base
|
||||
sta TileStore+TS_JMP_ADDR,x ; Address of the snippet handler for this tile
|
||||
|
||||
dec :col
|
||||
bpl :hop
|
||||
dec :row
|
||||
lda #40
|
||||
sta :col
|
||||
:hop
|
||||
|
||||
dex
|
||||
dex
|
||||
bpl :loop
|
||||
rts
|
||||
|
||||
; Set a tile value in the tile backing store. Mark dirty if the value changes
|
||||
;
|
||||
; A = tile id
|
||||
; X = tile column [0, 40] (41 columns)
|
||||
; Y = tile row [0, 25] (26 rows)
|
||||
;
|
||||
; Registers are not preserved
|
||||
oldTileId equ blttmp ; This location is used in _SetTileProcs, too
|
||||
newTileId equ blttmp+2
|
||||
procIdx equ blttmp+4
|
||||
|
||||
_SetTile
|
||||
sta newTileId
|
||||
jsr _GetTileStoreOffset0 ; Get the address of the X,Y tile position
|
||||
tax
|
||||
|
||||
lda TileStore+TS_TILE_ID,x
|
||||
cmp newTileId
|
||||
bne :changed
|
||||
rts
|
||||
|
||||
:changed sta oldTileId
|
||||
lda newTileId
|
||||
sta TileStore+TS_TILE_ID,x ; Value is different, store it.
|
||||
jsr _GetTileAddr
|
||||
sta TileStore+TS_TILE_ADDR,x ; Committed to drawing this tile, so get the address of the tile in the tiledata bank for later
|
||||
|
||||
; Set the renderer procs for this tile.
|
||||
;
|
||||
; NOTE: Later on, optimize this to just take the Tile ID & TILE_CTRL_MASK and lookup the right proc
|
||||
; table address from a lookup table....
|
||||
;
|
||||
; 1. The dirty render proc is always set the same.
|
||||
; 2. If BG1 and DYN_TILES are disabled, then the TS_BASE_TILE_DISP is selected from the Fast Renderers, otherwise
|
||||
; it is selected from the full tile rendering functions.
|
||||
; 3. The copy process is selected based on the flip bits
|
||||
;
|
||||
; When a tile overlaps the sprite, it is the responsibility of the Render function to compose the appropriate
|
||||
; functionality. Sometimes it is simple, but in cases of the sprites overlapping Dynamic Tiles and other cases
|
||||
; it can be more involved.
|
||||
|
||||
; Calculate the base tile proc selector from the tile Id
|
||||
stz procIdx
|
||||
|
||||
lda #TILE_PRIORITY_BIT
|
||||
bit newTileId
|
||||
beq :low_priority
|
||||
lda #4
|
||||
sta procIdx
|
||||
:low_priority
|
||||
lda #TILE_ID_MASK
|
||||
bit newTileId
|
||||
beq :is_zero
|
||||
lda #2
|
||||
tsb procIdx
|
||||
:is_zero
|
||||
|
||||
lda #TILE_VFLIP_BIT
|
||||
bit newTileId
|
||||
beq :no_vflip
|
||||
lda #1
|
||||
tsb procIdx
|
||||
:no_vflip
|
||||
|
||||
; Now integrate with the engine mode indicator
|
||||
|
||||
lda EngineMode
|
||||
bit #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER
|
||||
beq :setTileFast
|
||||
|
||||
bit #ENGINE_MODE_TWO_LAYER
|
||||
bne :not_dyn
|
||||
brl :setTileDyn
|
||||
|
||||
:not_dyn
|
||||
lda #TILE_DYN_BIT
|
||||
bit newTileId
|
||||
beq :pickTwoLyrProc
|
||||
|
||||
ldy #TwoLyrDynProcs
|
||||
brl :pickDynProc
|
||||
|
||||
:pickTwoLyrProc ldy #TwoLyrProcs
|
||||
lda procIdx
|
||||
jsr _SetTileProcs
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
; Specialized check for when the engine is in "Fast" mode. If is a simple decision tree based on whether
|
||||
; the tile priority bit is set, and whether this is the special tile 0 or not.
|
||||
:setTileFast
|
||||
ldy #FastProcs
|
||||
lda procIdx
|
||||
jsr _SetTileProcs
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
; Specialized check for when the engine has enabled dynamic tiles. In this case we are no longer
|
||||
; guaranteed that the opcodes in a tile are PEA instructions.
|
||||
:setTileDyn
|
||||
lda #TILE_DYN_BIT
|
||||
bit newTileId
|
||||
beq :pickSlowProc ; If the Dynamic bit is not set, select a tile proc that sets opcodes
|
||||
|
||||
ldy #DynProcs ; use this table
|
||||
:pickDynProc
|
||||
lda newTileId ; Otherwise chose one of the two dynamic tuples
|
||||
and #TILE_PRIORITY_BIT
|
||||
beq *+5 ; If the Priority bit is not set, pick the first entry
|
||||
lda #1 ; If the Priority bit is set, pick the other one
|
||||
jsr _SetTileProcs
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
:pickSlowProc ldy #SlowProcs
|
||||
lda procIdx
|
||||
jsr _SetTileProcs
|
||||
jmp _PushDirtyTileX
|
||||
|
||||
; X = Tile Store offset
|
||||
; Y = Engine Mode Base Table address
|
||||
; A = Table proc index
|
||||
;
|
||||
; see TileProcTables in static/TileStore.s
|
||||
tblPtr equ blttmp
|
||||
_SetTileProcs
|
||||
|
||||
; Multiple the proc index by 6 to get the correct table entry offset
|
||||
|
||||
asl
|
||||
sta tblPtr
|
||||
asl
|
||||
adc tblPtr
|
||||
sta tblPtr
|
||||
|
||||
; Add this offset to the base table address
|
||||
|
||||
tya
|
||||
adc tblPtr
|
||||
sta tblPtr
|
||||
|
||||
; Set the pointer to this bank
|
||||
|
||||
phk
|
||||
phk
|
||||
pla
|
||||
and #$00FF
|
||||
sta tblPtr+2
|
||||
|
||||
; Lookup the tile procedures
|
||||
|
||||
ldy #0
|
||||
lda [tblPtr],y
|
||||
stal K_TS_BASE_TILE_DISP,x
|
||||
|
||||
ldy #2
|
||||
lda [tblPtr],y
|
||||
stal K_TS_SPRITE_TILE_DISP,x
|
||||
|
||||
ldy #4
|
||||
lda [tblPtr],y
|
||||
stal K_TS_ONE_SPRITE,x
|
||||
rts
|
||||
|
||||
; TileProcTables
|
||||
;
|
||||
; Tables of tuples used to populate the K_TS_* dispatch arrays for different combinations. This is
|
||||
; easier to maintain than a bunch of conditional code. Each etry hold three addresses.
|
||||
;
|
||||
; First address: Draw a tile directly into the code buffer (no sprites)
|
||||
; Second address: Draw a tile merged with sprite data from the direct page
|
||||
; Third address: Specialize routine to draw a tile merged with one sprite
|
||||
;
|
||||
; There are unique tuples of routines for all of the different combinations of tile properties
|
||||
; and engine modes. This is an extesive number of combinations, but it simplified the development
|
||||
; and maintainence of the rendering subroutines. Also, the difference subroutines can be written
|
||||
; in any way and can make use of their on subroutines to reduce code size.
|
||||
;
|
||||
; Properties:
|
||||
;
|
||||
; [MODE] ENGINE_MODE: Fast, Dyn, TwoLayer
|
||||
; [Z | N] Is Tile 0? : Yes, No
|
||||
; [A | V] Is VFLIP? : Yes, No
|
||||
; [Over | Under] Priority? : Yes, No
|
||||
;
|
||||
; So eight tuples per engine mode; 24 tuples total. Table name convention
|
||||
;
|
||||
; <MODE><Over|Under><Z|N><A|V>
|
||||
FastProcs
|
||||
FastOverZA dw ConstTile0Fast,SpriteOver0Fast,OneSpriteFastOver0
|
||||
FastOverZV dw ConstTile0Fast,SpriteOver0Fast,OneSpriteFastOver0
|
||||
FastOverNA dw CopyTileAFast,SpriteOverAFast,OneSpriteFastOverA
|
||||
FastOverNV dw CopyTileVFast,SpriteOverVFast,OneSpriteFastOverV
|
||||
FastUnderZA dw ConstTile0Fast,SpriteUnder0Fast,SpriteUnder0Fast
|
||||
FastUnderZV dw ConstTile0Fast,SpriteUnder0Fast,SpriteUnder0Fast
|
||||
FastUnderNA dw CopyTileAFast,SpriteUnderAFast,OneSpriteFastUnderA
|
||||
FastUnderNV dw CopyTileVFast,SpriteUnderVFast,OneSpriteFastUnderV
|
||||
|
||||
; "Slow" procs. These are duplicates of the "Fast" functions, but also
|
||||
; set the PEA opcode in all cases.
|
||||
SlowProcs
|
||||
SlowOverZA dw ConstTile0Slow,SpriteOver0Slow,OneSpriteSlowOver0
|
||||
SlowOverZV dw ConstTile0Slow,SpriteOver0Slow,OneSpriteSlowOver0
|
||||
SlowOverNA dw CopyTileASlow,SpriteOverASlow,OneSpriteSlowOverA
|
||||
SlowOverNV dw CopyTileVSlow,SpriteOverVSlow,OneSpriteSlowOverV
|
||||
SlowUnderZA dw ConstTile0Slow,SpriteUnder0Slow,SpriteUnder0Slow
|
||||
SlowUnderZV dw ConstTile0Slow,SpriteUnder0Slow,SpriteUnder0Slow
|
||||
SlowUnderNA dw CopyTileASlow,SpriteUnderASlow,OneSpriteSlowUnderA
|
||||
SlowUnderNV dw CopyTileVSlow,SpriteUnderVSlow,OneSpriteSlowUnderV
|
||||
|
||||
; "Dynamic" procs. These are the specialized routines for a dynamic tiles
|
||||
; that does not need to worry about a second background. Because dynamic
|
||||
; tiles don't support horizontal or vertical flipping, there are only two
|
||||
; sets of procedures: one for Over and one for Under.
|
||||
DynProcs
|
||||
DynOver dw CopyDynamicTile,DynamicOver,OneSpriteDynamicOver
|
||||
DynUnder dw CopyDynamicTile,DynamicUnder,OneSpriteDynamicUnder
|
||||
|
||||
; "Two Layer" procs. These are the most complex procs. Generally,
|
||||
; all of these methods are implemented by building up the data
|
||||
; and mask into the direct page space and then calling a common
|
||||
; function to create the complex code fragments in the code field.
|
||||
; There is not a lot of opportuinity to optimize these routines.
|
||||
;
|
||||
; To improve the performance when two-layer rendering is enabled,
|
||||
; the TILE_SOLID_BIT hint bit can be set to indicate that a tile
|
||||
; has no transparency. This allows one of the faster routines
|
||||
; to be selected from the other Proc tables
|
||||
TwoLyrProcs
|
||||
TwoLyrOverZA dw Tile0TwoLyr,SpriteOver0TwoLyr,OneSpriteOver0TwoLyr
|
||||
TwoLyrOverZV dw Tile0TwoLyr,SpriteOver0TwoLyr,OneSpriteOver0TwoLyr
|
||||
TwoLyrOverNA dw CopyTileATwoLyr,SpriteOverATwoLyr,OneSpriteTwoLyrOverA
|
||||
TwoLyrOverNV dw CopyTileVTwoLyr,SpriteOverVTwoLyr,OneSpriteTwoLyrOverV
|
||||
TwoLyrUnderZA dw Tile0TwoLyr,SpriteOver0TwoLyr,OneSpriteOver0TwoLyr ; if sprites are over or under the transparent tile, same rendering code
|
||||
TwoLyrUnderZV dw Tile0TwoLyr,SpriteOver0TwoLyr,OneSpriteOver0TwoLyr
|
||||
TwoLyrUnderNA dw CopyTileATwoLyr,SpriteUnderATwoLyr,OneSpriteTwoLyrUnderA
|
||||
TwoLyrUnderNV dw CopyTileVTwoLyr,SpriteUnderVTwoLyr,OneSpriteTwoLyrUnderV
|
||||
|
||||
; "Dynamic" procs that can handle the second background.
|
||||
TwoLyrDynProcs
|
||||
TwoLyrDynOver dw CopyDynamicTileTwoLyr,DynamicOverTwoLyr,OneSpriteDynamicOverTwoLyr
|
||||
TwoLyrDynUnder dw CopyDynamicTileTwoLyr,DynamicUnderTwoLyr,OneSpriteDynamicUnderTwoLyr
|
||||
|
||||
; SetBG0XPos
|
||||
;
|
||||
; Set the virtual horizontal position of the primary background layer. In addition to
|
||||
; updating the direct page state locations, this routine needs to preserve the original
|
||||
; value as well. This is a bit subtle, because if this routine is called multiple times
|
||||
; with different values, we need to make sure the *original* value is preserved and not
|
||||
; continuously overwrite it.
|
||||
;
|
||||
; We assume that there is a clean code field in this routine
|
||||
_SetBG0XPos
|
||||
cmp StartX
|
||||
beq :out ; Easy, if nothing changed, then nothing changes
|
||||
|
||||
ldx StartX ; Load the old value (but don't save it yet)
|
||||
sta StartX ; Save the new position
|
||||
|
||||
lda #DIRTY_BIT_BG0_X
|
||||
tsb DirtyBits ; Check if the value is already dirty, if so exit
|
||||
bne :out ; without overwriting the original value
|
||||
|
||||
stx OldStartX ; First change, so preserve the value
|
||||
:out rts
|
||||
|
||||
|
||||
; SetBG0YPos
|
||||
;
|
||||
; Set the virtual position of the primary background layer.
|
||||
_SetBG0YPos
|
||||
cmp StartY
|
||||
beq :out ; Easy, if nothing changed, then nothing changes
|
||||
|
||||
ldx StartY ; Load the old value (but don't save it yet)
|
||||
sta StartY ; Save the new position
|
||||
|
||||
lda #DIRTY_BIT_BG0_Y
|
||||
tsb DirtyBits ; Check if the value is already dirty, if so exit
|
||||
bne :out ; without overwriting the original value
|
||||
|
||||
stx OldStartY ; First change, so preserve the value
|
||||
:out rts
|
||||
|
||||
; Macro helper for the bit test tree
|
||||
; dobit bit_position,dest;next;exit
|
||||
dobit mac
|
||||
lsr
|
||||
bcc next_bit
|
||||
beq last_bit
|
||||
tax
|
||||
lda (SPRITE_VBUFF_PTR+{]1*2}),y
|
||||
clc
|
||||
adc _Sprites+TS_VBUFF_BASE+{]1*2}
|
||||
sta sprite_ptr0+{]2*4}
|
||||
txa
|
||||
jmp ]3
|
||||
last_bit lda (SPRITE_VBUFF_PTR+{]1*2}),y
|
||||
clc ; pre-adjust these later
|
||||
adc _Sprites+TS_VBUFF_BASE+{]1*2}
|
||||
sta sprite_ptr0+{]2*4}
|
||||
jmp ]4
|
||||
next_bit
|
||||
<<<
|
||||
|
||||
; Specialization for the first sprite which can optimize its dispatch if its the only one
|
||||
; dobit bit_position,dest;next;exit
|
||||
dobit1 mac
|
||||
lsr
|
||||
bcc next_bit
|
||||
beq last_bit
|
||||
tax
|
||||
lda (SPRITE_VBUFF_PTR+{]1*2}),y
|
||||
clc
|
||||
adc _Sprites+TS_VBUFF_BASE+{]1*2}
|
||||
sta sprite_ptr0+{]2*4}
|
||||
txa
|
||||
jmp ]3
|
||||
last_bit lda (SPRITE_VBUFF_PTR+{]1*2}),y
|
||||
clc ; pre-adjust these later
|
||||
adc _Sprites+TS_VBUFF_BASE+{]1*2}
|
||||
sta sprite_ptr0+{]2*4}
|
||||
tyx
|
||||
jmp (K_TS_ONE_SPRITE,x)
|
||||
next_bit
|
||||
<<<
|
||||
|
||||
; If we find a last bit (4th in this case) and will exit
|
||||
stpbit mac
|
||||
lsr
|
||||
bcc next_bit
|
||||
lda (SPRITE_VBUFF_PTR+{]1*2}),y
|
||||
clc ; pre-adjust these later
|
||||
adc _Sprites+TS_VBUFF_BASE+{]1*2}
|
||||
sta sprite_ptr0+{]2*4}
|
||||
jmp ]3
|
||||
next_bit
|
||||
<<<
|
||||
|
||||
; Last bit test which *must* be set
|
||||
endbit mac
|
||||
lda (SPRITE_VBUFF_PTR+{]1*2}),y
|
||||
clc ; pre-adjust these later
|
||||
adc _Sprites+TS_VBUFF_BASE+{]1*2}
|
||||
sta sprite_ptr0+{]2*4}
|
||||
jmp ]3
|
||||
<<<
|
||||
|
||||
endbit1 mac
|
||||
lda (SPRITE_VBUFF_PTR+{]1*2}),y
|
||||
clc ; pre-adjust these later
|
||||
adc _Sprites+TS_VBUFF_BASE+{]1*2}
|
||||
sta sprite_ptr0+{]2*4}
|
||||
tyx
|
||||
jmp (K_TS_ONE_SPRITE,x)
|
||||
<<<
|
||||
|
||||
; OPTIMIZATION:
|
||||
;
|
||||
; bit #$00FF ; Skip the first 8 bits if they are all zeros
|
||||
; bne norm_entry
|
||||
; xba
|
||||
; jmp skip_entry
|
||||
;
|
||||
; Placed at the entry point
|
||||
|
||||
; This is a complex, but fast subroutine that is called from the core tile rendering code. It
|
||||
; Takes a bitmap of sprites in the Accumulator and then extracts the VBuff addresses for the
|
||||
; target TileStore entry and places them in specific direct page locations.
|
||||
;
|
||||
; Inputs:
|
||||
; A = sprite bitmap (assumed to be non-zero)
|
||||
; Y = tile store index
|
||||
; D = second work page
|
||||
; B = vbuff array bank
|
||||
; Output:
|
||||
; X =
|
||||
;
|
||||
; ]1 address of single sprite process
|
||||
; ]2 address of two sprite process
|
||||
; ]3 address of three sprite process
|
||||
; ]4 address of four sprite process
|
||||
|
||||
SpriteBitsToVBuffAddrs mac
|
||||
dobit1 0;0;b_1_1
|
||||
dobit1 1;0;b_2_1
|
||||
dobit1 2;0;b_3_1
|
||||
dobit1 3;0;b_4_1
|
||||
dobit1 4;0;b_5_1
|
||||
dobit1 5;0;b_6_1
|
||||
dobit1 6;0;b_7_1
|
||||
dobit1 7;0;b_8_1
|
||||
dobit1 8;0;b_9_1
|
||||
dobit1 9;0;b_10_1
|
||||
dobit1 10;0;b_11_1
|
||||
dobit1 11;0;b_12_1
|
||||
dobit1 12;0;b_13_1
|
||||
dobit1 13;0;b_14_1
|
||||
dobit1 14;0;b_15_1
|
||||
endbit1 15;0
|
||||
|
||||
b_1_1 dobit 1;1;b_2_2;]2
|
||||
b_2_1 dobit 2;1;b_3_2;]2
|
||||
b_3_1 dobit 3;1;b_4_2;]2
|
||||
b_4_1 dobit 4;1;b_5_2;]2
|
||||
b_5_1 dobit 5;1;b_6_2;]2
|
||||
b_6_1 dobit 6;1;b_7_2;]2
|
||||
b_7_1 dobit 7;1;b_8_2;]2
|
||||
b_8_1 dobit 8;1;b_9_2;]2
|
||||
b_9_1 dobit 9;1;b_10_2;]2
|
||||
b_10_1 dobit 10;1;b_11_2;]2
|
||||
b_11_1 dobit 11;1;b_12_2;]2
|
||||
b_12_1 dobit 12;1;b_13_2;]2
|
||||
b_13_1 dobit 13;1;b_14_2;]2
|
||||
b_14_1 dobit 14;1;b_15_2;]2
|
||||
b_15_1 endbit 15;1;]2
|
||||
|
||||
b_2_2 dobit 2;2;b_3_3;]3
|
||||
b_3_2 dobit 3;2;b_4_3;]3
|
||||
b_4_2 dobit 4;2;b_5_3;]3
|
||||
b_5_2 dobit 5;2;b_6_3;]3
|
||||
b_6_2 dobit 6;2;b_7_3;]3
|
||||
b_7_2 dobit 7;2;b_8_3;]3
|
||||
b_8_2 dobit 8;2;b_9_3;]3
|
||||
b_9_2 dobit 9;2;b_10_3;]3
|
||||
b_10_2 dobit 10;2;b_11_3;]3
|
||||
b_11_2 dobit 11;2;b_12_3;]3
|
||||
b_12_2 dobit 12;2;b_13_3;]3
|
||||
b_13_2 dobit 13;2;b_14_3;]3
|
||||
b_14_2 dobit 14;2;b_15_3;]3
|
||||
b_15_2 endbit 15;2;]3
|
||||
|
||||
b_3_3 stpbit 3;3;]4
|
||||
b_4_3 stpbit 4;3;]4
|
||||
b_5_3 stpbit 5;3;]4
|
||||
b_6_3 stpbit 6;3;]4
|
||||
b_7_3 stpbit 7;3;]4
|
||||
b_8_3 stpbit 8;3;]4
|
||||
b_9_3 stpbit 9;3;]4
|
||||
b_10_3 stpbit 10;3;]4
|
||||
b_11_3 stpbit 11;3;]4
|
||||
b_12_3 stpbit 12;3;]4
|
||||
b_13_3 stpbit 13;3;]4
|
||||
b_14_3 stpbit 14;3;]4
|
||||
b_15_3 endbit 15;3;]4
|
||||
<<<
|
||||
|
||||
; Store some tables in the K bank that will be used exclusively for jmp (abs,x) dispatch
|
||||
|
||||
K_TS_BASE_TILE_DISP ds TILE_STORE_SIZE ; draw the tile without a sprite
|
||||
K_TS_COPY_TILE_DATA ds TILE_STORE_SIZE ; copy/merge the tile into temp storage
|
||||
K_TS_SPRITE_TILE_DISP ds TILE_STORE_SIZE ; select the sprite routine for this tile
|
||||
K_TS_ONE_SPRITE ds TILE_STORE_SIZE ; specialized sprite routine when only one sprite covers the tile
|
||||
K_TS_APPLY_TILE_DATA ds TILE_STORE_SIZE ; move tile from temp storage into code field
|
119
src/Timer.s
119
src/Timer.s
|
@ -1,37 +1,5 @@
|
|||
; Timer implementation
|
||||
;
|
||||
; The engire provides four timer slot that can be used by one-shot or
|
||||
; recurring timers. Each timer is given an initial tick count, a
|
||||
; reset tick count (0 = one-shot), and an action to perform.
|
||||
;
|
||||
; The timers handle overflow, so if a recurring timer has a tick count of 3
|
||||
; and 7 VBL ticks have passed, then the timer will be fired twice and
|
||||
; a tick count of 2 will be set.
|
||||
;
|
||||
; As such, the timers are appropriate to drive physical and other game
|
||||
; behaviors at a frame-independent rate.
|
||||
;
|
||||
; A collection of 4 timers that are triggered when their countdown
|
||||
; goes below zero. Each timer takes up 16 bytes
|
||||
;
|
||||
; A timer can fire multiple times during a singular evaluation. For example, if the
|
||||
; timer delay is set to 1 and 3 VBL ticks happen, then the timer delta is -2, will fire,
|
||||
; have the delay added and get -1, fire again, increment to zero, first again and then
|
||||
; finally reset to 1.
|
||||
;
|
||||
; +0 counter decremented by the number of ticks since last run
|
||||
; +2 reset copied into counter when triggered. 0 turns off the timer.
|
||||
; +4 addr long address of timer routine
|
||||
; +8 user 8 bytes of user data space for timer state
|
||||
MAX_TIMERS equ 4
|
||||
TIMER_REC_SIZE equ 16
|
||||
mx %00
|
||||
|
||||
lastTick ds 2
|
||||
Timers ds TIMER_REC_SIZE*MAX_TIMERS
|
||||
|
||||
GetVBLTicks ENT
|
||||
jsr _GetVBLTicks
|
||||
rtl
|
||||
_GetVBLTicks
|
||||
PushLong #0
|
||||
_GetTick
|
||||
|
@ -42,7 +10,7 @@ _GetVBLTicks
|
|||
; Initialize the timers
|
||||
InitTimers
|
||||
jsr _GetVBLTicks
|
||||
sta lastTick
|
||||
sta LastTick
|
||||
|
||||
lda #0
|
||||
ldx #{TIMER_REC_SIZE*MAX_TIMERS}-2
|
||||
|
@ -63,17 +31,12 @@ InitTimers
|
|||
; Return
|
||||
; C = 0 if success, 1 if no timer slots are available
|
||||
; A = timer slot ID if C = 0
|
||||
AddTimer ENT
|
||||
phb
|
||||
|
||||
_AddTimer
|
||||
php ; Save the input parameters
|
||||
phx
|
||||
pha
|
||||
phy
|
||||
|
||||
phk
|
||||
plb
|
||||
|
||||
ldx #0
|
||||
:loop lda Timers,x ; If the counter is zero, timer is free
|
||||
beq :freeslot
|
||||
|
@ -105,28 +68,23 @@ AddTimer ENT
|
|||
lda Timers+0,x ; if not a one-shot, put the counter
|
||||
sta Timers+2,x ; value into the reset field
|
||||
|
||||
:oneshot plb
|
||||
txa ; return the slot ID and a success status
|
||||
:oneshot txa ; return the slot ID and a success status
|
||||
clc
|
||||
rtl
|
||||
rts
|
||||
|
||||
:notimers ply
|
||||
pla
|
||||
plx
|
||||
plp
|
||||
plb
|
||||
|
||||
sec ; Return an error status
|
||||
lda #0
|
||||
rtl
|
||||
rts
|
||||
|
||||
; Small function to remove a timer
|
||||
;
|
||||
; A = Timer ID
|
||||
RemoveTimer ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
_RemoveTimer
|
||||
cmp #{TIMER_REC_SIZE*{MAX_TIMERS-1}}+1
|
||||
bcs :exit
|
||||
|
||||
|
@ -137,38 +95,51 @@ RemoveTimer ENT
|
|||
stz Timers+6,x
|
||||
|
||||
:exit
|
||||
plb
|
||||
rtl
|
||||
rts
|
||||
|
||||
; Execute the timer functions
|
||||
DoTimers ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
;DoTimers ENT
|
||||
; phb
|
||||
; jsr _SetDataBank
|
||||
;
|
||||
; jsr _GetVBLTicks
|
||||
;
|
||||
; cmp LastTick ; Throttle to 60 fps
|
||||
; beq :exit
|
||||
; tax ; Calculate the increment
|
||||
; sec
|
||||
; sbc LastTick
|
||||
; stx LastTick
|
||||
|
||||
jsr _GetVBLTicks
|
||||
|
||||
cmp lastTick ; Throttle to 60 fps
|
||||
beq :exit
|
||||
tax ; Calculate the increment
|
||||
sec
|
||||
sbc lastTick
|
||||
stx lastTick
|
||||
|
||||
; We don't want times to fire excessively. If the timer has nt been evaluated for over
|
||||
; We don't want times to fire excessively. If the timer hasn't been evaluated for over
|
||||
; one second, then just skip processing and wait for the next call.
|
||||
cmp #60
|
||||
bcs :exit
|
||||
; cmp #60
|
||||
; bcs :exit
|
||||
|
||||
jsr _DoTimers
|
||||
; jsr _DoTimers
|
||||
|
||||
:exit plb
|
||||
rtl
|
||||
;:exit plb
|
||||
; rtl
|
||||
|
||||
; Countdown the timers
|
||||
;
|
||||
; A = number of elapsed ticks
|
||||
_DoTimers
|
||||
jsr _GetVBLTicks
|
||||
|
||||
cmp LastTick ; Throttle to 60 fps
|
||||
beq :exit
|
||||
|
||||
tax ; Calculate the increment
|
||||
sec
|
||||
sbc LastTick
|
||||
stx LastTick
|
||||
|
||||
; We don't want times to fire excessively. If the timer hasn't been evaluated for over
|
||||
; one second, then just skip processing and wait for the next call.
|
||||
cmp #60
|
||||
bcc :do_timer
|
||||
:exit rts
|
||||
|
||||
:do_timer
|
||||
pha
|
||||
ldx #0
|
||||
:loop
|
||||
|
@ -186,9 +157,9 @@ _DoTimers
|
|||
phx ; Save our index
|
||||
|
||||
lda Timers+4,x ; execute the timer callback
|
||||
sta :dispatch+1
|
||||
stal :dispatch+1
|
||||
lda Timers+5,x
|
||||
sta :dispatch+2
|
||||
stal :dispatch+2
|
||||
:dispatch jsl $000000
|
||||
|
||||
plx
|
||||
|
|
688
src/Tool.s
688
src/Tool.s
|
@ -3,10 +3,47 @@
|
|||
; Ref: Toolbox Reference, Volume 2, Appendix A
|
||||
; Ref: IIgs Tech Note #73
|
||||
|
||||
use Mem.Macs.s
|
||||
use Misc.Macs.s
|
||||
use Util.Macs
|
||||
use Locator.Macs
|
||||
use Core.MACS.s
|
||||
|
||||
use Defs.s
|
||||
use static/TileStoreDefs.s
|
||||
|
||||
ToStrip equ $E10184
|
||||
|
||||
; Define some macros to help streamline the entry and exit from the toolbox calls
|
||||
_TSEntry mac
|
||||
phd
|
||||
phb
|
||||
tcd
|
||||
jsr _SetDataBank
|
||||
<<<
|
||||
|
||||
_TSExit mac
|
||||
plb
|
||||
pld
|
||||
ldx ]1 ; Error code
|
||||
ldy ]2 ; Number of stack bytes to remove
|
||||
jml ToStrip
|
||||
<<<
|
||||
|
||||
_TSExit1 mac
|
||||
plb
|
||||
pld
|
||||
; ldx ]1 ; Error code already in X
|
||||
ldy ]1 ; Number of stack bytes to remove
|
||||
jml ToStrip
|
||||
<<<
|
||||
|
||||
FirstParam equ 10 ; When using the _TSEntry macro, the first parameter is at 10,s
|
||||
|
||||
mx %00
|
||||
|
||||
_CallTable
|
||||
dw {_CTEnd-_CallTable}/4,0
|
||||
adrl {_CTEnd-_CallTable}/4
|
||||
adrl _TSBootInit-1
|
||||
adrl _TSStartUp-1
|
||||
adrl _TSShutDown-1
|
||||
|
@ -16,8 +53,63 @@ _CallTable
|
|||
adrl _TSReserved-1
|
||||
adrl _TSReserved-1
|
||||
|
||||
adrl _TSSetScreenMode
|
||||
adrl _TSReadControl-1
|
||||
adrl _TSSetScreenMode-1
|
||||
adrl _TSSetTile-1
|
||||
adrl _TSSetBG0Origin-1
|
||||
adrl _TSRender-1
|
||||
adrl _TSLoadTileSet-1
|
||||
adrl _TSCreateSpriteStamp-1
|
||||
adrl _TSAddSprite-1
|
||||
adrl _TSMoveSprite-1
|
||||
adrl _TSUpdateSprite-1
|
||||
adrl _TSRemoveSprite-1
|
||||
|
||||
adrl _TSGetSeconds-1
|
||||
|
||||
adrl _TSCopyTileToDynamic-1
|
||||
|
||||
adrl _TSSetPalette-1
|
||||
adrl _TSCopyPicToBG1-1
|
||||
adrl _TSBindSCBArray-1
|
||||
adrl _TSGetBG0TileMapInfo-1
|
||||
adrl _TSGetScreenInfo-1
|
||||
adrl _TSSetBG1Origin-1
|
||||
adrl _TSGetTileAt-1
|
||||
|
||||
adrl _TSSetBG0TileMapInfo-1
|
||||
adrl _TSSetBG1TileMapInfo-1
|
||||
|
||||
adrl _TSAddTimer-1
|
||||
adrl _TSRemoveTimer-1
|
||||
adrl _TSStartScript-1
|
||||
|
||||
adrl _TSSetOverlay-1
|
||||
adrl _TSClearOverlay-1
|
||||
|
||||
adrl _TSGetTileDataAddr-1
|
||||
adrl _TSFillTileStore-1
|
||||
adrl _TSRefresh-1
|
||||
_CTEnd
|
||||
_GTEAddSprite MAC
|
||||
UserTool $1000+GTEToolNum
|
||||
<<<
|
||||
_GTEMoveSprite MAC
|
||||
UserTool $1100+GTEToolNum
|
||||
<<<
|
||||
_GTEUpdateSprite MAC
|
||||
UserTool $1200+GTEToolNum
|
||||
<<<
|
||||
_GTERemoveSprite MAC
|
||||
UserTool $1300+GTEToolNum
|
||||
<<<
|
||||
; Helper function to set the data back to the toolset default
|
||||
_SetDataBank sep #$20
|
||||
lda #^TileStore
|
||||
pha
|
||||
plb
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; Do nothing when the tool set is installed
|
||||
_TSBootInit
|
||||
|
@ -25,40 +117,66 @@ _TSBootInit
|
|||
clc
|
||||
rtl
|
||||
|
||||
; Call the regular GTE startup function after setting the Work Area Point (WAP). The caller much provide
|
||||
; one page of Bank 0 memory for the tool set's private use
|
||||
; Call the regular GTE startup function after setting the Work Area Pointer (WAP). The caller must provide
|
||||
; one page of Bank 0 memory for the tool set's private use and a userId to use for allocating memory
|
||||
;
|
||||
; X =
|
||||
; X = tool set number in low byte and function number in high byte
|
||||
;
|
||||
; StartUp(dPageAddr, capFlags, userId)
|
||||
_TSStartUp
|
||||
:zpToUse equ 7
|
||||
|
||||
pea #$8000
|
||||
userId = 7
|
||||
capFlags = userId+2
|
||||
zpToUse = userId+4
|
||||
|
||||
lda zpToUse,s ; Get the direct page address
|
||||
phd ; Save the current direct page
|
||||
tcd ; Set to our working direct page space
|
||||
|
||||
txa
|
||||
and #$00FF
|
||||
pha
|
||||
and #$00FF ; Get just the tool number
|
||||
sta ToolNum
|
||||
|
||||
pea $0000
|
||||
lda :zpToUse+6,s
|
||||
pha
|
||||
lda userId+2,s ; Get the userId for memory allocations
|
||||
sta UserId
|
||||
|
||||
lda capFlags+2,s ; Get the engine capability bits
|
||||
sta EngineMode
|
||||
|
||||
phb
|
||||
jsr _SetDataBank
|
||||
jsr _CoreStartUp ; Initialize the library
|
||||
plb
|
||||
|
||||
; SetWAP(userOrSystem, tsNum, waptPtr)
|
||||
|
||||
pea #$8000 ; $8000 = user tool set
|
||||
pei ToolNum ; Push the tool number from the direct page
|
||||
pea $0000 ; High word of WAP is zero (bank 0)
|
||||
phd ; Low word of WAP is the direct page
|
||||
_SetWAP
|
||||
|
||||
jsr _CoreStartUp
|
||||
pld ; Restore the caller's direct page
|
||||
|
||||
ldx #0 ; No error
|
||||
ldy #6 ; Remove the 6 input bytes
|
||||
jml ToStrip
|
||||
|
||||
; ShutDown()
|
||||
_TSShutDown
|
||||
cmp #0 ; Acc is low word of the WAP (direct page)
|
||||
beq :inactive
|
||||
|
||||
phd
|
||||
pha
|
||||
pld ; Set the direct page for the toolset
|
||||
tcd ; Set the direct page for the toolset
|
||||
|
||||
phx ; Preserve the X register
|
||||
jsr _CoreShutDown ; Shut down GTE
|
||||
pla
|
||||
phb
|
||||
jsr _SetDataBank
|
||||
jsr _CoreShutDown ; Shut down the library
|
||||
plb
|
||||
|
||||
pea $8000
|
||||
and #$00FF
|
||||
pha
|
||||
pei ToolNum
|
||||
pea $0000 ; Set WAP to null
|
||||
pea $0000
|
||||
_SetWAP
|
||||
|
@ -71,7 +189,7 @@ _TSShutDown
|
|||
rtl
|
||||
|
||||
_TSVersion
|
||||
lda #$0100 ; Version 1
|
||||
lda #$0100 ; Version 1
|
||||
sta 7,s
|
||||
|
||||
lda #0
|
||||
|
@ -88,7 +206,7 @@ _TSStatus
|
|||
sta 1,s
|
||||
tya
|
||||
ora 1,s
|
||||
sta 1,s ; 0 if WAP is null, non-zero if WAP is set
|
||||
sta 1,s ; 0 if WAP is null, non-zero if WAP is set
|
||||
|
||||
lda #0
|
||||
clc
|
||||
|
@ -101,31 +219,523 @@ _TSReserved
|
|||
sec
|
||||
rtl
|
||||
|
||||
; SetScreenMode(width, height)
|
||||
_TSSetScreenMode
|
||||
phd ; Preserve the direct page
|
||||
pha
|
||||
pld
|
||||
height equ FirstParam
|
||||
width equ FirstParam+2
|
||||
|
||||
lda 9,s
|
||||
_TSEntry
|
||||
|
||||
lda height,s
|
||||
tay
|
||||
lda 9,s
|
||||
lda width,s
|
||||
tax
|
||||
jsr _SetScreenMode
|
||||
pld
|
||||
|
||||
ldx #0 ; No error
|
||||
ldy #4 ; Remove the 4 input bytes
|
||||
jml ToStrip
|
||||
_TSExit #0;#4
|
||||
|
||||
; ReadControl()
|
||||
_TSReadControl
|
||||
phd ; Preserve the direct page
|
||||
pha
|
||||
pld
|
||||
:output equ FirstParam
|
||||
|
||||
_TSEntry
|
||||
|
||||
jsr _ReadControl
|
||||
sta 9,s
|
||||
sta :output,s
|
||||
|
||||
pld
|
||||
ldx #0 ; No error
|
||||
ldy #0 ; Remove zero input bytes
|
||||
jml ToStrip
|
||||
_TSExit #0;#0
|
||||
|
||||
; SetTile(xTile, yTile, tileId)
|
||||
_TSSetTile
|
||||
tileId equ FirstParam
|
||||
yTile equ FirstParam+2
|
||||
xTile equ FirstParam+4
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda xTile,s ; Valid range [0, 40] (41 columns)
|
||||
tax
|
||||
lda yTile,s ; Valid range [0, 25] (26 rows)
|
||||
tay
|
||||
lda tileId,s
|
||||
jsr _SetTile
|
||||
|
||||
_TSExit #0;#6
|
||||
|
||||
; SetBG0Origin(x, y)
|
||||
_TSSetBG0Origin
|
||||
yPos equ FirstParam
|
||||
xPos equ FirstParam+2
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda xPos,s
|
||||
jsr _SetBG0XPos
|
||||
lda yPos,s
|
||||
jsr _SetBG0YPos
|
||||
|
||||
_TSExit #0;#4
|
||||
|
||||
; Render()
|
||||
_TSRender
|
||||
_TSEntry
|
||||
jsr _Render
|
||||
_TSExit #0;#0
|
||||
|
||||
; LoadTileSet(Pointer)
|
||||
_TSLoadTileSet
|
||||
TSPtr equ FirstParam
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda TSPtr+2,s
|
||||
tax
|
||||
lda TSPtr,s
|
||||
jsr _LoadTileSet
|
||||
|
||||
_TSExit #0;#4
|
||||
|
||||
; CreateSpriteStamp(spriteId: Word, vbuffAddr: Word)
|
||||
_TSCreateSpriteStamp
|
||||
:vbuff equ FirstParam
|
||||
:spriteId equ FirstParam+2
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :vbuff,s
|
||||
tay
|
||||
lda :spriteId,s
|
||||
jsr _CreateSpriteStamp
|
||||
|
||||
_TSExit #0;#4
|
||||
|
||||
_TSAddSprite
|
||||
:spriteSlot equ FirstParam+0
|
||||
:spriteY equ FirstParam+2
|
||||
:spriteX equ FirstParam+4
|
||||
:spriteId equ FirstParam+6
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :spriteY,s
|
||||
and #$00FF
|
||||
xba
|
||||
sta :spriteY,s
|
||||
lda :spriteX,s
|
||||
and #$00FF
|
||||
ora :spriteY,s
|
||||
tay
|
||||
|
||||
lda :spriteSlot,s
|
||||
tax
|
||||
|
||||
lda :spriteId,s
|
||||
jsr _AddSprite
|
||||
|
||||
_TSExit #0;#8
|
||||
|
||||
_TSMoveSprite
|
||||
:spriteY equ FirstParam+0
|
||||
:spriteX equ FirstParam+2
|
||||
:spriteSlot equ FirstParam+4
|
||||
_TSEntry
|
||||
|
||||
lda :spriteX,s
|
||||
tax
|
||||
lda :spriteY,s
|
||||
tay
|
||||
lda :spriteSlot,s
|
||||
jsr _MoveSprite
|
||||
|
||||
_TSExit #0;#6
|
||||
|
||||
_TSUpdateSprite
|
||||
:vbuff equ FirstParam+0
|
||||
:spriteFlags equ FirstParam+2
|
||||
:spriteSlot equ FirstParam+4
|
||||
_TSEntry
|
||||
|
||||
lda :spriteFlags,s
|
||||
tax
|
||||
lda :vbuff,s
|
||||
tay
|
||||
lda :spriteSlot,s
|
||||
jsr _UpdateSprite
|
||||
|
||||
_TSExit #0;#6
|
||||
|
||||
_TSRemoveSprite
|
||||
:spriteSlot equ FirstParam+0
|
||||
_TSEntry
|
||||
|
||||
lda :spriteSlot,s
|
||||
jsr _RemoveSprite
|
||||
|
||||
_TSExit #0;#2
|
||||
|
||||
_TSGetSeconds
|
||||
:output equ FirstParam
|
||||
|
||||
_TSEntry
|
||||
|
||||
ldal OneSecondCounter
|
||||
sta :output,s
|
||||
|
||||
_TSExit #0;#0
|
||||
|
||||
_TSCopyTileToDynamic
|
||||
:dynId equ FirstParam+0
|
||||
:tileId equ FirstParam+2
|
||||
_TSEntry
|
||||
|
||||
lda EngineMode
|
||||
bit #ENGINE_MODE_DYN_TILES
|
||||
beq :notEnabled
|
||||
|
||||
lda :tileId,s
|
||||
tax
|
||||
lda :dynId,s
|
||||
tay
|
||||
jsr CopyTileToDyn
|
||||
|
||||
:notEnabled
|
||||
_TSExit #0;#4
|
||||
|
||||
|
||||
; SetPalette(palNum, Pointer)
|
||||
_TSSetPalette
|
||||
:ptr equ FirstParam+0
|
||||
:palNum equ FirstParam+4
|
||||
|
||||
_TSEntry
|
||||
|
||||
phb
|
||||
lda :ptr+3,s ; add one extra byte for the phb
|
||||
xba
|
||||
pha
|
||||
plb
|
||||
plb
|
||||
|
||||
lda :ptr+1,s
|
||||
tax
|
||||
lda :palNum+1,s
|
||||
jsr _SetPalette
|
||||
plb
|
||||
|
||||
_TSExit #0;#6
|
||||
|
||||
_TSCopyPicToBG1
|
||||
:ptr equ FirstParam+0
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda BG1DataBank
|
||||
tay
|
||||
lda :ptr+2,s
|
||||
tax
|
||||
lda :ptr,s
|
||||
jsr _CopyPicToBG1
|
||||
|
||||
_TSExit #0;#4
|
||||
|
||||
_TSBindSCBArray
|
||||
:ptr equ FirstParam+0
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :ptr,s
|
||||
tax
|
||||
lda :ptr+2,s
|
||||
jsr _BindSCBArray
|
||||
|
||||
_TSExit #0;#4
|
||||
|
||||
_TSGetBG0TileMapInfo
|
||||
:ptr equ FirstParam+4
|
||||
:height equ FirstParam+2
|
||||
:width equ FirstParam+0
|
||||
_TSEntry
|
||||
|
||||
lda TileMapWidth
|
||||
sta :width,s
|
||||
lda TileMapHeight
|
||||
sta :height,s
|
||||
lda TileMapPtr
|
||||
sta :ptr,s
|
||||
lda TileMapPtr+2
|
||||
sta :ptr+2,s
|
||||
|
||||
_TSExit #0;#0
|
||||
|
||||
|
||||
_TSGetScreenInfo
|
||||
:height equ FirstParam+6
|
||||
:width equ FirstParam+4
|
||||
:y equ FirstParam+2
|
||||
:x equ FirstParam+0
|
||||
_TSEntry
|
||||
|
||||
lda ScreenX0
|
||||
sta :x,s
|
||||
lda ScreenY0
|
||||
sta :y,s
|
||||
lda ScreenWidth
|
||||
sta :width,s
|
||||
lda ScreenHeight
|
||||
sta :height,s
|
||||
|
||||
_TSExit #0;#0
|
||||
|
||||
; SetBG1Origin(x, y)
|
||||
_TSSetBG1Origin
|
||||
:y equ FirstParam
|
||||
:x equ FirstParam+2
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :x,s
|
||||
jsr _SetBG1XPos
|
||||
lda :y,s
|
||||
jsr _SetBG1YPos
|
||||
|
||||
_TSExit #0;#4
|
||||
|
||||
; GetTileAt(x, y)
|
||||
_TSGetTileAt
|
||||
:y equ FirstParam
|
||||
:x equ FirstParam+2
|
||||
:output equ FirstParam+4
|
||||
|
||||
_TSEntry
|
||||
|
||||
; Convert the x, y coordinated to tile store block coordinates
|
||||
lda :x,s
|
||||
tax
|
||||
lda :y,s
|
||||
tay
|
||||
jsr _GetTileAt
|
||||
bcc :ok
|
||||
lda #0
|
||||
bra :out
|
||||
|
||||
; Load the tile at that tile store location
|
||||
|
||||
:ok
|
||||
jsr _GetTileStoreOffset0 ; Get the address of the X,Y tile position
|
||||
tax
|
||||
lda TileStore+TS_TILE_ID,x
|
||||
:out
|
||||
sta :output,s
|
||||
|
||||
_TSExit #0;#4
|
||||
|
||||
; SetBG0TileMapInfo(width, height, ptr)
|
||||
_TSSetBG0TileMapInfo
|
||||
:ptr equ FirstParam+0
|
||||
:height equ FirstParam+4
|
||||
:width equ FirstParam+6
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :width,s
|
||||
sta TileMapWidth
|
||||
lda :height,s
|
||||
sta TileMapHeight
|
||||
lda :ptr,s
|
||||
sta TileMapPtr
|
||||
lda :ptr+2,s
|
||||
sta TileMapPtr+2
|
||||
|
||||
lda #DIRTY_BIT_BG0_REFRESH ; force a refresh of the BG0 on the next Render
|
||||
tsb DirtyBits
|
||||
|
||||
_TSExit #0;#8
|
||||
|
||||
; SetBG1TileMapInfo(width, height, ptr)
|
||||
_TSSetBG1TileMapInfo
|
||||
:ptr equ FirstParam+0
|
||||
:height equ FirstParam+4
|
||||
:width equ FirstParam+6
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :width,s
|
||||
sta BG1TileMapWidth
|
||||
lda :height,s
|
||||
sta BG1TileMapHeight
|
||||
lda :ptr,s
|
||||
sta BG1TileMapPtr
|
||||
lda :ptr+2,s
|
||||
sta TileMapPtr+2
|
||||
|
||||
_TSExit #0;#8
|
||||
|
||||
; AddTimer(numTicks, callback, flags)
|
||||
_TSAddTimer
|
||||
:flags equ FirstParam+0
|
||||
:callback equ FirstParam+2
|
||||
:numTicks equ FirstParam+6
|
||||
:output equ FirstParam+8
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :callback+2,s
|
||||
tax
|
||||
lda :callback,s
|
||||
tay
|
||||
lda :flags,s
|
||||
lsr ; put low bit into carry
|
||||
lda :numTicks,s
|
||||
jsr _AddTimer
|
||||
sta :output,s
|
||||
ldx #0
|
||||
bcc :no_err
|
||||
ldx #NO_TIMERS_AVAILABLE
|
||||
:no_err
|
||||
_TSExit1 #8
|
||||
|
||||
; RemoveTimer(timerId)
|
||||
_TSRemoveTimer
|
||||
:timerId equ FirstParam+0
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :timerId,s
|
||||
jsr _RemoveTimer
|
||||
|
||||
_TSExit #0;#2
|
||||
|
||||
|
||||
; StartScript(timerId)
|
||||
_TSStartScript
|
||||
:scriptAddr equ FirstParam+0
|
||||
:numTicks equ FirstParam+4
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :numTicks,s
|
||||
tay
|
||||
lda :scriptAddr+2,s
|
||||
tax
|
||||
lda :scriptAddr,s
|
||||
jsr _StartScript
|
||||
|
||||
_TSExit #0;#6
|
||||
; SetOverlay(top, bottom, proc)
|
||||
_TSSetOverlay
|
||||
:proc equ FirstParam+0
|
||||
:bottom equ FirstParam+4
|
||||
:top equ FirstParam+6
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda #1
|
||||
sta Overlays
|
||||
lda :top,s
|
||||
sta Overlays+2
|
||||
lda :bottom,s
|
||||
sta Overlays+4
|
||||
lda :proc,s
|
||||
sta Overlays+6
|
||||
lda :proc+2,s
|
||||
sta Overlays+8
|
||||
|
||||
_TSExit #0;#8
|
||||
|
||||
; ClearOverlay()
|
||||
_TSClearOverlay
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda #0
|
||||
sta Overlays
|
||||
|
||||
_TSExit #0;#0
|
||||
|
||||
; GetTileDataAddr()
|
||||
_TSGetTileDataAddr
|
||||
:output equ FirstParam+0
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda #tiledata
|
||||
sta :output,s
|
||||
lda #^tiledata
|
||||
sta :output+2,s
|
||||
|
||||
_TSExit #0;#0
|
||||
|
||||
; FillTileStore(tileId)
|
||||
_TSFillTileStore
|
||||
:tileId equ FirstParam+0
|
||||
|
||||
_TSEntry
|
||||
|
||||
stz tmp0
|
||||
:oloop
|
||||
stz tmp1
|
||||
:iloop
|
||||
ldx tmp1
|
||||
ldy tmp0
|
||||
lda :tileId,s
|
||||
jsr _SetTile
|
||||
|
||||
lda tmp1
|
||||
inc
|
||||
sta tmp1
|
||||
cmp #TILE_STORE_WIDTH
|
||||
bcc :iloop
|
||||
|
||||
lda tmp0
|
||||
inc
|
||||
sta tmp0
|
||||
cmp #TILE_STORE_HEIGHT
|
||||
bcc :oloop
|
||||
|
||||
_TSExit #0;#2
|
||||
|
||||
; _TSRefresh()
|
||||
_TSRefresh
|
||||
_TSEntry
|
||||
|
||||
ldx #TILE_STORE_SIZE-2
|
||||
:loop jsr _PushDirtyTileX
|
||||
dex
|
||||
dex
|
||||
bpl :loop
|
||||
|
||||
_TSExit #0;#0
|
||||
|
||||
; Insert the GTE code
|
||||
|
||||
put Math.s
|
||||
put CoreImpl.s
|
||||
put Memory.s
|
||||
put Timer.s
|
||||
put Script.s
|
||||
put TileMap.s
|
||||
put Graphics.s
|
||||
put Tiles.s
|
||||
put Sprite.s
|
||||
put Sprite2.s
|
||||
put SpriteRender.s
|
||||
put Render.s
|
||||
put render/Render.s
|
||||
put render/Fast.s
|
||||
put render/Slow.s
|
||||
put render/Dynamic.s
|
||||
put render/TwoLayer.s
|
||||
put render/Sprite1.s
|
||||
put render/Sprite2.s
|
||||
put tiles/DirtyTileQueue.s
|
||||
put blitter/SCB.s
|
||||
put blitter/Horz.s
|
||||
put blitter/Vert.s
|
||||
put blitter/BG0.s
|
||||
put blitter/BG1.s
|
||||
put blitter/Template.s
|
||||
put blitter/TemplateUtils.s
|
||||
put blitter/Blitter.s
|
||||
put blitter/TileProcs.s
|
||||
put blitter/Tiles00000.s
|
||||
; put blitter/Tiles.s
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Tool160=Type(BA),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
|
@ -1,4 +1,4 @@
|
|||
; Support routinges for the primary background
|
||||
; Support routines for the primary background
|
||||
_InitBG0
|
||||
lda #DIRTY_BIT_BG0_X+DIRTY_BIT_BG0_Y
|
||||
tsb DirtyBits
|
||||
|
@ -8,14 +8,6 @@ _InitBG0
|
|||
;
|
||||
; A=low word of picture address
|
||||
; X=high word of pixture address
|
||||
CopyBinToField ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyBinToField
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyBinToField
|
||||
:srcptr equ tmp0
|
||||
:line_cnt equ tmp2
|
||||
|
@ -222,14 +214,6 @@ _CopyBinToField
|
|||
; X=high workd of pixture address
|
||||
;
|
||||
; Picture must be within one bank
|
||||
CopyPicToField ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyPicToField
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyPicToField
|
||||
:srcptr equ tmp0
|
||||
:line_cnt equ tmp2
|
||||
|
|
|
@ -4,20 +4,11 @@ _InitBG1
|
|||
jsr _ApplyBG1XPos
|
||||
rts
|
||||
|
||||
|
||||
; Copy a binary image data file into BG1. Assumes the file is the correct size (328 x 208)
|
||||
;
|
||||
; A=low word of picture address
|
||||
; X=high word of pixture address
|
||||
; Y=high word of BG1 bank
|
||||
CopyBinToBG1 ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyBinToBG1
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyBinToBG1
|
||||
:src_width equ tmp6
|
||||
:src_height equ tmp7
|
||||
|
@ -40,14 +31,6 @@ _CopyBinToBG1
|
|||
; A=low word of picture address
|
||||
; X=high word of pixture address
|
||||
; Y=high word of BG1 bank
|
||||
CopyPicToBG1 ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyPicToBG1
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyPicToBG1
|
||||
:src_width equ tmp6
|
||||
:src_height equ tmp7
|
||||
|
@ -193,59 +176,6 @@ _ApplyBG1XPos
|
|||
pld
|
||||
rts
|
||||
|
||||
ANGLEBNK ext
|
||||
ApplyBG1XPosAngle ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _ApplyBG1XPosAngle
|
||||
plb
|
||||
rtl
|
||||
|
||||
_ApplyBG1XPosAngle
|
||||
; phy
|
||||
|
||||
; lda BG1StartX
|
||||
; jsr Mod164
|
||||
; sta BG1StartXMod164
|
||||
|
||||
; lda #162
|
||||
; sec
|
||||
; sbc StartXMod164
|
||||
; bpl *+6
|
||||
; clc
|
||||
; adc #164
|
||||
; clc
|
||||
; adc BG1StartXMod164
|
||||
; cmp #164
|
||||
; bcc *+5
|
||||
; sbc #164
|
||||
|
||||
; clc
|
||||
; adc 1,s
|
||||
; tay ; cache the value
|
||||
|
||||
; pla ; pop the value
|
||||
phd ; save the direct page because we are going to switch to the
|
||||
lda BlitterDP ; blitter direct page space and fill in the addresses
|
||||
tcd
|
||||
|
||||
lda #^ANGLEBNK
|
||||
sta $fe
|
||||
sty $fc ; Store in the new direct page
|
||||
ldy #162
|
||||
tyx
|
||||
:loop
|
||||
lda [$fc],y
|
||||
sta 00,x ; store the value
|
||||
dey
|
||||
dey
|
||||
dex
|
||||
dex
|
||||
bpl :loop
|
||||
pld
|
||||
rts
|
||||
|
||||
_ClearBG1Buffer
|
||||
phb
|
||||
pha
|
||||
|
@ -266,88 +196,6 @@ _ClearBG1Buffer
|
|||
|
||||
plb
|
||||
rts
|
||||
ApplyBG1YPosAngle ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _ApplyBG1YPosAngle
|
||||
plb
|
||||
rtl
|
||||
|
||||
_ApplyBG1YPosAngle
|
||||
:virt_line equ tmp0
|
||||
:lines_left equ tmp1
|
||||
:draw_count equ tmp2
|
||||
:ytbl_idx equ tmp3
|
||||
:angle_tbl equ tmp4
|
||||
|
||||
sty :angle_tbl
|
||||
|
||||
lda BG1StartY
|
||||
jsr Mod208
|
||||
sta BG1StartYMod208
|
||||
sta :ytbl_idx ; Start copying from the first entry in the table
|
||||
|
||||
lda StartYMod208 ; This is the base line of the virtual screen
|
||||
sta :virt_line ; Keep track of it
|
||||
|
||||
lda ScreenHeight
|
||||
sta :lines_left
|
||||
|
||||
:loop
|
||||
lda :virt_line
|
||||
asl
|
||||
tax
|
||||
ldal BTableLow,x ; Get the address of the first code field line
|
||||
tay
|
||||
|
||||
sep #$20
|
||||
ldal BTableHigh,x
|
||||
pha ; push the bank on the stack
|
||||
plb
|
||||
rep #$20
|
||||
|
||||
lda :virt_line
|
||||
and #$000F
|
||||
eor #$FFFF
|
||||
inc
|
||||
clc
|
||||
adc #16
|
||||
min :lines_left
|
||||
|
||||
sta :draw_count ; Do this many lines
|
||||
asl
|
||||
tax
|
||||
|
||||
lda :ytbl_idx ; Read from this location (duplicate every 4 lines)
|
||||
lsr
|
||||
lsr
|
||||
asl
|
||||
clc
|
||||
adc :angle_tbl
|
||||
sec
|
||||
sbc #ANGLEBNK
|
||||
jsr CopyAngleYTableToBG1Addr ; or CopyBG1YTableToBG1Addr2
|
||||
|
||||
lda :virt_line ; advance to the virtual line after the segment we just
|
||||
clc ; filled in
|
||||
adc :draw_count
|
||||
sta :virt_line
|
||||
|
||||
lda :ytbl_idx ; advance the index into the YTable
|
||||
adc :draw_count
|
||||
sta :ytbl_idx
|
||||
|
||||
lda :lines_left ; subtract the number of lines we just completed
|
||||
sec
|
||||
sbc :draw_count
|
||||
sta :lines_left
|
||||
|
||||
jne :loop
|
||||
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
; Everytime either BG1 or BG0 Y-position changes, we have to update the Y-register
|
||||
; value in all of the code fields (within the visible screen)
|
||||
|
@ -357,6 +205,8 @@ _ApplyBG1YPos
|
|||
:draw_count equ tmp2
|
||||
:ytbl_idx equ tmp3
|
||||
|
||||
phb ; Save the bank
|
||||
|
||||
lda BG1StartY
|
||||
jsr Mod208
|
||||
sta BG1StartYMod208
|
||||
|
@ -413,7 +263,6 @@ _ApplyBG1YPos
|
|||
|
||||
jne :loop
|
||||
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
|
@ -494,97 +343,6 @@ CopyBG1YTableToBG1Addr
|
|||
sta: BG1_ADDR+$0000,y
|
||||
:none rts
|
||||
|
||||
; Unrolled copy routine to move y_angle entries into BG1_ADDR position with an additional
|
||||
; shift. This has to be split into two
|
||||
;
|
||||
; A = index into the array (x2)
|
||||
; Y = starting line * $1000
|
||||
; X = number of lines (x2)
|
||||
CopyAngleYTableToBG1Addr
|
||||
phx
|
||||
phb
|
||||
|
||||
phk ; restore access to this bank
|
||||
plb
|
||||
jsr SaveBG1AngleValues
|
||||
|
||||
plb
|
||||
plx ; x is used directly in this routine
|
||||
jsr ApplyBG1OffsetValues
|
||||
rts
|
||||
|
||||
SaveBG1AngleValues
|
||||
jmp (:tbl,x)
|
||||
:tbl da :none
|
||||
da :do01,:do02,:do03,:do04
|
||||
da :do05,:do06,:do07,:do08
|
||||
da :do09,:do10,:do11,:do12
|
||||
da :do13,:do14,:do15,:do16
|
||||
:do15 tax
|
||||
bra :x15
|
||||
:do14 tax
|
||||
bra :x14
|
||||
:do13 tax
|
||||
bra :x13
|
||||
:do12 tax
|
||||
bra :x12
|
||||
:do11 tax
|
||||
bra :x11
|
||||
:do10 tax
|
||||
bra :x10
|
||||
:do09 tax
|
||||
bra :x09
|
||||
:do08 tax
|
||||
bra :x08
|
||||
:do16 tax
|
||||
ldal ANGLEBNK+06,x
|
||||
sta BG1YCache+30
|
||||
:x15 ldal ANGLEBNK+06,x
|
||||
sta BG1YCache+28
|
||||
:x14 ldal ANGLEBNK+06,x
|
||||
sta BG1YCache+26
|
||||
:x13 ldal ANGLEBNK+06,x
|
||||
sta BG1YCache+24
|
||||
:x12 ldal ANGLEBNK+04,x
|
||||
sta BG1YCache+22
|
||||
:x11 ldal ANGLEBNK+04,x
|
||||
sta BG1YCache+20
|
||||
:x10 ldal ANGLEBNK+04,x
|
||||
sta BG1YCache+18
|
||||
:x09 ldal ANGLEBNK+04,x
|
||||
sta BG1YCache+16
|
||||
:x08 ldal ANGLEBNK+02,x
|
||||
sta BG1YCache+14
|
||||
:x07 ldal ANGLEBNK+02,x
|
||||
sta BG1YCache+12
|
||||
:x06 ldal ANGLEBNK+02,x
|
||||
sta BG1YCache+10
|
||||
:x05 ldal ANGLEBNK+02,x
|
||||
sta BG1YCache+08
|
||||
:x04 ldal ANGLEBNK+00,x
|
||||
sta BG1YCache+06
|
||||
:x03 ldal ANGLEBNK+00,x
|
||||
sta BG1YCache+04
|
||||
:x02 ldal ANGLEBNK+00,x
|
||||
sta BG1YCache+02
|
||||
:x01 ldal ANGLEBNK+00,x
|
||||
sta BG1YCache+00
|
||||
:none rts
|
||||
:do07 tax
|
||||
bra :x07
|
||||
:do06 tax
|
||||
bra :x06
|
||||
:do05 tax
|
||||
bra :x05
|
||||
:do04 tax
|
||||
bra :x04
|
||||
:do03 tax
|
||||
bra :x03
|
||||
:do02 tax
|
||||
bra :x02
|
||||
:do01 tax
|
||||
bra :x01
|
||||
|
||||
; Unrolled copy routine to move BG1YTable entries into BG1_ADDR position with an additional
|
||||
; shift. This has to be split into two
|
||||
;
|
||||
|
@ -596,16 +354,14 @@ CopyBG1YTableToBG1Addr2
|
|||
phx
|
||||
phb
|
||||
|
||||
phk ; restore access to this bank
|
||||
plb
|
||||
jsr _SetDataBank ; restore access to this bank
|
||||
ldy BG1OffsetIndex ; Get the offset and save the values
|
||||
jsr SaveBG1OffsetValues
|
||||
|
||||
plb
|
||||
plx ; x is used directly in this routine
|
||||
ply
|
||||
jsr ApplyBG1OffsetValues
|
||||
rts
|
||||
jmp ApplyBG1OffsetValues
|
||||
|
||||
SaveBG1OffsetValues
|
||||
jmp (:tbl,x)
|
||||
|
@ -738,7 +494,3 @@ ApplyBG1OffsetValues
|
|||
:none rts
|
||||
|
||||
BG1YCache ds 32
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ _BltRange
|
|||
|
||||
dey
|
||||
tya ; Get the address of the line that we want to return from
|
||||
adc StartY ; and create a pointer to it
|
||||
adc StartYMod208 ; and create a pointer to it
|
||||
asl
|
||||
tay
|
||||
lda BTableLow,y
|
||||
|
@ -27,16 +27,16 @@ _BltRange
|
|||
sta :exit_ptr+2
|
||||
|
||||
txa ; get the first line (0 - 199)
|
||||
adc StartY ; add in the virtual offset (0, 207) -- max value of 406
|
||||
adc StartYMod208 ; add in the virtual offset (0, 207) -- max value of 406
|
||||
asl
|
||||
tax ; this is the offset into the blitter table
|
||||
|
||||
sep #$20 ; 8-bit Acc
|
||||
lda BTableHigh,x ; patch in the bank
|
||||
sta blt_entry+3
|
||||
stal blt_entry+3
|
||||
|
||||
lda BTableLow+1,x ; patch in the page
|
||||
sta blt_entry+2
|
||||
stal blt_entry+2
|
||||
|
||||
; The way we patch the exit code is subtle, but very fast. The CODE_EXIT offset points to
|
||||
; an JMP/JML instruction that transitions to the next line after all of the code has been
|
||||
|
@ -51,6 +51,11 @@ _BltRange
|
|||
lda #FULL_RETURN ; this is the offset of the return code
|
||||
sta [:exit_ptr],y ; patch out the low byte of the JMP/JML
|
||||
|
||||
; lda StartYMod208
|
||||
; cmp #63
|
||||
; bne *+4
|
||||
; brk $40
|
||||
|
||||
; Now we need to set up the Bank, Stack Pointer and Direct Page registers for calling into
|
||||
; the code field
|
||||
|
||||
|
@ -59,7 +64,7 @@ _BltRange
|
|||
; beq :primary
|
||||
; lda BG1AltBank
|
||||
; bra :alt
|
||||
:primary lda BG1DataBank
|
||||
:primary lda BG1DataBank ; This is $00 if the TWO_LAYER bit of EngineMode is not set
|
||||
:alt
|
||||
pha
|
||||
plb
|
||||
|
|
|
@ -3,33 +3,6 @@
|
|||
; when the virtual X-position of the play field changes.
|
||||
|
||||
|
||||
; SetBG0XPos
|
||||
;
|
||||
; Set the virtual horizontal position of the primary background layer. In addition to
|
||||
; updating the direct page state locations, this routine needs to preserve the original
|
||||
; value as well. This is a bit subtle, because if this routine is called multiple times
|
||||
; with different values, we need to make sure the *original* value is preserved and not
|
||||
; continuously overwrite it.
|
||||
;
|
||||
; We assume that there is a clean code field in this routine
|
||||
SetBG0XPos ENT
|
||||
jsr _SetBG0XPos
|
||||
rtl
|
||||
|
||||
_SetBG0XPos
|
||||
cmp StartX
|
||||
beq :out ; Easy, if nothing changed, then nothing changes
|
||||
|
||||
ldx StartX ; Load the old value (but don't save it yet)
|
||||
sta StartX ; Save the new position
|
||||
|
||||
lda #DIRTY_BIT_BG0_X
|
||||
tsb DirtyBits ; Check if the value is already dirty, if so exit
|
||||
bne :out ; without overwriting the original value
|
||||
|
||||
stx OldStartX ; First change, so preserve the value
|
||||
:out rts
|
||||
|
||||
; Simple function that restores the saved opcode that are stashed in _applyBG0Xpos. It is
|
||||
; very important that opcodes are restored before new ones are inserted, because there is
|
||||
; only one, fixed storage location and old values will be overwritten if operations are not
|
||||
|
@ -48,6 +21,8 @@ _RestoreBG0Opcodes
|
|||
:draw_count_x2 equ tmp3
|
||||
:exit_offset equ tmp4
|
||||
|
||||
phb ; Save data bank
|
||||
|
||||
asl
|
||||
sta :virt_line_x2 ; Keep track of it
|
||||
|
||||
|
@ -57,7 +32,6 @@ _RestoreBG0Opcodes
|
|||
|
||||
lda LastPatchOffset ; If zero, there are no saved opcodes
|
||||
sta :exit_offset
|
||||
beq :loop
|
||||
|
||||
:loop
|
||||
ldx :virt_line_x2
|
||||
|
@ -102,7 +76,6 @@ _RestoreBG0Opcodes
|
|||
stz LastPatchOffset ; Clear the value once completed
|
||||
|
||||
:out
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
|
@ -306,6 +279,7 @@ _ApplyBG0XPos
|
|||
; 2. Writes the BRA instruction to exit the code field
|
||||
; 3. Writes the JMP entry point to enter the code field
|
||||
|
||||
phb ; Save the existing bank
|
||||
:loop
|
||||
lda :virt_line
|
||||
asl ; This will clear the carry bit
|
||||
|
@ -380,7 +354,7 @@ _ApplyBG0XPos
|
|||
ldx :draw_count_x2
|
||||
ldy :base_address ; Y-register is preserved, this can be removed
|
||||
pei :exit_address
|
||||
jmp :SaveHighOperand ; Only used once, so "inline" it
|
||||
jmp :SaveHighOperand ; Only used once, so "inline" it
|
||||
:save_high_op_rtn
|
||||
|
||||
:not_odd
|
||||
|
@ -401,7 +375,6 @@ _ApplyBG0XPos
|
|||
|
||||
jne :loop
|
||||
|
||||
phk
|
||||
plb
|
||||
rts
|
||||
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
_PEISlam
|
||||
lda ScreenWidth
|
||||
dec
|
||||
sta :screen_width_1 ; save the width-1 outside of the direct page
|
||||
stal :screen_width_1 ; save the width-1 outside of the direct page
|
||||
|
||||
lda #:pei_end ; patch the PEI entry address
|
||||
and #$FFFE ; should always be even, but....
|
||||
sec
|
||||
sbc ScreenWidth
|
||||
sta :inner+1
|
||||
stal :inner+1
|
||||
|
||||
phx
|
||||
tya
|
||||
|
@ -43,7 +43,7 @@ _PEISlam
|
|||
tcd ; screen address to the direct page register
|
||||
|
||||
tsc
|
||||
sta :stk_save ; save the stack pointer to restore later
|
||||
stal :stk_save ; save the stack pointer to restore later
|
||||
|
||||
clc ; clear before the loop -- nothing in the loop affect the carry bit
|
||||
brl :outer ; hop into the entry point.
|
||||
|
@ -57,7 +57,7 @@ _PEISlam
|
|||
tdc ; Move to the next line
|
||||
adc #160
|
||||
tcd
|
||||
adc :screen_width_1
|
||||
adcl :screen_width_1
|
||||
tcs
|
||||
|
||||
dey ; decrement the total counter, if zero then we're done
|
||||
|
@ -79,7 +79,7 @@ _PEISlam
|
|||
:restore
|
||||
tsx ; save the current stack
|
||||
_R0W0 ; restore the execution environment and
|
||||
lda :stk_save ; give a few cycles to catch some interrupts
|
||||
ldal :stk_save ; give a few cycles to catch some interrupts
|
||||
tcs
|
||||
cli ; fall through here -- saves a BRA instruction
|
||||
|
||||
|
@ -92,7 +92,7 @@ _PEISlam
|
|||
|
||||
:exit
|
||||
_R0W0
|
||||
lda :stk_save
|
||||
ldal :stk_save
|
||||
tcs
|
||||
cli
|
||||
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
; Support rotating the BG1 graphics by leveraging the fact that a rotation function can be decomposed
|
||||
; into an addition of two function parametertized by the angle of rotation: pixel = *(f(x, a) + f(y, a))
|
||||
;
|
||||
; The pre-build a number of rotation tables and then populate the direct page values and Y-register values
|
||||
; for each line of the blitter, such that a single lda (00),y instruction fetched the appropriate data
|
||||
;
|
||||
; This is about as fast of a rotation as we can do.
|
||||
;
|
||||
; When possible, off-screen locations are calculate to produce an address of $FFFE, so that the last two bytes
|
||||
; of the BG1 data buffer provides the "fill value".
|
||||
|
||||
ANGLEBNK ext
|
||||
_ApplyBG1XPosAngle
|
||||
; phy
|
||||
|
||||
; lda BG1StartX
|
||||
; jsr Mod164
|
||||
; sta BG1StartXMod164
|
||||
|
||||
; lda #162
|
||||
; sec
|
||||
; sbc StartXMod164
|
||||
; bpl *+6
|
||||
; clc
|
||||
; adc #164
|
||||
; clc
|
||||
; adc BG1StartXMod164
|
||||
; cmp #164
|
||||
; bcc *+5
|
||||
; sbc #164
|
||||
|
||||
; clc
|
||||
; adc 1,s
|
||||
; tay ; cache the value
|
||||
|
||||
; pla ; pop the value
|
||||
phd ; save the direct page because we are going to switch to the
|
||||
lda BlitterDP ; blitter direct page space and fill in the addresses
|
||||
tcd
|
||||
|
||||
lda #^ANGLEBNK
|
||||
sta $fe
|
||||
sty $fc ; Store in the new direct page
|
||||
ldy #162
|
||||
tyx
|
||||
:loop
|
||||
lda [$fc],y
|
||||
sta 00,x ; store the value
|
||||
dey
|
||||
dey
|
||||
dex
|
||||
dex
|
||||
bpl :loop
|
||||
pld
|
||||
rts
|
||||
|
||||
_ApplyBG1YPosAngle
|
||||
:virt_line equ tmp0
|
||||
:lines_left equ tmp1
|
||||
:draw_count equ tmp2
|
||||
:ytbl_idx equ tmp3
|
||||
:angle_tbl equ tmp4
|
||||
|
||||
sty :angle_tbl
|
||||
|
||||
lda BG1StartY
|
||||
jsr Mod208
|
||||
sta BG1StartYMod208
|
||||
sta :ytbl_idx ; Start copying from the first entry in the table
|
||||
|
||||
lda StartYMod208 ; This is the base line of the virtual screen
|
||||
sta :virt_line ; Keep track of it
|
||||
|
||||
lda ScreenHeight
|
||||
sta :lines_left
|
||||
|
||||
phb
|
||||
:loop
|
||||
lda :virt_line
|
||||
asl
|
||||
tax
|
||||
ldal BTableLow,x ; Get the address of the first code field line
|
||||
tay
|
||||
|
||||
sep #$20
|
||||
ldal BTableHigh,x
|
||||
pha ; push the bank on the stack
|
||||
plb
|
||||
rep #$20
|
||||
|
||||
lda :virt_line
|
||||
and #$000F
|
||||
eor #$FFFF
|
||||
inc
|
||||
clc
|
||||
adc #16
|
||||
min :lines_left
|
||||
|
||||
sta :draw_count ; Do this many lines
|
||||
asl
|
||||
tax
|
||||
|
||||
lda :ytbl_idx ; Read from this location (duplicate every 4 lines)
|
||||
lsr
|
||||
lsr
|
||||
asl
|
||||
clc
|
||||
adc :angle_tbl
|
||||
sec
|
||||
sbc #ANGLEBNK
|
||||
jsr CopyAngleYTableToBG1Addr ; or CopyBG1YTableToBG1Addr2
|
||||
|
||||
lda :virt_line ; advance to the virtual line after the segment we just
|
||||
clc ; filled in
|
||||
adc :draw_count
|
||||
sta :virt_line
|
||||
|
||||
lda :ytbl_idx ; advance the index into the YTable
|
||||
adc :draw_count
|
||||
sta :ytbl_idx
|
||||
|
||||
lda :lines_left ; subtract the number of lines we just completed
|
||||
sec
|
||||
sbc :draw_count
|
||||
sta :lines_left
|
||||
|
||||
jne :loop
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; Unrolled copy routine to move y_angle entries into BG1_ADDR position with an additional
|
||||
; shift. This has to be split into two
|
||||
;
|
||||
; A = index into the array (x2)
|
||||
; Y = starting line * $1000
|
||||
; X = number of lines (x2)
|
||||
CopyAngleYTableToBG1Addr
|
||||
phx
|
||||
phb
|
||||
|
||||
|
||||
jsr _SetDataBank ; restore access to this bank
|
||||
jsr SaveBG1AngleValues
|
||||
|
||||
plb
|
||||
plx ; x is used directly in this routine
|
||||
jmp ApplyBG1OffsetValues
|
||||
|
||||
SaveBG1AngleValues
|
||||
jmp (:tbl,x)
|
||||
:tbl da :none
|
||||
da :do01,:do02,:do03,:do04
|
||||
da :do05,:do06,:do07,:do08
|
||||
da :do09,:do10,:do11,:do12
|
||||
da :do13,:do14,:do15,:do16
|
||||
:do15 tax
|
||||
bra :x15
|
||||
:do14 tax
|
||||
bra :x14
|
||||
:do13 tax
|
||||
bra :x13
|
||||
:do12 tax
|
||||
bra :x12
|
||||
:do11 tax
|
||||
bra :x11
|
||||
:do10 tax
|
||||
bra :x10
|
||||
:do09 tax
|
||||
bra :x09
|
||||
:do08 tax
|
||||
bra :x08
|
||||
:do16 tax
|
||||
ldal ANGLEBNK+06,x
|
||||
sta BG1YCache+30
|
||||
:x15 ldal ANGLEBNK+06,x
|
||||
sta BG1YCache+28
|
||||
:x14 ldal ANGLEBNK+06,x
|
||||
sta BG1YCache+26
|
||||
:x13 ldal ANGLEBNK+06,x
|
||||
sta BG1YCache+24
|
||||
:x12 ldal ANGLEBNK+04,x
|
||||
sta BG1YCache+22
|
||||
:x11 ldal ANGLEBNK+04,x
|
||||
sta BG1YCache+20
|
||||
:x10 ldal ANGLEBNK+04,x
|
||||
sta BG1YCache+18
|
||||
:x09 ldal ANGLEBNK+04,x
|
||||
sta BG1YCache+16
|
||||
:x08 ldal ANGLEBNK+02,x
|
||||
sta BG1YCache+14
|
||||
:x07 ldal ANGLEBNK+02,x
|
||||
sta BG1YCache+12
|
||||
:x06 ldal ANGLEBNK+02,x
|
||||
sta BG1YCache+10
|
||||
:x05 ldal ANGLEBNK+02,x
|
||||
sta BG1YCache+08
|
||||
:x04 ldal ANGLEBNK+00,x
|
||||
sta BG1YCache+06
|
||||
:x03 ldal ANGLEBNK+00,x
|
||||
sta BG1YCache+04
|
||||
:x02 ldal ANGLEBNK+00,x
|
||||
sta BG1YCache+02
|
||||
:x01 ldal ANGLEBNK+00,x
|
||||
sta BG1YCache+00
|
||||
:none rts
|
||||
:do07 tax
|
||||
bra :x07
|
||||
:do06 tax
|
||||
bra :x06
|
||||
:do05 tax
|
||||
bra :x05
|
||||
:do04 tax
|
||||
bra :x04
|
||||
:do03 tax
|
||||
bra :x03
|
||||
:do02 tax
|
||||
bra :x02
|
||||
:do01 tax
|
||||
bra :x01
|
|
@ -9,15 +9,7 @@
|
|||
; on the SHR screen or the current value of StartY
|
||||
;
|
||||
; This could be made faster by forcing a SCB array to be copied into PEAs ahead of time, but this
|
||||
; is a bit more flexible
|
||||
BltSCB ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _BltSCB
|
||||
plb
|
||||
rtl
|
||||
|
||||
; is a bit more flexible
|
||||
_BltSCBOut
|
||||
rts
|
||||
_BltSCB
|
||||
|
@ -36,10 +28,10 @@ _BltSCB
|
|||
|
||||
lda SCBArrayPtr+2
|
||||
bpl :bind_to_bg0
|
||||
lda BG1StartY
|
||||
lda BG1StartYMod208
|
||||
bra :bind_to_bg1
|
||||
:bind_to_bg0
|
||||
lda StartY
|
||||
lda StartYMod208
|
||||
:bind_to_bg1
|
||||
clc
|
||||
adc SCBArrayPtr
|
||||
|
@ -52,7 +44,7 @@ _BltSCB
|
|||
inc
|
||||
clc
|
||||
adc #:scb_end
|
||||
sta :entry+1
|
||||
stal :entry+1
|
||||
|
||||
lda ScreenY1 ; Get the SCB address to put into the stack register
|
||||
dec
|
||||
|
@ -82,13 +74,7 @@ _BltSCB
|
|||
plb ; restore the bank
|
||||
rts
|
||||
|
||||
|
||||
; Quick helper to set the pointer (X = low word, A = high work)
|
||||
SetSCBArray ENT
|
||||
jsr _SetSCBArray
|
||||
rtl
|
||||
|
||||
_SetSCBArray
|
||||
_BindSCBArray
|
||||
stx SCBArrayPtr
|
||||
sta SCBArrayPtr+2
|
||||
rts
|
||||
|
|
|
@ -42,7 +42,7 @@ PagePatches da {long_0-base+2}
|
|||
|
||||
]index equ 0
|
||||
lup 82 ; All the snippet addresses. The two JMP
|
||||
da {snippets-base+{]index*32}+31} ; instructino are at the end of each of
|
||||
da {snippets-base+{]index*32}+31} ; instructions are at the end of each of
|
||||
da {snippets-base+{]index*32}+28} ; the 32-byte buffers
|
||||
]index equ ]index+1
|
||||
--^
|
||||
|
@ -58,538 +58,6 @@ BankPatches da {long_0-base+3}
|
|||
da {long_6-base+3}
|
||||
BankPatchNum equ *-BankPatches
|
||||
|
||||
; Set the physical location of the virtual screen on the physical screen. The
|
||||
; screen size must by a multiple of 8
|
||||
;
|
||||
; A = XXYY where XX is the left edge [0, 159] and YY is the top edge [0, 199]
|
||||
; X = width (in bytes)
|
||||
; Y = height (in lines)
|
||||
;
|
||||
; This subroutine stores the screen positions in the direct page space and fills
|
||||
; in the double-length ScreenAddrR table that holds the address of the right edge
|
||||
; of the playfield. This table is used to set addresses in the code banks when the
|
||||
; virtual origin is changed.
|
||||
;
|
||||
; We are not concerned about the raw performance of this function because it should
|
||||
; usually only be executed once during app initialization. It doesn't get called
|
||||
; with any significant frequency.
|
||||
|
||||
SetScreenRect sty ScreenHeight ; Save the screen height and width
|
||||
stx ScreenWidth
|
||||
|
||||
tax ; Temp save of the accumulator
|
||||
and #$00FF
|
||||
sta ScreenY0
|
||||
clc
|
||||
adc ScreenHeight
|
||||
sta ScreenY1
|
||||
|
||||
txa ; Restore the accumulator
|
||||
xba
|
||||
and #$00FF
|
||||
sta ScreenX0
|
||||
clc
|
||||
adc ScreenWidth
|
||||
sta ScreenX1
|
||||
|
||||
lda ScreenHeight ; Divide the height in scanlines by 8 to get the number tiles
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
sta ScreenTileHeight
|
||||
|
||||
lda ScreenWidth ; Divide width in bytes by 4 to get the number of tiles
|
||||
lsr
|
||||
lsr
|
||||
sta ScreenTileWidth
|
||||
|
||||
lda ScreenY0 ; Calculate the address of the first byte
|
||||
asl ; of the right side of the playfield
|
||||
tax
|
||||
lda ScreenAddr,x ; This is the address for the left edge of the physical screen
|
||||
clc
|
||||
adc ScreenX1
|
||||
dec
|
||||
pha ; Save for second loop
|
||||
|
||||
ldx #0
|
||||
ldy ScreenHeight
|
||||
jsr :loop
|
||||
pla ; Reset the address and continue filling in the
|
||||
ldy ScreenHeight ; second half of the table
|
||||
:loop clc
|
||||
sta RTable,x
|
||||
adc #160
|
||||
inx
|
||||
inx
|
||||
dey
|
||||
bne :loop
|
||||
|
||||
; Calculate the screen locations for each tile corner
|
||||
|
||||
lda ScreenY0 ; Calculate the address of the first byte
|
||||
asl ; of the right side of the playfield
|
||||
tax
|
||||
lda ScreenAddr,x ; This is the address for the left edge of the physical screen
|
||||
clc
|
||||
adc ScreenX0
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
:tsloop
|
||||
stal TileStore+TS_SCREEN_ADDR,x
|
||||
|
||||
clc
|
||||
adc #4 ; Go to the next tile
|
||||
|
||||
iny
|
||||
cpy #41 ; If we've done 41 columns, move to the next line
|
||||
bcc :nohop
|
||||
ldy #0
|
||||
clc
|
||||
adc #{8*160}-{4*41}
|
||||
:nohop
|
||||
|
||||
inx
|
||||
inx
|
||||
cpx #TILE_STORE_SIZE-2
|
||||
bcc :tsloop
|
||||
|
||||
; Return
|
||||
rts
|
||||
|
||||
; Generalized routine that calculates the on-screen address of the tiles and takes the
|
||||
; StartX and StartY values into consideration. This routine really exists to support
|
||||
; the dirty tile rendering mode and the tiles *must* be aligned with the playfield.
|
||||
; That is, StartX % 4 == 0 and StartY % 8 == 0. If these conditions are not met, then
|
||||
; screen will not render correctly.
|
||||
_RecalcTileScreenAddrs
|
||||
NextColPtr equ tmp0
|
||||
RowAddrPtr equ tmp1
|
||||
OnScreenAddr equ tmp2
|
||||
Counter equ tmp3
|
||||
|
||||
jsr _OriginToTileStore ; Get the (col,row) of the tile in the upper-left corner of the playfield
|
||||
|
||||
; Manually add the offsets to the NextCol and TileStoreYTable array address and put in a direct page
|
||||
; location so we can free up the registers.
|
||||
|
||||
clc
|
||||
txa
|
||||
adc #NextCol
|
||||
sta NextColPtr
|
||||
|
||||
tya
|
||||
adc #TileStoreYTable
|
||||
sta RowAddrPtr
|
||||
|
||||
; Calculate the on-screen address of the upper-left corner of the playfiled
|
||||
|
||||
lda ScreenY0 ; Calculate the address of the first byte
|
||||
asl ; of the right side of the playfield
|
||||
tax
|
||||
lda ScreenAddr,x ; This is the address for the left edge of the physical screen
|
||||
clc
|
||||
adc ScreenX0
|
||||
sta OnScreenAddr
|
||||
|
||||
; Now, loop through the tile store
|
||||
|
||||
lda #MAX_TILES
|
||||
sta Counter
|
||||
ldy #0
|
||||
:tsloop
|
||||
lda (NextColPtr),y ; Need to recalculate each time since the wrap-around could
|
||||
clc ; happen anywhere
|
||||
adc (RowAddrPtr) ;
|
||||
tax ; NOTE: Try to rework to use new TileStore2DLookup array
|
||||
|
||||
lda OnScreenAddr
|
||||
stal TileStore+TS_SCREEN_ADDR,x
|
||||
|
||||
clc
|
||||
adc #4 ; Go to the next tile
|
||||
|
||||
iny
|
||||
iny
|
||||
cpy #2*41 ; If we've done 41 columns, move to the next line
|
||||
bcc :nohop
|
||||
|
||||
inc RowAddrPtr ; Advance the row address (with wrap-around)
|
||||
inc RowAddrPtr
|
||||
ldy #0 ; Reset the column counter
|
||||
clc
|
||||
adc #{8*160}-{4*41}
|
||||
:nohop
|
||||
sta OnScreenAddr ; Save the updated on-screen address
|
||||
dec Counter
|
||||
bne :tsloop
|
||||
|
||||
rts
|
||||
|
||||
; Clear the SHR screen and then infill the defined field
|
||||
FillScreen lda #0
|
||||
jsr _ClearToColor
|
||||
|
||||
ldy ScreenY0
|
||||
:yloop
|
||||
tya
|
||||
asl a
|
||||
tax
|
||||
lda ScreenAddr,x
|
||||
clc
|
||||
adc ScreenX0
|
||||
tax
|
||||
phy
|
||||
|
||||
lda ScreenWidth
|
||||
lsr
|
||||
tay
|
||||
lda #$FFFF
|
||||
:xloop stal $E10000,x ; X is the absolute address
|
||||
inx
|
||||
inx
|
||||
dey
|
||||
bne :xloop
|
||||
|
||||
ply
|
||||
iny
|
||||
cpy ScreenY1
|
||||
bcc :yloop
|
||||
rts
|
||||
|
||||
; Special subroutine to divide the accumulator by 164 and return remainder in the Accumulator
|
||||
;
|
||||
; 164 = $A4 = 1010_0100
|
||||
Mod164 cmp #%1010010000000000
|
||||
bcc *+5
|
||||
sbc #%1010010000000000
|
||||
|
||||
cmp #%0101001000000000
|
||||
bcc *+5
|
||||
sbc #%0101001000000000
|
||||
|
||||
cmp #%0010100100000000
|
||||
bcc *+5
|
||||
sbc #%0010100100000000
|
||||
|
||||
cmp #%0001010010000000
|
||||
bcc *+5
|
||||
sbc #%0001010010000000
|
||||
|
||||
cmp #%0000101001000000
|
||||
bcc *+5
|
||||
sbc #%0000101001000000
|
||||
|
||||
cmp #%0000010100100000
|
||||
bcc *+5
|
||||
sbc #%0000010100100000
|
||||
|
||||
cmp #%0000001010010000
|
||||
bcc *+5
|
||||
sbc #%0000001010010000
|
||||
|
||||
cmp #%0000000101001000
|
||||
bcc *+5
|
||||
sbc #%0000000101001000
|
||||
|
||||
cmp #%0000000010100100
|
||||
bcc *+5
|
||||
sbc #%0000000010100100
|
||||
rts
|
||||
|
||||
; Special subroutine to divide the accumulator by 208 and return remainder in the Accumulator
|
||||
;
|
||||
; 208 = $D0 = 1101_0000
|
||||
;
|
||||
; There are probably faster hacks to divide a 16-bit unsigned value by 208
|
||||
; https://www.drdobbs.com/parallel/optimizing-integer-division-by-a-constan/184408499
|
||||
; https://embeddedgurus.com/stack-overflow/2009/06/division-of-integers-by-constants/
|
||||
|
||||
Mod208 cmp #%1101000000000000
|
||||
bcc *+5
|
||||
sbc #%1101000000000000
|
||||
|
||||
cmp #%0110100000000000
|
||||
bcc *+5
|
||||
sbc #%0110100000000000
|
||||
|
||||
cmp #%0011010000000000
|
||||
bcc *+5
|
||||
sbc #%0011010000000000
|
||||
|
||||
cmp #%0001101000000000
|
||||
bcc *+5
|
||||
sbc #%0001101000000000
|
||||
|
||||
cmp #%0000110100000000
|
||||
bcc *+5
|
||||
sbc #%0000110100000000
|
||||
|
||||
cmp #%0000011010000000
|
||||
bcc *+5
|
||||
sbc #%0000011010000000
|
||||
|
||||
cmp #%0000001101000000
|
||||
bcc *+5
|
||||
sbc #%0000001101000000
|
||||
|
||||
cmp #%0000000110100000
|
||||
bcc *+5
|
||||
sbc #%0000000110100000
|
||||
|
||||
cmp #%0000000011010000
|
||||
bcc *+5
|
||||
sbc #%0000000011010000
|
||||
rts
|
||||
|
||||
; Patch an 8-bit or 16-bit valueS into the bank. These are a set up unrolled loops to
|
||||
; quickly patch in a constanct value, or a value from an array into a given set of
|
||||
; templates.
|
||||
;
|
||||
; Because we have structured everything as parallel code blocks, most updates to the blitter
|
||||
; reduce to storing a constant value and have an amortized cost of just a single store.
|
||||
;
|
||||
; The utility of these routines is that they also handle setting just a range of lines
|
||||
; within a single bank.
|
||||
;
|
||||
; X = number of lines * 2, 0 to 32
|
||||
; Y = starting line * $1000
|
||||
; A = value
|
||||
;
|
||||
; Set M to 0 or 1
|
||||
SetConst ; Need a blank line here, otherwise the :tbl local variable resolveds backwards
|
||||
jmp (:tbl,x)
|
||||
:tbl da :bottom-00,:bottom-03,:bottom-06,:bottom-09
|
||||
da :bottom-12,:bottom-15,:bottom-18,:bottom-21
|
||||
da :bottom-24,:bottom-27,:bottom-30,:bottom-33
|
||||
da :bottom-36,:bottom-39,:bottom-42,:bottom-45
|
||||
da :bottom-48
|
||||
:top sta $F000,y
|
||||
sta $E000,y
|
||||
sta $D000,y
|
||||
sta $C000,y
|
||||
sta $B000,y
|
||||
sta $A000,y
|
||||
sta $9000,y
|
||||
sta $8000,y
|
||||
sta $7000,y
|
||||
sta $6000,y
|
||||
sta $5000,y
|
||||
sta $4000,y
|
||||
sta $3000,y
|
||||
sta $2000,y
|
||||
sta $1000,y
|
||||
sta: $0000,y
|
||||
:bottom rts
|
||||
|
||||
; SetDPAddrs
|
||||
;
|
||||
; A = absolute address (largest)
|
||||
; Y = offset
|
||||
;
|
||||
; Initializes a bank of direct page offsets
|
||||
SetDPAddrs
|
||||
lda #$0800
|
||||
sta $F000,y
|
||||
lda #$0700
|
||||
sta $E000,y
|
||||
lda #$0600
|
||||
sta $D000,y
|
||||
lda #$0500
|
||||
sta $C000,y
|
||||
lda #$0400
|
||||
sta $B000,y
|
||||
lda #$0300
|
||||
sta $A000,y
|
||||
lda #$0200
|
||||
sta $9000,y
|
||||
lda #$0100
|
||||
sta: $8000,y
|
||||
|
||||
lda #$0800
|
||||
sta $7000,y
|
||||
lda #$0700
|
||||
sta $6000,y
|
||||
lda #$0600
|
||||
sta $5000,y
|
||||
lda #$0500
|
||||
sta $4000,y
|
||||
lda #$0400
|
||||
sta $3000,y
|
||||
lda #$0300
|
||||
sta $2000,y
|
||||
lda #$0200
|
||||
sta $1000,y
|
||||
lda #$0100
|
||||
sta: $0000,y
|
||||
rts
|
||||
|
||||
; SetAbsAddrs
|
||||
;
|
||||
; A = absolute address (largest)
|
||||
; Y = offset
|
||||
; X = number of lines
|
||||
;
|
||||
; Stores a value and decrements by $1000 for each line
|
||||
SetAbsAddrs sec
|
||||
jmp (:tbl,x)
|
||||
:tbl da :bottom-00,:bottom-03,:bottom-09,:bottom-15
|
||||
da :bottom-21,:bottom-27,:bottom-33,:bottom-39
|
||||
da :bottom-45,:bottom-51,:bottom-57,:bottom-63
|
||||
da :bottom-69,:bottom-75,:bottom-81,:bottom-87
|
||||
da :bottom-93
|
||||
:top sta $F000,y
|
||||
sbc #$1000
|
||||
sta $E000,y
|
||||
sbc #$1000
|
||||
sta $D000,y
|
||||
sbc #$1000
|
||||
sta $C000,y
|
||||
sbc #$1000
|
||||
sta $B000,y
|
||||
sbc #$1000
|
||||
sta $A000,y
|
||||
sbc #$1000
|
||||
sta $9000,y
|
||||
sbc #$1000
|
||||
sta $8000,y
|
||||
sbc #$1000
|
||||
sta $7000,y
|
||||
sbc #$1000
|
||||
sta $6000,y
|
||||
sbc #$1000
|
||||
sta $5000,y
|
||||
sbc #$1000
|
||||
sta $4000,y
|
||||
sbc #$1000
|
||||
sta $3000,y
|
||||
sbc #$1000
|
||||
sta $2000,y
|
||||
sbc #$1000
|
||||
sta $1000,y
|
||||
sbc #$1000
|
||||
sta: $0000,y
|
||||
:bottom rts
|
||||
|
||||
; Fill up a full bank with blitter templates. Currently we can fit 16 lines per bank, so need
|
||||
; a total of 13 banks to hold the 208 lines for full-screen support
|
||||
;
|
||||
; A = high word of bank table
|
||||
; Y = index * 4 of the bank to initialize
|
||||
BuildBank
|
||||
|
||||
:bankArray equ tmp0
|
||||
:target equ tmp2
|
||||
:nextBank equ tmp4
|
||||
|
||||
stx :bankArray
|
||||
sta :bankArray+2
|
||||
|
||||
stz :target
|
||||
iny
|
||||
iny
|
||||
lda [:bankArray],y
|
||||
sta :target+2
|
||||
|
||||
iny ; move to the next item
|
||||
iny
|
||||
iny ; middle byte
|
||||
cpy #4*13 ; if greater than the array length, wrap back to zero
|
||||
bcc :ok
|
||||
ldy #1
|
||||
:ok lda [:bankArray],y ; Get the middle and high bytes of the address
|
||||
sta :nextBank
|
||||
|
||||
:next
|
||||
jsr :BuildLine2
|
||||
lda :target
|
||||
clc
|
||||
adc #$1000
|
||||
sta :target
|
||||
bcc :next
|
||||
|
||||
phb
|
||||
pei :target+1
|
||||
plb
|
||||
plb
|
||||
|
||||
; Change the patched value to one of DP_ENTRY, TWO_LYR_ENTRY or ONE_LYR_ENTRY based on the capabilities
|
||||
; that the engine needs.
|
||||
|
||||
lda #$F000+{DP_ENTRY} ; Set the address from each line to the next
|
||||
ldy #CODE_EXIT+1
|
||||
ldx #15*2
|
||||
jsr SetAbsAddrs
|
||||
|
||||
ldy #DP_ADDR
|
||||
jsr SetDPAddrs
|
||||
|
||||
ldy #$F000+CODE_EXIT ; Patch the last line with a JML to go to the next bank
|
||||
lda #{$005C+{DP_ENTRY}*256}
|
||||
sta [:target],y
|
||||
ldy #$F000+CODE_EXIT+2
|
||||
lda :nextBank
|
||||
sta [:target],y
|
||||
|
||||
ldy #$8000+CODE_EXIT ; Patch one line per bank to enable interrupts
|
||||
lda #{$004C+{ENABLE_INT}*256}
|
||||
sta [:target],y
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; This is the relocation subroutine, it is responsible for copying the template to a
|
||||
; memory location and patching up the necessary instructions.
|
||||
;
|
||||
; X = low word of address (must be a multiple of $1000)
|
||||
; A = high word of address (bank)
|
||||
:BuildLine
|
||||
stx :target
|
||||
sta :target+2
|
||||
|
||||
:BuildLine2
|
||||
lda #CODE_LEN ; round up to an even number of bytes
|
||||
inc
|
||||
and #$FFFE
|
||||
beq :nocopy
|
||||
dec
|
||||
dec
|
||||
tay
|
||||
:loop lda base,y
|
||||
sta [:target],y
|
||||
|
||||
dey
|
||||
dey
|
||||
bpl :loop
|
||||
|
||||
:nocopy lda #0 ; copy is complete, now patch up the addresses
|
||||
sep #$20
|
||||
|
||||
ldx #0
|
||||
lda :target+2 ; patch in the bank for the absolute long addressing mode
|
||||
:dobank ldy BankPatches,x
|
||||
sta [:target],y
|
||||
inx
|
||||
inx
|
||||
cpx #BankPatchNum
|
||||
bcc :dobank
|
||||
|
||||
ldx #0
|
||||
:dopage ldy PagePatches,x ; patch the page addresses by adding the page offset to each
|
||||
lda [:target],y
|
||||
clc
|
||||
adc :target+1
|
||||
sta [:target],y
|
||||
inx
|
||||
inx
|
||||
cpx #PagePatchNum
|
||||
bcc :dopage
|
||||
|
||||
:out
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; Start of the template code. This code is replicated 16 times per bank and spans
|
||||
; 13 banks for a total of 208 lines, which is what is required to render 26 tiles
|
||||
; to cover the full screen vertical scrolling.
|
||||
|
|
|
@ -0,0 +1,336 @@
|
|||
; Untility function related to patching and manipulating the blitter template code
|
||||
|
||||
mx %00
|
||||
|
||||
; Generalized routine that calculates the on-screen address of the tiles and takes the
|
||||
; StartX and StartY values into consideration. This routine really exists to support
|
||||
; the dirty tile rendering mode and the tiles *must* be aligned with the playfield.
|
||||
; That is, StartX % 4 == 0 and StartY % 8 == 0. If these conditions are not met, then
|
||||
; screen will not render correctly.
|
||||
_RecalcTileScreenAddrs
|
||||
NextColPtr equ tmp0
|
||||
RowAddrPtr equ tmp1
|
||||
OnScreenAddr equ tmp2
|
||||
Counter equ tmp3
|
||||
|
||||
jsr _OriginToTileStore ; Get the (col,row) of the tile in the upper-left corner of the playfield
|
||||
|
||||
; Manually add the offsets to the NextCol and TileStoreYTable array address and put in a direct page
|
||||
; location so we can free up the registers.
|
||||
|
||||
clc
|
||||
txa
|
||||
adc #NextCol
|
||||
sta NextColPtr
|
||||
|
||||
tya
|
||||
adc #TileStoreYTable
|
||||
sta RowAddrPtr
|
||||
|
||||
; Calculate the on-screen address of the upper-left corner of the playfiled
|
||||
|
||||
lda ScreenY0 ; Calculate the address of the first byte
|
||||
asl ; of the right side of the playfield
|
||||
tax
|
||||
lda ScreenAddr,x ; This is the address for the left edge of the physical screen
|
||||
clc
|
||||
adc ScreenX0
|
||||
sta OnScreenAddr
|
||||
|
||||
; Now, loop through the tile store
|
||||
|
||||
lda #MAX_TILES
|
||||
sta Counter
|
||||
ldy #0
|
||||
:tsloop
|
||||
lda (NextColPtr),y ; Need to recalculate each time since the wrap-around could
|
||||
clc ; happen anywhere
|
||||
adc (RowAddrPtr) ;
|
||||
tax ; NOTE: Try to rework to use new TileStore2DLookup array
|
||||
|
||||
lda OnScreenAddr
|
||||
sta TileStore+TS_SCREEN_ADDR,x
|
||||
|
||||
clc
|
||||
adc #4 ; Go to the next tile
|
||||
|
||||
iny
|
||||
iny
|
||||
cpy #2*41 ; If we've done 41 columns, move to the next line
|
||||
bcc :nohop
|
||||
|
||||
inc RowAddrPtr ; Advance the row address (with wrap-around)
|
||||
inc RowAddrPtr
|
||||
ldy #0 ; Reset the column counter
|
||||
clc
|
||||
adc #{8*160}-{4*41}
|
||||
:nohop
|
||||
sta OnScreenAddr ; Save the updated on-screen address
|
||||
dec Counter
|
||||
bne :tsloop
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; Patch an 8-bit or 16-bit valueS into the bank. These are a set up unrolled loops to
|
||||
; quickly patch in a constant value, or a value from an array into a given set of
|
||||
; templates.
|
||||
;
|
||||
; Because we have structured everything as parallel code blocks, most updates to the blitter
|
||||
; reduce to storing a constant value and have an amortized cost of just a single store.
|
||||
;
|
||||
; The utility of these routines is that they also handle setting just a range of lines
|
||||
; within a single bank.
|
||||
;
|
||||
; X = number of lines * 2, 0 to 32
|
||||
; Y = starting line * $1000
|
||||
; A = value
|
||||
;
|
||||
; Set M to 0 or 1
|
||||
SetConst ; Need a blank line here, otherwise the :tbl local variable resolveds backwards
|
||||
jmp (:tbl,x)
|
||||
:tbl da :bottom-00,:bottom-03,:bottom-06,:bottom-09
|
||||
da :bottom-12,:bottom-15,:bottom-18,:bottom-21
|
||||
da :bottom-24,:bottom-27,:bottom-30,:bottom-33
|
||||
da :bottom-36,:bottom-39,:bottom-42,:bottom-45
|
||||
da :bottom-48
|
||||
:top sta $F000,y
|
||||
sta $E000,y
|
||||
sta $D000,y
|
||||
sta $C000,y
|
||||
sta $B000,y
|
||||
sta $A000,y
|
||||
sta $9000,y
|
||||
sta $8000,y
|
||||
sta $7000,y
|
||||
sta $6000,y
|
||||
sta $5000,y
|
||||
sta $4000,y
|
||||
sta $3000,y
|
||||
sta $2000,y
|
||||
sta $1000,y
|
||||
sta: $0000,y
|
||||
:bottom rts
|
||||
|
||||
; SetDPAddrs
|
||||
;
|
||||
; A = absolute address (largest)
|
||||
; Y = offset
|
||||
;
|
||||
; Initializes a bank of direct page offsets
|
||||
SetDPAddrs
|
||||
lda #$0800
|
||||
sta $F000,y
|
||||
lda #$0700
|
||||
sta $E000,y
|
||||
lda #$0600
|
||||
sta $D000,y
|
||||
lda #$0500
|
||||
sta $C000,y
|
||||
lda #$0400
|
||||
sta $B000,y
|
||||
lda #$0300
|
||||
sta $A000,y
|
||||
lda #$0200
|
||||
sta $9000,y
|
||||
lda #$0100
|
||||
sta: $8000,y
|
||||
|
||||
lda #$0800
|
||||
sta $7000,y
|
||||
lda #$0700
|
||||
sta $6000,y
|
||||
lda #$0600
|
||||
sta $5000,y
|
||||
lda #$0500
|
||||
sta $4000,y
|
||||
lda #$0400
|
||||
sta $3000,y
|
||||
lda #$0300
|
||||
sta $2000,y
|
||||
lda #$0200
|
||||
sta $1000,y
|
||||
lda #$0100
|
||||
sta: $0000,y
|
||||
rts
|
||||
|
||||
; SetAbsAddrs
|
||||
;
|
||||
; A = absolute address (largest)
|
||||
; Y = offset
|
||||
; X = number of lines
|
||||
;
|
||||
; Stores a value and decrements by $1000 for each line
|
||||
SetAbsAddrs sec
|
||||
jmp (:tbl,x)
|
||||
:tbl da :bottom-00,:bottom-03,:bottom-09,:bottom-15
|
||||
da :bottom-21,:bottom-27,:bottom-33,:bottom-39
|
||||
da :bottom-45,:bottom-51,:bottom-57,:bottom-63
|
||||
da :bottom-69,:bottom-75,:bottom-81,:bottom-87
|
||||
da :bottom-93
|
||||
:top sta $F000,y
|
||||
sbc #$1000
|
||||
sta $E000,y
|
||||
sbc #$1000
|
||||
sta $D000,y
|
||||
sbc #$1000
|
||||
sta $C000,y
|
||||
sbc #$1000
|
||||
sta $B000,y
|
||||
sbc #$1000
|
||||
sta $A000,y
|
||||
sbc #$1000
|
||||
sta $9000,y
|
||||
sbc #$1000
|
||||
sta $8000,y
|
||||
sbc #$1000
|
||||
sta $7000,y
|
||||
sbc #$1000
|
||||
sta $6000,y
|
||||
sbc #$1000
|
||||
sta $5000,y
|
||||
sbc #$1000
|
||||
sta $4000,y
|
||||
sbc #$1000
|
||||
sta $3000,y
|
||||
sbc #$1000
|
||||
sta $2000,y
|
||||
sbc #$1000
|
||||
sta $1000,y
|
||||
sbc #$1000
|
||||
sta: $0000,y
|
||||
:bottom rts
|
||||
|
||||
; Fill up a full bank with blitter templates. Currently we can fit 16 lines per bank, so need
|
||||
; a total of 13 banks to hold the 208 lines for full-screen support
|
||||
;
|
||||
; A = high word of bank table
|
||||
; Y = index * 4 of the bank to initialize
|
||||
BuildBank
|
||||
|
||||
:bankArray equ tmp0
|
||||
:target equ tmp2
|
||||
:nextBank equ tmp4
|
||||
:entryOffset equ tmp6
|
||||
|
||||
stx :bankArray
|
||||
sta :bankArray+2
|
||||
|
||||
stz :target
|
||||
iny
|
||||
iny
|
||||
lda [:bankArray],y
|
||||
sta :target+2
|
||||
|
||||
iny ; move to the next item
|
||||
iny
|
||||
iny ; middle byte
|
||||
cpy #4*13 ; if greater than the array length, wrap back to zero
|
||||
bcc :ok
|
||||
ldy #1
|
||||
:ok lda [:bankArray],y ; Get the middle and high bytes of the address
|
||||
sta :nextBank
|
||||
|
||||
:next
|
||||
jsr :BuildLine2
|
||||
lda :target
|
||||
clc
|
||||
adc #$1000
|
||||
sta :target
|
||||
bcc :next
|
||||
|
||||
phb
|
||||
pei :target+1
|
||||
plb
|
||||
plb
|
||||
|
||||
; Change the patched value to one of DP_ENTRY, TWO_LYR_ENTRY or ONE_LYR_ENTRY based on the capabilities
|
||||
; that the engine needs.
|
||||
|
||||
lda #DP_ENTRY
|
||||
sta :entryOffset
|
||||
lda EngineMode
|
||||
bne :not_simple
|
||||
lda #ONE_LYR_ENTRY
|
||||
sta :entryOffset
|
||||
:not_simple
|
||||
|
||||
lda #$F000 ; Set the address from each line to the next
|
||||
ora :entryOffset
|
||||
ldy #CODE_EXIT+1
|
||||
ldx #15*2
|
||||
jsr SetAbsAddrs
|
||||
|
||||
ldy #DP_ADDR
|
||||
jsr SetDPAddrs
|
||||
|
||||
ldy #$F000+CODE_EXIT ; Patch the last line with a JML to go to the next bank
|
||||
lda :entryOffset
|
||||
xba
|
||||
ora #$005C
|
||||
sta [:target],y
|
||||
ldy #$F000+CODE_EXIT+2
|
||||
lda :nextBank
|
||||
sta [:target],y
|
||||
|
||||
ldy #$8000+CODE_EXIT ; Patch one line per bank to enable interrupts
|
||||
lda #{$004C+{ENABLE_INT}*256}
|
||||
sta [:target],y
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; This is the relocation subroutine, it is responsible for copying the template to a
|
||||
; memory location and patching up the necessary instructions.
|
||||
;
|
||||
; X = low word of address (must be a multiple of $1000)
|
||||
; A = high word of address (bank)
|
||||
:BuildLine
|
||||
stx :target
|
||||
sta :target+2
|
||||
|
||||
:BuildLine2
|
||||
phb ; save bank and reset to the code bank because
|
||||
phk ; the template is part of this bank
|
||||
plb
|
||||
|
||||
lda #CODE_LEN ; round up to an even number of bytes
|
||||
inc
|
||||
and #$FFFE
|
||||
beq :nocopy
|
||||
dec
|
||||
dec
|
||||
tay
|
||||
:loop lda base,y
|
||||
sta [:target],y
|
||||
|
||||
dey
|
||||
dey
|
||||
bpl :loop
|
||||
|
||||
:nocopy lda #0 ; copy is complete, now patch up the addresses
|
||||
sep #$20
|
||||
|
||||
ldx #0
|
||||
lda :target+2 ; patch in the bank for the absolute long addressing mode
|
||||
:dobank ldy BankPatches,x
|
||||
sta [:target],y
|
||||
inx
|
||||
inx
|
||||
cpx #BankPatchNum
|
||||
bcc :dobank
|
||||
|
||||
ldx #0
|
||||
:dopage ldy PagePatches,x ; patch the page addresses by adding the page offset to each
|
||||
lda [:target],y
|
||||
clc
|
||||
adc :target+1
|
||||
sta [:target],y
|
||||
inx
|
||||
inx
|
||||
cpx #PagePatchNum
|
||||
bcc :dopage
|
||||
|
||||
rep #$20
|
||||
plb
|
||||
rts
|
|
@ -0,0 +1,121 @@
|
|||
; A simple helper function that fills in all of the opcodes of a tile with the PEA opcode. This is
|
||||
; a separate functino because we can often just update the tile data if we know the opcodes are already
|
||||
; set. When we have to fill the opcodes, this function is used
|
||||
_TBFillPEAOpcode
|
||||
sep #$20
|
||||
lda #$F4
|
||||
]line equ 0
|
||||
lup 8
|
||||
sta: $0000+{]line*$1000},y
|
||||
sta: $0003+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; Copy tile data into the direct page compositing buffer. The main reason to do this in full passes is
|
||||
; because we can avoid needing to use both the X and Y registers during the compositing process and
|
||||
; reserve Y to hold the code field address.
|
||||
;
|
||||
; Also, we can get away with not setting the bank register, this is a wash in terms of speed, but results
|
||||
; in simpler, more composable subroutines
|
||||
_TBCopyTileDataAndMaskToCBuff
|
||||
jsr _TBCopyTileDataToCBuff
|
||||
jmp _TBCopyTileMaskToCBuff
|
||||
|
||||
_TBCopyTileDataAndMaskToCBuffV
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jmp _TBCopyTileMaskToCBuffV
|
||||
|
||||
_TBCopyTileDataToCBuff
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyTileDataToCBuffV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta blttmp+{]dest*4}
|
||||
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta blttmp+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; Copy tile mask data into the direct page compositing buffer.
|
||||
_TBCopyTileMaskToCBuff
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4}+32,x
|
||||
sta blttmp+{]line*4}+32
|
||||
|
||||
ldal tiledata+{]line*4}+32+2,x
|
||||
sta blttmp+{]line*4}+32+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyTileMaskToCBuffV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4}+32,x
|
||||
sta blttmp+{]dest*4}+32
|
||||
|
||||
ldal tiledata+{]src*4}+32+2,x
|
||||
sta blttmp+{]dest*4}+32+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; Tile 0 specializations
|
||||
; _TBConstTile
|
||||
;
|
||||
; A specialized routine that fills in a tile with a single constant value. It's intended to be used to
|
||||
; fill in solid colors, so there are no specialized horizontal or verical flipped variants
|
||||
_TBConstTileX
|
||||
lda #0
|
||||
sta: $0001,y
|
||||
sta: $0004,y
|
||||
sta $1001,y
|
||||
sta $1004,y
|
||||
sta $2001,y
|
||||
sta $2004,y
|
||||
sta $3001,y
|
||||
sta $3004,y
|
||||
sta $4001,y
|
||||
sta $4004,y
|
||||
sta $5001,y
|
||||
sta $5004,y
|
||||
sta $6001,y
|
||||
sta $6004,y
|
||||
sta $7001,y
|
||||
sta $7004,y
|
||||
plb
|
||||
rts
|
||||
|
||||
_TBConstTileSlow0
|
||||
tax
|
||||
jsr _TBFillPEAOpcode
|
||||
jmp _TBConstTileX
|
||||
|
||||
_TBConstTileDataToDP2
|
||||
]line equ 0
|
||||
lup 8
|
||||
stz tmp_tile_data+{]line*4}
|
||||
stz tmp_tile_data+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
|
@ -37,132 +37,45 @@
|
|||
;
|
||||
; It is simply too slow to try to horizontally reverse the pixel data on the fly. This still allows
|
||||
; for up to 512 tiles to be stored in a single bank, which should be sufficient.
|
||||
|
||||
TILE_CTRL_MASK equ $FE00
|
||||
TILE_PROC_MASK equ $F800 ; Select tile proc for rendering
|
||||
|
||||
; Temporary direct page locatinos used by some of the complex tile renderers
|
||||
|
||||
_X_REG equ tiletmp
|
||||
_Y_REG equ tiletmp+2
|
||||
_T_PTR equ tiletmp+4 ; Copy of the tile address pointer
|
||||
_BASE_ADDR equ tiletmp+6 ; Copy of BTableLow for this tile
|
||||
_SPR_X_REG equ tiletmp+8 ; Cache address of sprite plane source for a tile
|
||||
_JTBL_CACHE equ tiletmp+10 ; Cache the offset to the exception handler for a column
|
||||
_OP_CACHE equ tiletmp+12 ; Cache of a relevant operand / oeprator
|
||||
_TILE_ID equ tiletmp+14 ; Copy of the tile descriptor
|
||||
|
||||
; Low-level function to take a tile descriptor and return the address in the tiledata
|
||||
; bank. This is not too useful in the fast-path because the fast-path does more
|
||||
; incremental calculations, but it is handy for other utility functions
|
||||
;
|
||||
; A = tile descriptor
|
||||
;
|
||||
; The address is the TileID * 128 + (HFLIP * 64)
|
||||
GetTileAddr ENT
|
||||
jsr _GetTileAddr
|
||||
rtl
|
||||
_GetTileAddr
|
||||
asl ; Multiply by 2
|
||||
bit #2*TILE_HFLIP_BIT ; Check if the horizontal flip bit is set
|
||||
beq :no_flip
|
||||
inc ; Set the LSB
|
||||
:no_flip asl ; x4
|
||||
asl ; x8
|
||||
asl ; x16
|
||||
asl ; x32
|
||||
asl ; x64
|
||||
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
|
||||
; A is set to the the tile descriptor
|
||||
; Y is set to the top-left address of the tile in the BG1 data bank
|
||||
;
|
||||
; tmp0/tmp1 is reserved
|
||||
_RenderTileBG1
|
||||
pha ; Save the tile descriptor
|
||||
|
||||
and #TILE_VFLIP_BIT+TILE_HFLIP_BIT ; Only horizontal and vertical flips are supported for BG1
|
||||
xba
|
||||
tax
|
||||
ldal :actions,x
|
||||
stal :tiledisp+1
|
||||
|
||||
pla
|
||||
and #TILE_ID_MASK ; Mask out the ID and save just that
|
||||
_Mul128 ; multiplied by 128
|
||||
tax
|
||||
:tiledisp jmp $0000
|
||||
|
||||
:actions dw _TBSolidBG1_00,_TBSolidBG1_0H,_TBSolidBG1_V0,_TBSolidBG1_VH
|
||||
|
||||
; Given an address to a Tile Store record, dispatch to the appropriate tile renderer. The Tile
|
||||
; Store record contains all of the low-level information that's needed to call the renderer.
|
||||
;
|
||||
; Y = address of tile
|
||||
; There are two execution paths that are handled here. First, if there is no sprite, then
|
||||
; the tile data is read directly and written into the code field in a single pass. If there
|
||||
; are sprites that overlap the tile, then the sprite data is combined with the tile data
|
||||
; and written to a temporary direct page buffer. If
|
||||
;
|
||||
; This routine sets the direct page register to the second page since we use that space to
|
||||
; build and cache tile and sprite data, when necessary
|
||||
|
||||
_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_SPRITE_FLAG,x ; This is a bitfield of all the sprites that intersect this tile, only care if non-zero or not
|
||||
bne do_dirty_sprite
|
||||
|
||||
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
|
||||
; Handle the non-sprite tile blit
|
||||
CopyNoSprites
|
||||
sep #$20
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later
|
||||
|
||||
; txa
|
||||
; jsr BuildActiveSpriteArray ; Build the max 4 array of active sprites for this tile
|
||||
; sta ActiveSpriteCount
|
||||
; lda TileStore+TS_BASE_ADDR+1,x ; load the base address of the code field ($0000 or $8000)
|
||||
; sta _BASE_ADDR+1 ; so we can get by just copying the high byte
|
||||
rep #$20
|
||||
|
||||
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_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
|
||||
ldal TileProcs,x ; load and patch in the appropriate subroutine
|
||||
lda TileStore+TS_BASE_TILE_DISP,x ; Get the address of the renderer for this tile
|
||||
stal :tiledisp+1
|
||||
|
||||
ldx TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
||||
lda TileStore+TS_TILE_ID,x
|
||||
sta _TILE_ID ; Some tile blitters need to get the tile descriptor
|
||||
|
||||
sep #$20 ; load the bank of the target code field line
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,y
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated)
|
||||
pha
|
||||
rep #$20
|
||||
lda TileStore+TS_CODE_ADDR_LOW,y ; load the address of the code field
|
||||
pha
|
||||
lda TileStore+TS_BASE_ADDR,y ; load the base address of the code field
|
||||
sta _BASE_ADDR
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,y
|
||||
ply
|
||||
plb ; set the bank
|
||||
lda TileStore+TS_WORD_OFFSET,x
|
||||
plx
|
||||
plb ; set the bank to the code field that will be updated
|
||||
|
||||
; B is set to the correct code field bank
|
||||
; A is set to the tile word offset (0 through 80 in steps of 4)
|
||||
|
@ -171,6 +84,147 @@ _RenderTile2
|
|||
|
||||
:tiledisp jmp $0000 ; render the tile
|
||||
|
||||
; The sprite code is just responsible for quickly copying all of the sprite data
|
||||
; into the direct page temp area.
|
||||
|
||||
do_dirty_sprite
|
||||
pei TileStoreBankAndTileDataBank ; Special value that has the TileStore bank in LSB and TileData bank in MSB
|
||||
plb
|
||||
|
||||
; Cache a couple of values into the direct page that are used across all copy routines
|
||||
|
||||
lda TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated)
|
||||
sta tileAddr
|
||||
|
||||
ldx TileStore+TS_VBUFF_ADDR_COUNT,y
|
||||
jmp (dirty_sprite_dispatch,x)
|
||||
dirty_sprite_dispatch
|
||||
da CopyNoSprites
|
||||
da CopyOneSprite
|
||||
da CopyTwoSprites
|
||||
da CopyThreeSprites
|
||||
da CopyFourSprites ; MAX, don't bother with more than 4 sprites per tile
|
||||
|
||||
; We can optimize later, for now just copy the sprite data and mask into its own
|
||||
; direct page buffer and combine with the tile data later
|
||||
;
|
||||
; We set up direct page pointers to the mask bank and use the bank register for the
|
||||
; data.
|
||||
CopyFourSprites
|
||||
lda TileStore+TS_VBUFF_ADDR_0,y
|
||||
sta spriteIdx
|
||||
lda TileStore+TS_VBUFF_ADDR_1,y
|
||||
sta spriteIdx+4
|
||||
lda TileStore+TS_VBUFF_ADDR_2,y
|
||||
sta spriteIdx+8
|
||||
lda TileStore+TS_VBUFF_ADDR_3,y
|
||||
sta spriteIdx+12
|
||||
|
||||
; Copy three sprites into a temporary direct page buffer
|
||||
LDA_IL equ $A7 ; lda [dp]
|
||||
LDA_ILY equ $B7 ; lda [dp],y
|
||||
AND_IL equ $27 ; and [dp]
|
||||
AND_ILY equ $37 ; and [dp],y
|
||||
|
||||
CopyThreeSprites
|
||||
lda TileStore+TS_VBUFF_ADDR_0,y
|
||||
sta spriteIdx
|
||||
lda TileStore+TS_VBUFF_ADDR_1,y
|
||||
sta spriteIdx+4
|
||||
lda TileStore+TS_VBUFF_ADDR_2,y
|
||||
sta spriteIdx+8
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldy #]line*SPRITE_PLANE_SPAN
|
||||
lda (spriteIdx+8),y
|
||||
db AND_ILY,spriteIdx+4 ; Can't use long indirect inside LUP because of ']'
|
||||
ora (spriteIdx+4),y
|
||||
db AND_ILY,spriteIdx+0
|
||||
ora (spriteIdx+0),y
|
||||
sta tmp_sprite_data+{]line*4}
|
||||
|
||||
db LDA_ILY,spriteIdx+8
|
||||
db AND_ILY,spriteIdx+4
|
||||
db AND_ILY,spriteIdx+0
|
||||
sta tmp_sprite_mask+{]line*4}
|
||||
|
||||
ldy #]line*SPRITE_PLANE_SPAN+2
|
||||
lda (spriteIdx+8),y
|
||||
db AND_ILY,spriteIdx+4
|
||||
ora (spriteIdx+4),y
|
||||
db AND_ILY,spriteIdx+0
|
||||
ora (spriteIdx+0),y
|
||||
sta tmp_sprite_data+{]line*4}+2
|
||||
|
||||
db LDA_ILY,spriteIdx+8
|
||||
db AND_ILY,spriteIdx+4
|
||||
db AND_ILY,spriteIdx+0
|
||||
sta tmp_sprite_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
; jmp FinishTile
|
||||
|
||||
; Copy two sprites into a temporary direct page buffer
|
||||
CopyTwoSprites
|
||||
lda TileStore+TS_VBUFF_ADDR_0,y
|
||||
sta spriteIdx
|
||||
lda TileStore+TS_VBUFF_ADDR_1,y
|
||||
sta spriteIdx+4
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldy #]line*SPRITE_PLANE_SPAN
|
||||
lda (spriteIdx+4),y
|
||||
db AND_ILY,spriteIdx+0
|
||||
ora (spriteIdx+0),y
|
||||
sta tmp_sprite_data+{]line*4}
|
||||
|
||||
db LDA_ILY,spriteIdx+4
|
||||
db AND_ILY,spriteIdx+0
|
||||
sta tmp_sprite_mask+{]line*4}
|
||||
|
||||
ldy #]line*SPRITE_PLANE_SPAN+2
|
||||
lda (spriteIdx+4),y
|
||||
db AND_ILY,spriteIdx+0
|
||||
ora (spriteIdx+0),y
|
||||
sta tmp_sprite_data+{]line*4}+2
|
||||
|
||||
db LDA_ILY,spriteIdx+4
|
||||
db AND_ILY,spriteIdx+0
|
||||
sta tmp_sprite_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
; jmp FinishTile
|
||||
|
||||
CopyOneSprite
|
||||
clc
|
||||
lda TileStore+TS_VBUFF_ADDR_0,y
|
||||
sta spriteIdx
|
||||
adc #2
|
||||
sta spriteIdx+4
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
; ldal tiledata,x
|
||||
; and [spriteIdx]
|
||||
; ora (spriteIdx)
|
||||
; sta tmp_sprite_data+{]line*4}
|
||||
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta tmp_sprite_data+{]line*4}
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta tmp_sprite_data+{]line*4}+2
|
||||
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta tmp_sprite_mask+{]line*4}
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta tmp_sprite_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
; jmp FinishTile
|
||||
|
||||
; Reference all of the tile rendering subroutines defined in the TileXXXXX files. Each file defines
|
||||
; 8 entry points:
|
||||
;
|
||||
|
@ -297,123 +351,6 @@ ClearTile
|
|||
rep #$20
|
||||
rts
|
||||
|
||||
; Helper functions to copy tile data to the appropriate location in Bank 0
|
||||
; X = tile ID
|
||||
; Y = dynamic tile ID
|
||||
CopyTileToDyn ENT
|
||||
txa
|
||||
jsr _GetTileAddr
|
||||
tax
|
||||
|
||||
tya
|
||||
and #$001F ; Maximum of 32 dynamic tiles
|
||||
asl
|
||||
asl ; 4 bytes per page
|
||||
adc BlitterDP ; Add to the bank 00 base address
|
||||
adc #$0100 ; Go to the next page
|
||||
tay
|
||||
jsr CopyTileDToDyn ; Copy the tile data
|
||||
jsr CopyTileMToDyn ; Copy the tile mask
|
||||
rtl
|
||||
|
||||
; X = address of tile
|
||||
; Y = tile address in bank 0
|
||||
CopyTileDToDyn
|
||||
phb
|
||||
pea $0000
|
||||
plb
|
||||
plb
|
||||
|
||||
ldal tiledata+0,x
|
||||
sta: $0000,y
|
||||
ldal tiledata+2,x
|
||||
sta: $0002,y
|
||||
ldal tiledata+4,x
|
||||
sta $0100,y
|
||||
ldal tiledata+6,x
|
||||
sta $0102,y
|
||||
ldal tiledata+8,x
|
||||
sta $0200,y
|
||||
ldal tiledata+10,x
|
||||
sta $0202,y
|
||||
ldal tiledata+12,x
|
||||
sta $0300,y
|
||||
ldal tiledata+14,x
|
||||
sta $0302,y
|
||||
ldal tiledata+16,x
|
||||
sta $0400,y
|
||||
ldal tiledata+18,x
|
||||
sta $0402,y
|
||||
ldal tiledata+20,x
|
||||
sta $0500,y
|
||||
ldal tiledata+22,x
|
||||
sta $0502,y
|
||||
ldal tiledata+24,x
|
||||
sta $0600,y
|
||||
ldal tiledata+26,x
|
||||
sta $0602,y
|
||||
ldal tiledata+28,x
|
||||
sta $0700,y
|
||||
ldal tiledata+30,x
|
||||
sta $0702,y
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; Helper function to copy tile mask to the appropriate location in Bank 0
|
||||
;
|
||||
; X = address of tile
|
||||
; Y = tile address in bank 0
|
||||
;
|
||||
; Argument are the same as CopyTileDToDyn, the code takes care of adjust offsets.
|
||||
; This make is possible to call the two functions back-to-back
|
||||
;
|
||||
; ldx tileAddr
|
||||
; ldy dynTileAddr
|
||||
; jsr CopyTileDToDyn
|
||||
; jsr CopyTileMToDyn
|
||||
CopyTileMToDyn
|
||||
phb
|
||||
pea $0000
|
||||
plb
|
||||
plb
|
||||
|
||||
ldal tiledata+32+0,x
|
||||
sta: $0080,y
|
||||
ldal tiledata+32+2,x
|
||||
sta: $0082,y
|
||||
ldal tiledata+32+4,x
|
||||
sta $0180,y
|
||||
ldal tiledata+32+6,x
|
||||
sta $0182,y
|
||||
ldal tiledata+32+8,x
|
||||
sta $0280,y
|
||||
ldal tiledata+32+10,x
|
||||
sta $0282,y
|
||||
ldal tiledata+32+12,x
|
||||
sta $0380,y
|
||||
ldal tiledata+32+14,x
|
||||
sta $0382,y
|
||||
ldal tiledata+32+16,x
|
||||
sta $0480,y
|
||||
ldal tiledata+32+18,x
|
||||
sta $0482,y
|
||||
ldal tiledata+32+20,x
|
||||
sta $0580,y
|
||||
ldal tiledata+32+22,x
|
||||
sta $0582,y
|
||||
ldal tiledata+32+24,x
|
||||
sta $0680,y
|
||||
ldal tiledata+32+26,x
|
||||
sta $0682,y
|
||||
ldal tiledata+32+28,x
|
||||
sta $0780,y
|
||||
ldal tiledata+32+30,x
|
||||
sta $0782,y
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; CopyBG0Tile
|
||||
;
|
||||
; A low-level function that copies 8x8 tiles directly into the code field space.
|
||||
|
@ -421,14 +358,6 @@ CopyTileMToDyn
|
|||
; A = Tile ID (0 - 511)
|
||||
; X = Tile column (0 - 40)
|
||||
; Y = Tile row (0 - 25)
|
||||
CopyBG0Tile ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyBG0Tile
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyBG0Tile
|
||||
phb ; save the current bank
|
||||
phx ; save the original x-value
|
||||
|
@ -474,14 +403,6 @@ _CopyBG0Tile
|
|||
; A = Tile ID (0 - 511)
|
||||
; X = Tile column (0 - 40)
|
||||
; Y = Tile row (0 - 25)
|
||||
CopyBG1Tile
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _CopyBG1Tile
|
||||
plb
|
||||
rtl
|
||||
|
||||
_CopyBG1Tile
|
||||
phb ; save the current bank
|
||||
phx ; save the original x-value
|
||||
|
@ -518,7 +439,7 @@ _CopyBG1Tile
|
|||
; a tile.
|
||||
;
|
||||
; TileStore+TS_TILE_ID : Tile descriptor
|
||||
; TileStore+TS_DIRTY : $FFFF is clean, otherwise stores a back-reference to the DirtyTiles array
|
||||
; TileStore+TS_DIRTY : $0000 is clean, any other value indicated a dirty tile
|
||||
; 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
|
||||
|
@ -543,262 +464,117 @@ _CopyBG1Tile
|
|||
; TileStore+TS_SPRITE_ADDR_15
|
||||
; TileStore+TS_SPRITE_ADDR_16
|
||||
|
||||
|
||||
; 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
|
||||
DirtyTiles ds TILE_STORE_SIZE ; At most this many tiles can possibly be update at once
|
||||
|
||||
; Initialize the tile storage data structures. This takes care of populating the tile records with the
|
||||
; appropriate constant values.
|
||||
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
|
||||
ldy #0
|
||||
lda #0
|
||||
:yloop
|
||||
sta TileStoreYTable,y
|
||||
; To make processing the tile faster, we do them in chunks of eight. This allows the loop to be
|
||||
; unrolled, which means we don't have to keep track of the register value and makes it faster to
|
||||
; clear the dirty tile flag after being processed.
|
||||
; _ApplyTilesUnrolled
|
||||
tdc ; Move to the dedicated direct page for tile rendering
|
||||
clc
|
||||
adc #41*2
|
||||
iny
|
||||
iny
|
||||
cpy #26*2
|
||||
bcc :yloop
|
||||
adc #$100
|
||||
tcd
|
||||
|
||||
; Next, initialize the Tile Store itself
|
||||
phb ; Save the current bank
|
||||
tsc
|
||||
sta tmp0 ; Save it on the direct page
|
||||
bra at_loop
|
||||
|
||||
ldx #TILE_STORE_SIZE-2
|
||||
lda #25
|
||||
sta :row
|
||||
lda #40
|
||||
sta :col
|
||||
lda #$8000
|
||||
sta :vbuff
|
||||
; The DirtyTiles array and the TileStore information is in the Tile Store bank. Because we
|
||||
; process up to 8 tiles as a time and the tile code sets the bank register to the target
|
||||
; code field bank, we need to restore the bank register each time. So, we pre-push
|
||||
; 8 copies of the TileStore bank onto the stack.
|
||||
|
||||
:loop
|
||||
|
||||
; The first set of values in the Tile Store are changed during each frame based on the actions
|
||||
; that are happening
|
||||
at_exit
|
||||
tdc ; Move back to the original direct page
|
||||
sec
|
||||
sbc #$100
|
||||
tcd
|
||||
|
||||
lda #0
|
||||
stal TileStore+TS_TILE_ID,x ; clear the tile store with the special zero tile
|
||||
stal TileStore+TS_TILE_ADDR,x
|
||||
stal TileStore+TS_TILE_DISP,x
|
||||
|
||||
stal TileStore+TS_SPRITE_FLAG,x ; no sprites are set at the beginning
|
||||
lda #$FFFF ; none of the tiles are dirty
|
||||
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
|
||||
|
||||
lda :row ; Set the long address of where this tile
|
||||
asl ; exists in the code fields
|
||||
tay
|
||||
lda BRowTableHigh,y
|
||||
stal TileStore+TS_CODE_ADDR_HIGH,x ; High word of the tile address (just the bank)
|
||||
lda BRowTableLow,y
|
||||
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
|
||||
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
|
||||
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
|
||||
dec :row
|
||||
lda #40
|
||||
sta :col
|
||||
:hop
|
||||
|
||||
dex
|
||||
dex
|
||||
bpl :loop
|
||||
plb ; Restore the original data bank and return
|
||||
rts
|
||||
dt_base equ $FE ; top of second direct page space
|
||||
|
||||
_ClearDirtyTiles
|
||||
bra :hop
|
||||
:loop
|
||||
jsr _PopDirtyTile
|
||||
:hop
|
||||
lda DirtyTileCount
|
||||
bne :loop
|
||||
rts
|
||||
at_loop
|
||||
lda tmp0
|
||||
tcs
|
||||
|
||||
; Helper function to get the address offset into the tile cachce / tile backing store
|
||||
; X = tile column [0, 40] (41 columns)
|
||||
; Y = tile row [0, 25] (26 rows)
|
||||
GetTileStoreOffset ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _GetTileStoreOffset
|
||||
plb
|
||||
rtl
|
||||
lda DirtyTileCount ; This is pre-multiplied by 2
|
||||
beq at_exit ; If there are no items, exit
|
||||
|
||||
ldx TileStoreBankDoubled
|
||||
phx
|
||||
phx
|
||||
phx
|
||||
|
||||
_GetTileStoreOffset
|
||||
phx ; preserve the registers
|
||||
phy
|
||||
cmp #16 ; If there are >= 8 elements, then
|
||||
bcs at_chunk ; do a full chunk
|
||||
|
||||
jsr _GetTileStoreOffset0
|
||||
|
||||
ply
|
||||
plx
|
||||
rts
|
||||
|
||||
_GetTileStoreOffset0
|
||||
tya
|
||||
asl
|
||||
tay
|
||||
txa
|
||||
asl
|
||||
clc
|
||||
adc TileStoreYTable,y
|
||||
rts
|
||||
|
||||
; Set a tile value in the tile backing store. Mark dirty if the value changes
|
||||
;
|
||||
; 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
|
||||
stz DirtyTileCount ; Otherwise, this pass will handle them all
|
||||
tax
|
||||
pla
|
||||
|
||||
cmpl TileStore+TS_TILE_ID,x ; Only set to dirty if the value changed
|
||||
beq :nochange
|
||||
jmp (at_table,x)
|
||||
at_table da at_exit,at_one,at_two,at_three
|
||||
da at_four,at_five,at_six,at_seven
|
||||
|
||||
stal TileStore+TS_TILE_ID,x ; Value is different, store it.
|
||||
jsr _GetTileAddr
|
||||
stal TileStore+TS_TILE_ADDR,x ; Committed to drawing this tile, so get the address of the tile in the tiledata bank for later
|
||||
at_chunk sec
|
||||
sbc #16
|
||||
sta DirtyTileCount ; Fall through
|
||||
|
||||
ldal TileStore+TS_TILE_ID,x
|
||||
and #TILE_VFLIP_BIT+TILE_HFLIP_BIT ; get the lookup value
|
||||
xba
|
||||
stal TileStore+TS_TILE_DISP,x
|
||||
; Because all of the registers get used in the _RenderTile2 subroutine, we
|
||||
; push the values from the DirtyTiles array onto the stack and then pop off
|
||||
; the values as we go
|
||||
|
||||
; txa ; Add this tile to the list of dirty tiles to refresh
|
||||
jmp _PushDirtyTileX ; on the next call to _ApplyTiles
|
||||
ldy dt_base ; Reload the base index
|
||||
ldx DirtyTiles+14,y ; Load the TileStore offset
|
||||
stz TileStore+TS_DIRTY,x ; Clear this tile's dirty flag
|
||||
jsr _RenderTile2 ; Draw the tile
|
||||
plb ; Reset the data bank to the TileStore bank
|
||||
|
||||
:nochange rts
|
||||
|
||||
|
||||
; Append a new dirty tile record
|
||||
;
|
||||
; A = result of _GetTileStoreOffset for X, Y
|
||||
;
|
||||
; The main purpose of this function is to
|
||||
;
|
||||
; 1. Avoid marking the same tile dirty multiple times, and
|
||||
; 2. Pre-calculating all of the information necessary to render the tile
|
||||
PushDirtyTile ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _PushDirtyTile
|
||||
plb
|
||||
rtl
|
||||
|
||||
; alternate version that is very slightly slower, but preserves the y-register
|
||||
_PushDirtyTile
|
||||
tax
|
||||
|
||||
; alternate entry point if the x-register is already set
|
||||
_PushDirtyTileX
|
||||
ldal TileStore+TS_DIRTY,x
|
||||
bpl :occupied2
|
||||
|
||||
txa ; any non-negative value will work, this saves work below
|
||||
stal TileStore+TS_DIRTY,x ; and is 1 cycle faster than loading a constant value
|
||||
|
||||
ldx DirtyTileCount ; 4
|
||||
sta DirtyTiles,x ; 6
|
||||
inx ; 2
|
||||
inx ; 2
|
||||
stx DirtyTileCount ; 4 = 18
|
||||
rts
|
||||
:occupied2
|
||||
txa ; Make sure TileStore offset is returned in the accumulator
|
||||
rts
|
||||
|
||||
; Remove a dirty tile from the list and return it in state ready to be rendered. It is important
|
||||
; that the core rendering functions *only* use _PopDirtyTile to get a list of tiles to update,
|
||||
; because this routine merges the tile IDs stored in the Tile Store with the Sprite
|
||||
; information to set the TILE_SPRITE_BIT. This is the *only* place in the entire code base that
|
||||
; applies this bit to a tile descriptor.
|
||||
PopDirtyTile ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _PopDirtyTile
|
||||
plb
|
||||
rtl
|
||||
|
||||
_PopDirtyTile
|
||||
ldy DirtyTileCount
|
||||
bne _PopDirtyTile2
|
||||
rts
|
||||
|
||||
_PopDirtyTile2 ; alternate entry point
|
||||
dey
|
||||
dey
|
||||
sty DirtyTileCount ; remove last item from the list
|
||||
|
||||
ldx DirtyTiles,y ; load the offset into the Tile Store
|
||||
lda #$FFFF
|
||||
stal TileStore+TS_DIRTY,x ; clear the occupied backlink
|
||||
rts
|
||||
|
||||
; Run through the dirty tile list and render them into the code field
|
||||
ApplyTiles ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
jsr _ApplyTiles
|
||||
plb
|
||||
rtl
|
||||
|
||||
_ApplyTiles
|
||||
bra :begin
|
||||
|
||||
:loop
|
||||
; 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 X-register.
|
||||
|
||||
phb
|
||||
jsr _RenderTile2
|
||||
at_seven
|
||||
ldy dt_base
|
||||
ldx DirtyTiles+12,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile2
|
||||
plb
|
||||
|
||||
; Loop again until the list of dirty tiles is empty
|
||||
at_six
|
||||
ldy dt_base
|
||||
ldx DirtyTiles+10,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile2
|
||||
plb
|
||||
|
||||
:begin ldy DirtyTileCount
|
||||
bne :loop
|
||||
rts
|
||||
at_five
|
||||
ldy dt_base
|
||||
ldx DirtyTiles+8,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile2
|
||||
plb
|
||||
|
||||
at_four
|
||||
ldy dt_base
|
||||
ldx DirtyTiles+6,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile2
|
||||
plb
|
||||
|
||||
at_three
|
||||
ldy dt_base
|
||||
ldx DirtyTiles+4,y
|
||||
jsr _RenderTile2
|
||||
plb
|
||||
|
||||
at_two
|
||||
ldy dt_base
|
||||
ldx DirtyTiles+2,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile2
|
||||
plb
|
||||
|
||||
at_one
|
||||
ldy dt_base
|
||||
ldx DirtyTiles+0,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile2
|
||||
plb
|
||||
|
||||
jmp at_loop
|
||||
|
|
|
@ -36,6 +36,53 @@ _TBSolidTile_VH
|
|||
;
|
||||
; This does not increase the FPS by 37% because only a small number of tiles are drawn each frame, but it
|
||||
; has an impact and can significantly help out when sprites trigger more dirty tile updates than normal.
|
||||
|
||||
|
||||
; This is called via a JMP (abs,x) with an extra byte on the stack that holds the bank
|
||||
; register value. This must be restored prior to returning
|
||||
CopyTileAFast
|
||||
tax
|
||||
_CopyTileAFast
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
plb
|
||||
rts
|
||||
|
||||
CopyTileASlow
|
||||
tax
|
||||
jsr FillPEAOpcode
|
||||
jmp _CopyTileAFast
|
||||
|
||||
CopyTileVFast
|
||||
tax
|
||||
_CopyTileVFast
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta: $0004+{]dest*$1000},y
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta: $0001+{]dest*$1000},y
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
plb
|
||||
rts
|
||||
|
||||
CopyTileVSlow
|
||||
tax
|
||||
jsr FillPEAOpcode
|
||||
jmp _CopyTileVFast
|
||||
|
||||
|
||||
|
||||
; Old routines
|
||||
_TBCopyData
|
||||
]line equ 0
|
||||
lup 8
|
||||
|
@ -47,17 +94,6 @@ _TBCopyData
|
|||
--^
|
||||
rts
|
||||
|
||||
;_TBCopyDataH
|
||||
;]line equ 0
|
||||
; lup 8
|
||||
; ldal tiledata+{]line*4}+64,x
|
||||
; sta: $0004+{]line*$1000},y
|
||||
; ldal tiledata+{]line*4}+66,x
|
||||
; sta: $0001+{]line*$1000},y
|
||||
;]line equ ]line+1
|
||||
; --^
|
||||
; rts
|
||||
|
||||
_TBCopyDataV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
|
@ -71,40 +107,3 @@ _TBCopyDataV
|
|||
--^
|
||||
rts
|
||||
|
||||
;_TBCopyDataVH
|
||||
;]src equ 7
|
||||
;]dest equ 0
|
||||
; lup 8
|
||||
; ldal tiledata+{]src*4}+64,x
|
||||
; sta: $0004+{]dest*$1000},y
|
||||
; ldal tiledata+{]src*4}+66,x
|
||||
; sta: $0001+{]dest*$1000},y
|
||||
;]src equ ]src-1
|
||||
;]dest equ ]dest+1
|
||||
; --^
|
||||
; rts
|
||||
|
||||
; A simple helper function that fill in all of the opcodes of a tile with the PEA opcode. This is
|
||||
; a common function since a tile must be explicitly flagged to use a mask, so this routine is used
|
||||
; quite frequently in a well-designed tile map.
|
||||
_TBFillPEAOpcode
|
||||
sep #$20
|
||||
lda #$F4
|
||||
sta: $0000,y
|
||||
sta: $0003,y
|
||||
sta $1000,y
|
||||
sta $1003,y
|
||||
sta $2000,y
|
||||
sta $2003,y
|
||||
sta $3000,y
|
||||
sta $3003,y
|
||||
sta $4000,y
|
||||
sta $4003,y
|
||||
sta $5000,y
|
||||
sta $5003,y
|
||||
sta $6000,y
|
||||
sta $6003,y
|
||||
sta $7000,y
|
||||
sta $7003,y
|
||||
rep #$20
|
||||
rts
|
||||
|
|
|
@ -12,6 +12,48 @@ _TBDynamicTile_00
|
|||
jsr _TBDynamicData
|
||||
jmp _TBFillLdaDpOpcode
|
||||
|
||||
_TBDynamic
|
||||
ldal TileStore+TS_TILE_ID,x
|
||||
and #$007F
|
||||
ora #$4800
|
||||
|
||||
]line equ 0 ; render the first column
|
||||
lup 8
|
||||
sta: $0004+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
inc ; advance to the next word
|
||||
inc
|
||||
|
||||
]line equ 0 ; render the second column
|
||||
lup 8
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
sep #$20
|
||||
lda #$B5
|
||||
sta: $0000,y
|
||||
sta: $0003,y
|
||||
sta $1000,y
|
||||
sta $1003,y
|
||||
sta $2000,y
|
||||
sta $2003,y
|
||||
sta $3000,y
|
||||
sta $3003,y
|
||||
sta $4000,y
|
||||
sta $4003,y
|
||||
sta $5000,y
|
||||
sta $5003,y
|
||||
sta $6000,y
|
||||
sta $6003,y
|
||||
sta $7000,y
|
||||
sta $7003,y
|
||||
rep #$20
|
||||
|
||||
plb
|
||||
rts
|
||||
; Primitive to render a dynamic tile
|
||||
;
|
||||
; LDA 00,x / PHA where the operand is fixed when the tile is rendered
|
||||
|
|
|
@ -30,7 +30,6 @@ _TBFastSpriteTile_VH
|
|||
; Need to update the X-register before calling this
|
||||
_TBApplySpriteData
|
||||
ldx _SPR_X_REG ; set to the unaligned tile block address in the sprite plane
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
|
@ -46,118 +45,46 @@ _TBApplySpriteData
|
|||
--^
|
||||
rts
|
||||
|
||||
; Copy tile data into the direct page compositing buffer. The main reason to do this in full passes is
|
||||
; because we can avoid needing to use both the X and Y registers during the compositing process and
|
||||
; reserve Y to hold the code field address.
|
||||
;
|
||||
; Also, we can get away with not setting the bank register, this is a wash in terms of speed, but results
|
||||
; in simpler, more composable subroutines
|
||||
_TBCopyTileDataToCBuff
|
||||
_TBApplySpriteDataOne
|
||||
ldx spriteIdx
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta blttmp+{]line*4}
|
||||
lda blttmp+{]line*4}
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
lda blttmp+{]line*4}+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
rts
|
||||
|
||||
;_TBCopyTileDataToCBuffH
|
||||
;]line equ 0
|
||||
; lup 8
|
||||
; ldal tiledata+{]line*4}+64,x
|
||||
; sta blttmp+{]line*4}
|
||||
;
|
||||
; ldal tiledata+{]line*4}+64+2,x
|
||||
; sta blttmp+{]line*4}+2
|
||||
;]line equ ]line+1
|
||||
; --^
|
||||
; rts
|
||||
|
||||
_TBCopyTileDataToCBuffV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta blttmp+{]dest*4}
|
||||
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta blttmp+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
;_TBCopyTileDataToCBuffVH
|
||||
;]src equ 7
|
||||
;]dest equ 0
|
||||
; lup 8
|
||||
; ldal tiledata+{]src*4}+64,x
|
||||
; sta blttmp+{]dest*4}
|
||||
;
|
||||
; ldal tiledata+{]src*4}+64+2,x
|
||||
; sta blttmp+{]dest*4}+2
|
||||
;]src equ ]src-1
|
||||
;]dest equ ]dest+1
|
||||
; --^
|
||||
; rts
|
||||
|
||||
|
||||
; Copy tile mask data into the direct page compositing buffer.
|
||||
_TBCopyTileMaskToCBuff
|
||||
_TBApplySpriteDataTwo
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4}+32,x
|
||||
sta blttmp+{]line*4}+32
|
||||
lda blttmp+{]line*4}
|
||||
ldx spriteIdx+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
ldx spriteIdx
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
ldal tiledata+{]line*4}+32+2,x
|
||||
sta blttmp+{]line*4}+32+2
|
||||
lda blttmp+{]line*4}+2
|
||||
ldx spriteIdx+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
ldx spriteIdx
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
;_TBCopyTileMaskToCBuffH
|
||||
;]line equ 0
|
||||
; lup 8
|
||||
; ldal tiledata+{]line*4}+32+64,x
|
||||
; sta blttmp+{]line*4}+32
|
||||
;
|
||||
; ldal tiledata+{]line*4}+32+64+2,x
|
||||
; sta blttmp+{]line*4}+32+2
|
||||
;]line equ ]line+1
|
||||
; --^
|
||||
; rts
|
||||
|
||||
_TBCopyTileMaskToCBuffV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4}+32,x
|
||||
sta blttmp+{]dest*4}+32
|
||||
|
||||
ldal tiledata+{]src*4}+32+2,x
|
||||
sta blttmp+{]dest*4}+32+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
;_TBCopyTileMaskToCBuffVH
|
||||
;]src equ 7
|
||||
;]dest equ 0
|
||||
; lup 8
|
||||
; ldal tiledata+{]src*4}+32+64,x
|
||||
; sta blttmp+{]dest*4}+32
|
||||
;
|
||||
; ldal tiledata+{]src*4}+32+64+2,x
|
||||
; sta blttmp+{]dest*4}+32+2
|
||||
;]src equ ]src-1
|
||||
;]dest equ ]dest+1
|
||||
; --^
|
||||
; rts
|
||||
|
||||
rts
|
||||
|
||||
; Copy just the data into the code field from the composite buffer
|
||||
_TBSolidComposite
|
||||
|
|
|
@ -3,6 +3,48 @@
|
|||
; This tile type does not explicitly support horizontal or vertical flipping. An appropriate tile
|
||||
; descriptor should be passed into CopyTileToDyn to put the horizontally or vertically flipped source
|
||||
; data into the dynamic tile buffer
|
||||
_TBDynamicSpriteTile
|
||||
sta _X_REG
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$B500
|
||||
xba
|
||||
sta _OP_CACHE ; This is the 2-byte opcode for to load the data
|
||||
|
||||
CopyDynWord 0;$0003
|
||||
CopyDynWord 4;$1003
|
||||
CopyDynWord 8;$2003
|
||||
CopyDynWord 12;$3003
|
||||
CopyDynWord 16;$4003
|
||||
CopyDynWord 20;$5003
|
||||
CopyDynWord 24;$6003
|
||||
CopyDynWord 28;$7003
|
||||
|
||||
clc
|
||||
lda _JTBL_CACHE
|
||||
adc #32 ; All the snippets are 32 bytes wide and, since we're
|
||||
sta _JTBL_CACHE ; within one tile, the second column is consecutive
|
||||
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
CopyDynWord 2;$0000
|
||||
CopyDynWord 6;$1000
|
||||
CopyDynWord 10;$2000
|
||||
CopyDynWord 14;$3000
|
||||
CopyDynWord 18;$4000
|
||||
CopyDynWord 22;$5000
|
||||
CopyDynWord 26;$6000
|
||||
CopyDynWord 30;$7000
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
|
||||
_TBDynamicSpriteTile_00
|
||||
sty _Y_REG ; This is restored in the macro
|
||||
|
||||
|
@ -53,6 +95,56 @@ _TBDynamicSpriteTile_00
|
|||
|
||||
rts
|
||||
|
||||
; Create a masked render based on data in the direct page temporary buffer
|
||||
;
|
||||
; ]1 : sprite buffer offset
|
||||
; ]2 : code field offset
|
||||
CopyDynWord mac
|
||||
lda tmp_sprite_mask+{]1} ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
lda tmp_sprite_data+{]1} ; load the sprite data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
mixed cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$F000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE ; Get the LDA dp,x instruction for this column
|
||||
sta: $0000,x
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,x
|
||||
lda tmp_sprite_mask+{]1}
|
||||
sta: $0003,x
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $0006,x
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,x
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda #$4800 ; Put the PHA in the third byte
|
||||
sta: {]2}+1,y
|
||||
lda _OP_CACHE ; Store the LDA dp,x instruction with operand
|
||||
sta: {]2},y
|
||||
next
|
||||
<<<
|
||||
|
||||
; Masked renderer for a dynamic tile with sprite data overlaid.
|
||||
;
|
||||
|
@ -70,13 +162,13 @@ CopyDynSpriteWord MAC
|
|||
;
|
||||
; If MASK == 0, then we can do a PEA. If MASK == $FFFF, then fall back to the simple Dynamic Tile
|
||||
; code.
|
||||
ldal spritemask+]1,x ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
ldal spritemask+{]1},x ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
ldal spritedata+]1,x ; load the sprite data
|
||||
ldal spritedata+{]1},x ; load the sprite data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
|
@ -95,12 +187,12 @@ mixed cmp #$FFFF ; All 1's in the mask is a fully transpare
|
|||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,y
|
||||
ldal spritemask+]1,x
|
||||
ldal spritemask+{]1},x
|
||||
sta: $0003,y
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,y
|
||||
ldal spritedata+]1,x
|
||||
ldal spritedata+{]1},x
|
||||
sta: $0006,y
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
|
|
|
@ -82,13 +82,13 @@ CopyDynMaskedSpriteWord MAC
|
|||
; If MASK == 0, then we can do a PEA. If MASK == $FFFF, then fall back to the simple Dynamic Tile
|
||||
; code and eliminate the constanct AND/ORA instructions.
|
||||
|
||||
ldal spritemask+]1,x ; load the mask value
|
||||
ldal spritemask+{]1},x ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
ldal spritedata+]1,x ; load the sprite data
|
||||
ldal spritedata+{]1},x ; load the sprite data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
|
@ -99,7 +99,7 @@ mixed
|
|||
sta: ]2,y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$F000} ; adjust for the current row offset
|
||||
sta: ]2+1,y
|
||||
sta: {]2}+1,y
|
||||
tay ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE
|
||||
|
@ -111,14 +111,14 @@ mixed
|
|||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0006,y
|
||||
ldal spritemask+]1,x
|
||||
ldal spritemask+{]1},x
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent ; so we can use the Tile00011 method
|
||||
sta: $0007,y
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0009,y
|
||||
ldal spritedata+]1,x
|
||||
ldal spritedata+{]1},x
|
||||
sta: $000A,y
|
||||
|
||||
lda #$0980 ; branch to the prologue (BRA *+11)
|
||||
|
|
|
@ -77,7 +77,7 @@ CopyDynPriSpriteWord MAC
|
|||
|
||||
lda #$00A9 ; LDA #DATA
|
||||
sta: $0000,y
|
||||
ldal spritedata+]1,x
|
||||
ldal spritedata+{]1},x
|
||||
sta: $0001,y
|
||||
|
||||
lda _OP_CACHE
|
||||
|
|
|
@ -90,14 +90,14 @@ CopyDynPrioMaskedSpriteWord MAC
|
|||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,y
|
||||
|
||||
ldal spritemask+]1,x
|
||||
ldal spritemask+{]1},x
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent ; so we can use the Tile00011 method
|
||||
sta: $0003,y
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,y
|
||||
ldal spritedata+]1,x
|
||||
ldal spritedata+{]1},x
|
||||
sta: $0006,y
|
||||
|
||||
lda _T_PTR
|
||||
|
|
|
@ -1,4 +1,26 @@
|
|||
|
||||
; On entry
|
||||
;
|
||||
; B is set to the correct BG1 data bank
|
||||
; A is set to the the tile descriptor
|
||||
; Y is set to the top-left address of the tile in the BG1 data bank
|
||||
;
|
||||
; tmp0/tmp1 is reserved
|
||||
_RenderTileBG1
|
||||
pha ; Save the tile descriptor
|
||||
|
||||
and #TILE_VFLIP_BIT+TILE_HFLIP_BIT ; Only horizontal and vertical flips are supported for BG1
|
||||
xba
|
||||
tax
|
||||
|
||||
pla
|
||||
and #TILE_ID_MASK ; Mask out the ID and save just that
|
||||
_Mul128 ; multiplied by 128
|
||||
jmp (:actions,x)
|
||||
:actions dw _TBSolidBG1_00,_TBSolidBG1_0H,_TBSolidBG1_V0,_TBSolidBG1_VH
|
||||
|
||||
_TBSolidBG1_00
|
||||
tax
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
|
@ -10,6 +32,7 @@ _TBSolidBG1_00
|
|||
rts
|
||||
|
||||
_TBSolidBG1_0H
|
||||
tax
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4}+64,x
|
||||
|
@ -21,6 +44,7 @@ _TBSolidBG1_0H
|
|||
rts
|
||||
|
||||
_TBSolidBG1_V0
|
||||
tax
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
|
@ -34,6 +58,7 @@ _TBSolidBG1_V0
|
|||
rts
|
||||
|
||||
_TBSolidBG1_VH
|
||||
tax
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
|
|
|
@ -2,28 +2,6 @@
|
|||
; of these routines are to adjust tables and patch in new values into the code field
|
||||
; when the virtual Y-position of the play field changes.
|
||||
|
||||
|
||||
; SetBG0YPos
|
||||
;
|
||||
; Set the virtual position of the primary background layer.
|
||||
SetBG0YPos ENT
|
||||
jsr _SetBG0YPos
|
||||
rtl
|
||||
|
||||
_SetBG0YPos
|
||||
cmp StartY
|
||||
beq :out ; Easy, if nothing changed, then nothing changes
|
||||
|
||||
ldx StartY ; Load the old value (but don't save it yet)
|
||||
sta StartY ; Save the new position
|
||||
|
||||
lda #DIRTY_BIT_BG0_Y
|
||||
tsb DirtyBits ; Check if the value is already dirty, if so exit
|
||||
bne :out ; without overwriting the original value
|
||||
|
||||
stx OldStartY ; First change, so preserve the value
|
||||
:out rts
|
||||
|
||||
; Based on the current value of StartY in the direct page. Set up the dispatch
|
||||
; information so that the BltRange driver will render the correct code field
|
||||
; lines in the correct order
|
||||
|
@ -67,6 +45,7 @@ _ApplyBG0YPos
|
|||
; and ~2,500 per secord. This is ~1% of our total CPU budget and is *just* enough cycles to be
|
||||
; interesting.... Another 8 cycles could be removed by doing all calculatinos pre-multiplied by 2
|
||||
; to avoid several 'asl' instructions
|
||||
phb
|
||||
:loop
|
||||
lda :virt_line
|
||||
asl
|
||||
|
@ -112,9 +91,9 @@ _ApplyBG0YPos
|
|||
sta :lines_left
|
||||
|
||||
jne :loop
|
||||
|
||||
phk
|
||||
plb
|
||||
|
||||
:out
|
||||
rts
|
||||
|
||||
; Unrolled copy routine to move RTable intries into STK_ADDR position.
|
||||
|
@ -167,7 +146,7 @@ CopyRTableToStkAddr
|
|||
:x14 ldal RTable+26,x
|
||||
sta STK_ADDR+$D000,y
|
||||
:x13 ldal RTable+24,x
|
||||
sta: STK_ADDR+$C000,y
|
||||
sta STK_ADDR+$C000,y
|
||||
:x12 ldal RTable+22,x
|
||||
sta STK_ADDR+$B000,y
|
||||
:x11 ldal RTable+20,x
|
||||
|
@ -175,7 +154,7 @@ CopyRTableToStkAddr
|
|||
:x10 ldal RTable+18,x
|
||||
sta STK_ADDR+$9000,y
|
||||
:x09 ldal RTable+16,x
|
||||
sta: STK_ADDR+$8000,y
|
||||
sta STK_ADDR+$8000,y
|
||||
:x08 ldal RTable+14,x
|
||||
sta STK_ADDR+$7000,y
|
||||
:x07 ldal RTable+12,x
|
||||
|
@ -183,7 +162,7 @@ CopyRTableToStkAddr
|
|||
:x06 ldal RTable+10,x
|
||||
sta STK_ADDR+$5000,y
|
||||
:x05 ldal RTable+08,x
|
||||
sta: STK_ADDR+$4000,y
|
||||
sta STK_ADDR+$4000,y
|
||||
:x04 ldal RTable+06,x
|
||||
sta STK_ADDR+$3000,y
|
||||
:x03 ldal RTable+04,x
|
||||
|
|
|
@ -0,0 +1,711 @@
|
|||
; Rendering functions for Dynamic tiles. There are no Fast/Slow variants here
|
||||
CopyDynamicTile
|
||||
ldal TileStore+TS_TILE_ID,x
|
||||
and #$007F
|
||||
ora #$4800
|
||||
|
||||
]line equ 0 ; render the first column
|
||||
lup 8
|
||||
sta: $0004+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
inc ; advance to the next word
|
||||
inc
|
||||
|
||||
]line equ 0 ; render the second column
|
||||
lup 8
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
sep #$20
|
||||
lda #$B5
|
||||
sta: $0000,y
|
||||
sta: $0003,y
|
||||
sta $1000,y
|
||||
sta $1003,y
|
||||
sta $2000,y
|
||||
sta $2003,y
|
||||
sta $3000,y
|
||||
sta $3003,y
|
||||
sta $4000,y
|
||||
sta $4003,y
|
||||
sta $5000,y
|
||||
sta $5003,y
|
||||
sta $6000,y
|
||||
sta $6003,y
|
||||
sta $7000,y
|
||||
sta $7003,y
|
||||
rep #$20
|
||||
plb
|
||||
rts
|
||||
|
||||
; These routines handle the sprites. They rely on a fairly complicated macro that takes care of
|
||||
; populating the code field and snippet space
|
||||
DynamicOver
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$B500
|
||||
xba
|
||||
sta _OP_CACHE ; This is the 2-byte opcode for to load the data
|
||||
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x
|
||||
pha
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x
|
||||
plb
|
||||
|
||||
CopyDynOver 0;$0003
|
||||
CopyDynOver 4;$1003
|
||||
CopyDynOver 8;$2003
|
||||
CopyDynOver 12;$3003
|
||||
CopyDynOver 16;$4003
|
||||
CopyDynOver 20;$5003
|
||||
CopyDynOver 24;$6003
|
||||
CopyDynOver 28;$7003
|
||||
|
||||
sec
|
||||
lda _JTBL_CACHE
|
||||
sbc #SNIPPET_SIZE ; Advance to the next snippet (Reverse indexing)
|
||||
sta _JTBL_CACHE
|
||||
|
||||
clc
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
CopyDynOver 2;$0000
|
||||
CopyDynOver 6;$1000
|
||||
CopyDynOver 10;$2000
|
||||
CopyDynOver 14;$3000
|
||||
CopyDynOver 18;$4000
|
||||
CopyDynOver 22;$5000
|
||||
CopyDynOver 26;$6000
|
||||
CopyDynOver 30;$7000
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
DynamicUnder
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE ; This is the 2-byte opcode for to load the data
|
||||
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x
|
||||
pha
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x
|
||||
plb
|
||||
|
||||
CopyDynUnder 0;$0003
|
||||
CopyDynUnder 4;$1003
|
||||
CopyDynUnder 8;$2003
|
||||
CopyDynUnder 12;$3003
|
||||
CopyDynUnder 16;$4003
|
||||
CopyDynUnder 20;$5003
|
||||
CopyDynUnder 24;$6003
|
||||
CopyDynUnder 28;$7003
|
||||
|
||||
sec
|
||||
lda _JTBL_CACHE
|
||||
sbc #SNIPPET_SIZE
|
||||
sta _JTBL_CACHE
|
||||
|
||||
clc
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
CopyDynUnder 2;$0000
|
||||
CopyDynUnder 6;$1000
|
||||
CopyDynUnder 10;$2000
|
||||
CopyDynUnder 14;$3000
|
||||
CopyDynUnder 18;$4000
|
||||
CopyDynUnder 22;$5000
|
||||
CopyDynUnder 26;$6000
|
||||
CopyDynUnder 30;$7000
|
||||
|
||||
; Now fill in the JMP opcodes
|
||||
_DynFillJmpOpcode
|
||||
sep #$20
|
||||
lda #$4C
|
||||
sta: $0000,y
|
||||
sta: $0003,y
|
||||
sta $1000,y
|
||||
sta $1003,y
|
||||
sta $2000,y
|
||||
sta $2003,y
|
||||
sta $3000,y
|
||||
sta $3003,y
|
||||
sta $4000,y
|
||||
sta $4003,y
|
||||
sta $5000,y
|
||||
sta $5003,y
|
||||
sta $6000,y
|
||||
sta $6003,y
|
||||
sta $7000,y
|
||||
sta $7003,y
|
||||
rep #$20
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; Bank is already set to code field
|
||||
; Y register is the offset
|
||||
; X register is the TileStore
|
||||
; A is the tile address
|
||||
CopyDynamicTileTwoLyr
|
||||
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_WORD_OFFSET,x
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
; We need to do an AND dp|$80,x / ORA dp,x. The opcode values are $35 and $15, respectively.
|
||||
; We pre-calculate the AND opcode with the high bit of the operand set and then, in the macro
|
||||
; perform and EOR #$2080 to covert the opcode and operand in one instruction
|
||||
|
||||
ldal TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE2 ; This is an op to load the dynamic tile data
|
||||
|
||||
CopyMaskedDWord $0003
|
||||
CopyMaskedDWord $1003
|
||||
CopyMaskedDWord $2003
|
||||
CopyMaskedDWord $3003
|
||||
CopyMaskedDWord $4003
|
||||
CopyMaskedDWord $5003
|
||||
CopyMaskedDWord $6003
|
||||
CopyMaskedDWord $7003
|
||||
|
||||
sec
|
||||
lda _JTBL_CACHE
|
||||
sbc #SNIPPET_SIZE ; Advance to the next snippet (Reverse indexing)
|
||||
sta _JTBL_CACHE
|
||||
|
||||
clc
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
lda _OP_CACHE2
|
||||
adc #$0200
|
||||
sta _OP_CACHE2
|
||||
|
||||
CopyMaskedDWord $0000
|
||||
CopyMaskedDWord $1000
|
||||
CopyMaskedDWord $2000
|
||||
CopyMaskedDWord $3000
|
||||
CopyMaskedDWord $4000
|
||||
CopyMaskedDWord $5000
|
||||
CopyMaskedDWord $6000
|
||||
CopyMaskedDWord $7000
|
||||
|
||||
jmp _DynFillJmpOpcode
|
||||
|
||||
; Render a sprite on top of a dyamic tile with transparent areas shwing the second background
|
||||
DynamicOverTwoLyr
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
; We need to do an AND dp|$80,x / ORA dp,x. The opcode values are $35 and $15, respectively.
|
||||
; We pre-calculate the AND opcode with the high bit of the operand set and then, in the macro
|
||||
; perform and EOR #$2080 to covert the opcode and operand in one instruction
|
||||
|
||||
lda TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE2 ; This is an op to load the dynamic tile data
|
||||
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x
|
||||
pha
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x
|
||||
plb
|
||||
|
||||
CopyDynMaskedSpriteWord 0;$0003
|
||||
CopyDynMaskedSpriteWord 4;$1003
|
||||
CopyDynMaskedSpriteWord 8;$2003
|
||||
CopyDynMaskedSpriteWord 12;$3003
|
||||
CopyDynMaskedSpriteWord 16;$4003
|
||||
CopyDynMaskedSpriteWord 20;$5003
|
||||
CopyDynMaskedSpriteWord 24;$6003
|
||||
CopyDynMaskedSpriteWord 28;$7003
|
||||
|
||||
sec
|
||||
lda _JTBL_CACHE
|
||||
sbc #SNIPPET_SIZE ; Advance to the next snippet (Reverse indexing)
|
||||
sta _JTBL_CACHE
|
||||
|
||||
clc
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
lda _OP_CACHE2
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE2
|
||||
|
||||
CopyDynMaskedSpriteWord 2;$0000
|
||||
CopyDynMaskedSpriteWord 6;$1000
|
||||
CopyDynMaskedSpriteWord 10;$2000
|
||||
CopyDynMaskedSpriteWord 14;$3000
|
||||
CopyDynMaskedSpriteWord 18;$4000
|
||||
CopyDynMaskedSpriteWord 22;$5000
|
||||
CopyDynMaskedSpriteWord 26;$6000
|
||||
CopyDynMaskedSpriteWord 30;$7000
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; Render a sprite on top of a dyamic tile with transparent areas shwing the second background
|
||||
DynamicUnderTwoLyr
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
; We need to do an AND dp|$80,x / ORA dp,x. The opcode values are $35 and $15, respectively.
|
||||
; We pre-calculate the AND opcode with the high bit of the operand set and then, in the macro
|
||||
; perform and EOR #$2080 to covert the opcode and operand in one instruction
|
||||
|
||||
lda TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE2 ; This is an op to load the dynamic tile data
|
||||
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x
|
||||
pha
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x
|
||||
plb
|
||||
|
||||
CopyDynPrioMaskedSpriteWord 0;$0003
|
||||
CopyDynPrioMaskedSpriteWord 4;$1003
|
||||
CopyDynPrioMaskedSpriteWord 8;$2003
|
||||
CopyDynPrioMaskedSpriteWord 12;$3003
|
||||
CopyDynPrioMaskedSpriteWord 16;$4003
|
||||
CopyDynPrioMaskedSpriteWord 20;$5003
|
||||
CopyDynPrioMaskedSpriteWord 24;$6003
|
||||
CopyDynPrioMaskedSpriteWord 28;$7003
|
||||
|
||||
sec
|
||||
lda _JTBL_CACHE
|
||||
sbc #SNIPPET_SIZE ; Advance to the next snippet (Reverse indexing)
|
||||
sta _JTBL_CACHE
|
||||
|
||||
clc
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
lda _OP_CACHE2
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE2
|
||||
|
||||
CopyDynPrioMaskedSpriteWord 2;$0000
|
||||
CopyDynPrioMaskedSpriteWord 6;$1000
|
||||
CopyDynPrioMaskedSpriteWord 10;$2000
|
||||
CopyDynPrioMaskedSpriteWord 14;$3000
|
||||
CopyDynPrioMaskedSpriteWord 18;$4000
|
||||
CopyDynPrioMaskedSpriteWord 22;$5000
|
||||
CopyDynPrioMaskedSpriteWord 26;$6000
|
||||
CopyDynPrioMaskedSpriteWord 30;$7000
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
|
||||
; Create a masked render based on data in the direct page temporary buffer.
|
||||
;
|
||||
; If the MASK is $0000, then insert a PEA
|
||||
; If the MASK is $FFFF, then insert a LDA DP,x / PHA
|
||||
; If mixed, create a snippet of LDA DP,x / AND #MASK / ORA #DATA / PHA
|
||||
;
|
||||
; ]1 : sprite buffer offset
|
||||
; ]2 : code field offset
|
||||
CopyDynOver mac
|
||||
lda tmp_sprite_mask+{]1} ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
lda tmp_sprite_data+{]1} ; load the sprite data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
mixed cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE ; Get the LDA dp,x instruction for this column
|
||||
sta: $0000,x
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,x
|
||||
lda tmp_sprite_mask+{]1}
|
||||
sta: $0003,x
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $0006,x
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,x
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda #$4800 ; Put the PHA in the third byte
|
||||
sta: {]2}+1,y
|
||||
lda _OP_CACHE ; Store the LDA dp,x instruction with operand
|
||||
sta: {]2},y
|
||||
next
|
||||
<<<
|
||||
|
||||
; Masked renderer for a dynamic tile on top of the sprite data. There are no transparent vs
|
||||
; solid vs mixed considerations here. This only sets the JMP address, setting the JMP opcodes
|
||||
; must happen elsewhere
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
; ]2 : code field offset
|
||||
CopyDynUnder MAC
|
||||
|
||||
; Need to fill in the first 9 bytes of the JMP handler with the following code sequence where
|
||||
; the data and mask from from the sprite plane
|
||||
;
|
||||
; lda #DATA
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bra *+16
|
||||
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda #$00A9 ; LDA #DATA
|
||||
sta: $0000,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $0001,x
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0003,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0005,x ; ORA $00,x
|
||||
|
||||
lda #$0E80 ; branch to the prologue (BRA *+16)
|
||||
sta: $0007,x
|
||||
eom
|
||||
|
||||
; Masked renderer for a dynamic tile. What's interesting about this renderer is that the mask
|
||||
; value is not used directly, but simply indicates if we can use a LDA 0,x / PHA sequence,
|
||||
; a LDA (00),y / PHA, or a JMP to a blended render
|
||||
;
|
||||
; If a dynamic tile is animated, there is the possibility to create a special mask that marks
|
||||
; words of the tile that a front / back / mixed across all frames.
|
||||
;
|
||||
; ]1 : code field offset
|
||||
;
|
||||
; This macro does not set the opcode since they will all be JMP instructions, they can be
|
||||
; filled more efficiently in a separate routine.
|
||||
CopyMaskedDWord MAC
|
||||
|
||||
; Need to fill in the first 6 bytes of the JMP handler with the following code sequence
|
||||
;
|
||||
; lda (00),y
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bra *+17
|
||||
|
||||
lda _JTBL_CACHE
|
||||
ora #{{]1}&$7000} ; adjust for the current row offset
|
||||
sta: {]1}+1,y
|
||||
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
lda _OP_CACHE
|
||||
sta: $0000,x ; LDA (00),y
|
||||
lda _OP_CACHE2
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
lda #$0F80 ; branch to the prologue (BRA *+17)
|
||||
sta: $0006,x
|
||||
eom
|
||||
|
||||
|
||||
; Masked renderer for a masked dynamic tile with sprite data overlaid.
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
; ]2 : code field offset
|
||||
CopyDynMaskedSpriteWord MAC
|
||||
|
||||
; Need to fill in the first 14 bytes of the JMP handler with the following code sequence where
|
||||
; the data and mask from from the sprite plane
|
||||
;
|
||||
; lda ($00),y
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bra *+15
|
||||
;
|
||||
; If MASK == 0, then we can do a PEA. If MASK == $FFFF, then fall back to the simple Dynamic Tile
|
||||
; code and eliminate the constanct AND/ORA instructions.
|
||||
|
||||
lda tmp_sprite_mask+{]1} ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: {]2},y
|
||||
lda tmp_sprite_data+{]1} ; load the sprite data
|
||||
sta: {]2}+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
; We will always do a JMP to the exception handler, so set that up, then check for sprite
|
||||
; transparency
|
||||
mixed
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0000,x ; LDA (00),y
|
||||
lda _OP_CACHE2
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0006,x
|
||||
lda tmp_sprite_mask+{]1}
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent
|
||||
sta: $0007,x
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0009,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $000A,x
|
||||
|
||||
lda #$0980 ; branch to the prologue (BRA *+11)
|
||||
sta: $000C,x
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda #$0F80 ; branch to the epilogue (BRA *+17)
|
||||
sta: $0006,x
|
||||
next
|
||||
eom
|
||||
|
||||
|
||||
; Masked renderer for a masked dynamic tile with sprite data underlaid.
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
; ]2 : code field offset
|
||||
CopyDynPrioMaskedSpriteWord MAC
|
||||
|
||||
; Need to fill in the first 14 bytes of the JMP handler with the following code sequence where
|
||||
; the data and mask from from the sprite plane
|
||||
;
|
||||
; lda ($00),y
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bra *+15
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0000,x ; LDA (00),y
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,x
|
||||
|
||||
lda tmp_sprite_mask+{]1}
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent ; so we can use the Tile00011 method
|
||||
sta: $0003,x
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $0006,x
|
||||
|
||||
lda _OP_CACHE2
|
||||
sta: $0008,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $000A,x ; ORA $00,x
|
||||
|
||||
lda #$0980 ; branch to the prologue (BRA *+11)
|
||||
sta: $000C,x
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda _OP_CACHE2
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
|
||||
lda #$0F80 ; branch to the epilogue (BRA *+17)
|
||||
sta: $0006,x
|
||||
next
|
||||
eom
|
||||
|
||||
; Helper functions to move tile data into the dynamic tile space
|
||||
|
||||
; Helper functions to copy tile data to the appropriate location in Bank 0
|
||||
; X = tile ID
|
||||
; Y = dynamic tile ID
|
||||
CopyTileToDyn
|
||||
txa
|
||||
jsr _GetTileAddr
|
||||
tax
|
||||
|
||||
tya
|
||||
and #$001F ; Maximum of 32 dynamic tiles
|
||||
asl
|
||||
asl ; 4 bytes per page
|
||||
adc BlitterDP ; Add to the bank 00 base address
|
||||
adc #$0100 ; Go to the next page
|
||||
tay
|
||||
jsr CopyTileDToDyn ; Copy the tile data
|
||||
jmp CopyTileMToDyn ; Copy the tile mask
|
||||
|
||||
; X = address of tile
|
||||
; Y = tile address in bank 0
|
||||
CopyTileDToDyn
|
||||
phb
|
||||
pea $0000
|
||||
plb
|
||||
plb
|
||||
|
||||
ldal tiledata+0,x
|
||||
sta: $0000,y
|
||||
ldal tiledata+2,x
|
||||
sta: $0002,y
|
||||
ldal tiledata+4,x
|
||||
sta $0100,y
|
||||
ldal tiledata+6,x
|
||||
sta $0102,y
|
||||
ldal tiledata+8,x
|
||||
sta $0200,y
|
||||
ldal tiledata+10,x
|
||||
sta $0202,y
|
||||
ldal tiledata+12,x
|
||||
sta $0300,y
|
||||
ldal tiledata+14,x
|
||||
sta $0302,y
|
||||
ldal tiledata+16,x
|
||||
sta $0400,y
|
||||
ldal tiledata+18,x
|
||||
sta $0402,y
|
||||
ldal tiledata+20,x
|
||||
sta $0500,y
|
||||
ldal tiledata+22,x
|
||||
sta $0502,y
|
||||
ldal tiledata+24,x
|
||||
sta $0600,y
|
||||
ldal tiledata+26,x
|
||||
sta $0602,y
|
||||
ldal tiledata+28,x
|
||||
sta $0700,y
|
||||
ldal tiledata+30,x
|
||||
sta $0702,y
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; Helper function to copy tile mask to the appropriate location in Bank 0
|
||||
;
|
||||
; X = address of tile
|
||||
; Y = tile address in bank 0
|
||||
;
|
||||
; Argument are the same as CopyTileDToDyn, the code takes care of adjust offsets.
|
||||
; This make is possible to call the two functions back-to-back
|
||||
;
|
||||
; ldx tileAddr
|
||||
; ldy dynTileAddr
|
||||
; jsr CopyTileDToDyn
|
||||
; jsr CopyTileMToDyn
|
||||
CopyTileMToDyn
|
||||
phb
|
||||
pea $0000
|
||||
plb
|
||||
plb
|
||||
|
||||
ldal tiledata+32+0,x
|
||||
sta: $0080,y
|
||||
ldal tiledata+32+2,x
|
||||
sta: $0082,y
|
||||
ldal tiledata+32+4,x
|
||||
sta $0180,y
|
||||
ldal tiledata+32+6,x
|
||||
sta $0182,y
|
||||
ldal tiledata+32+8,x
|
||||
sta $0280,y
|
||||
ldal tiledata+32+10,x
|
||||
sta $0282,y
|
||||
ldal tiledata+32+12,x
|
||||
sta $0380,y
|
||||
ldal tiledata+32+14,x
|
||||
sta $0382,y
|
||||
ldal tiledata+32+16,x
|
||||
sta $0480,y
|
||||
ldal tiledata+32+18,x
|
||||
sta $0482,y
|
||||
ldal tiledata+32+20,x
|
||||
sta $0580,y
|
||||
ldal tiledata+32+22,x
|
||||
sta $0582,y
|
||||
ldal tiledata+32+24,x
|
||||
sta $0680,y
|
||||
ldal tiledata+32+26,x
|
||||
sta $0682,y
|
||||
ldal tiledata+32+28,x
|
||||
sta $0780,y
|
||||
ldal tiledata+32+30,x
|
||||
sta $0782,y
|
||||
|
||||
plb
|
||||
rts
|
|
@ -0,0 +1,258 @@
|
|||
; Collection of render function used when the engine is in "FAST" mode. In this mode
|
||||
; there are no dynamic tile or two layer tiles enabled, so all of the tiles are comprised
|
||||
; of PEA opcodes. These functions take advantage of this as the fact that masks are
|
||||
; not needed to improve rendering speed.
|
||||
|
||||
ConstTile0Fast
|
||||
lda #0
|
||||
sta: $0001,y
|
||||
sta: $0004,y
|
||||
sta $1001,y
|
||||
sta $1004,y
|
||||
sta $2001,y
|
||||
sta $2004,y
|
||||
sta $3001,y
|
||||
sta $3004,y
|
||||
sta $4001,y
|
||||
sta $4004,y
|
||||
sta $5001,y
|
||||
sta $5004,y
|
||||
sta $6001,y
|
||||
sta $6004,y
|
||||
sta $7001,y
|
||||
sta $7004,y
|
||||
plb
|
||||
rts
|
||||
|
||||
SpriteOverAFast
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
plb
|
||||
|
||||
_SpriteOverAFast ; Alternate entry point for the "Slow" routines
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
and tmp_sprite_mask+{]line*4}
|
||||
ora tmp_sprite_data+{]line*4}
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
and tmp_sprite_mask+{]line*4}+2
|
||||
ora tmp_sprite_data+{]line*4}+2
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
SpriteOverVFast
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
plb
|
||||
|
||||
_SpriteOverVFast
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
and tmp_sprite_mask+{]dest*4}
|
||||
ora tmp_sprite_data+{]dest*4}
|
||||
sta: $0004+{]dest*$1000},y
|
||||
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
and tmp_sprite_mask+{]dest*4}+2
|
||||
ora tmp_sprite_data+{]dest*4}+2
|
||||
sta: $0001+{]dest*$1000},y
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
plb
|
||||
rts
|
||||
|
||||
SpriteOver0Fast
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
plb
|
||||
|
||||
_SpriteOver0Fast
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda tmp_sprite_data+{]line*4}
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
lda tmp_sprite_data+{]line*4}+2
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
SpriteUnderAFast
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
plb
|
||||
|
||||
_SpriteUnderAFast
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda tmp_sprite_data+{]line*4}
|
||||
andl tiledata+{]line*4}+32,x
|
||||
oral tiledata+{]line*4},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
lda tmp_sprite_data+{]line*4}+2
|
||||
andl tiledata+{]line*4}+32+2,x
|
||||
oral tiledata+{]line*4}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
SpriteUnderVFast
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
plb
|
||||
|
||||
_SpriteUnderVFast
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
lda tmp_sprite_data+{]dest*4}
|
||||
andl tiledata+{]src*4}+32,x
|
||||
oral tiledata+{]src*4},x
|
||||
sta: $0004+{]dest*$1000},y
|
||||
|
||||
lda tmp_sprite_data+{]dest*4}+2
|
||||
andl tiledata+{]src*4}+32+2,x
|
||||
oral tiledata+{]src*4}+2,x
|
||||
sta: $0001+{]dest*$1000},y
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
SpriteUnder0Fast
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
plb
|
||||
|
||||
_SpriteUnder0Fast
|
||||
lda #0
|
||||
]line equ 0
|
||||
lup 8
|
||||
sta: $0004+{]line*$1000},y
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; Simple pair of routines that copies just the tile data to the direct page workspace. Data Bank
|
||||
; must be set to the TileData bank in entry.
|
||||
;
|
||||
; Preserves the X-register
|
||||
FastCopyTileDataA
|
||||
ldy TileStore+TS_TILE_ADDR,x ; load the tile address
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb ; set to the tiledata bank
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda tiledata+{]line*4},y
|
||||
sta tmp_tile_data+{]line*4}
|
||||
|
||||
lda tiledata+{]line*4}+2,y
|
||||
sta tmp_tile_data+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
FastCopyTileDataV
|
||||
ldy TileStore+TS_TILE_ADDR,x ; load the tile address
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb ; set to the tiledata bank
|
||||
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
lda tiledata+{]src*4},y
|
||||
sta tmp_tile_data+{]dest*4}
|
||||
|
||||
lda tiledata+{]src*4}+2,y
|
||||
sta tmp_tile_data+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
FastCopyTileDataAndMaskA
|
||||
ldy TileStore+TS_TILE_ADDR,x ; load the tile address
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb ; set to the tiledata bank
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda tiledata+{]line*4},y
|
||||
sta tmp_tile_data+{]line*4}
|
||||
lda tiledata+{]line*4}+32,y
|
||||
sta tmp_tile_mask+{]line*4}
|
||||
|
||||
lda tiledata+{]line*4}+2,y
|
||||
sta tmp_tile_data+{]line*4}+2
|
||||
lda tiledata+{]line*4}+32+2,y
|
||||
sta tmp_tile_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
FastCopyTileDataAndMaskV
|
||||
ldy TileStore+TS_TILE_ADDR,x ; load the tile address
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb ; set to the tiledata bank
|
||||
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
lda tiledata+{]src*4},y
|
||||
sta tmp_tile_data+{]dest*4}
|
||||
lda tiledata+{]src*4}+32,y
|
||||
sta tmp_tile_mask+{]dest*4}
|
||||
|
||||
lda tiledata+{]src*4}+2,y
|
||||
sta tmp_tile_data+{]dest*4}+2
|
||||
lda tiledata+{]src*4}+32+2,y
|
||||
sta tmp_tile_mask+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
|
@ -0,0 +1,83 @@
|
|||
This folder contains the rendering tuples for the different type of tile rendering modes
|
||||
that are defined by both the engine mode and the specific tile attributes. There are
|
||||
a *lot* or variants, so they are cataloged here.
|
||||
|
||||
The top-level TileRender function in the main entry point that defined the overal tile render
|
||||
flow as well as the register parameters and calling conventions for each of the modular
|
||||
components.
|
||||
|
||||
There are 5 pluggable functions that make up a rendering mode
|
||||
|
||||
1. K_TS_BASE_TILE_DISP
|
||||
|
||||
An address to a function that will render a tile into the code field. There are no
|
||||
sprites to handle in this case.
|
||||
|
||||
Arguments:
|
||||
A: TileData/TileMask address
|
||||
B: code field bank
|
||||
Y: address of the tile in the code bank
|
||||
X: TileStore offset
|
||||
|
||||
Return:
|
||||
None
|
||||
|
||||
If additional TileStore properties are needed for the renderer, they can be read using the X
|
||||
register.
|
||||
|
||||
2. K_TS_SPRITE_TILE_DISP
|
||||
|
||||
Selects the top-level handler for rendering a tile with a sprite. Currently, this is used to
|
||||
select between rendering a sprite above the tile, or under the tile based on the value of the
|
||||
TILE_PRIORITY_BIT.
|
||||
|
||||
Arguments:
|
||||
A: TileStore+TS_SPRITE_FLAG
|
||||
X: TileStore offset
|
||||
|
||||
Return:
|
||||
Y: TileStore offset
|
||||
sprite_ptrX dirct page values set to the sprite VBuff addresses
|
||||
|
||||
The handler routine is responsible for examining the TS_SPRITE_FLAG value and dispatching
|
||||
to an appropriate routine to handle the number of sprites intersecting the tile.
|
||||
|
||||
3. K_TS_ONE_SPRITE
|
||||
|
||||
A specialized routine when K_TS_SPRITE_TILE_DISP determines there is only one sprite to render
|
||||
it MUST dispatch to this function. The K_TS_ONE_SPRITE routine MAY make use of the K_TS_COPY_TILE_DATA
|
||||
and K_TS_APPLY_TILE_DATA functions, but is not required to do so.
|
||||
|
||||
4. K_TS_COPY_TILE_DATA & K_TS_APPLY_TILE_DATA
|
||||
|
||||
A pair of function that copye tile data (and possible mask information) into a temporary
|
||||
direct page space and then render that workspace into the code field.
|
||||
|
||||
These functions are used as building blocks by the generic Over/Under multi-sprite
|
||||
rendering code.
|
||||
|
||||
K_TS_COPY_TILE_DATA
|
||||
Arguments:
|
||||
B: Set to the TileData bank
|
||||
Y: Set to the tile address
|
||||
Return:
|
||||
X: preserve the X register
|
||||
|
||||
K_TS_APPLY_TILE_DATA
|
||||
Arguments:
|
||||
B: code field bank
|
||||
Y: address of the tile in the code bank
|
||||
Return:
|
||||
None
|
||||
|
||||
|
||||
|
||||
Generic Flow
|
||||
|
||||
1. Is there a sprite?
|
||||
No -> Call K_TS_BASE_TILE_DISP to render a tile into the code field
|
||||
|
||||
Yes -> Call K_TS_SPRITE_TILE_DISP
|
||||
|
||||
Over : Copy tile data + mask to DP, Copy sprite data + mask to DP, render tile to code field
|
||||
Under : Copy sprite data to DP,
|
|
@ -0,0 +1,86 @@
|
|||
; If there are no sprites, then we copy the tile data into the code field as fast as possible.
|
||||
; If there are sprites, then additional work is required
|
||||
_RenderTile
|
||||
lda TileStore+TS_SPRITE_FLAG,x ; any sprites on this line?
|
||||
bne :sprites
|
||||
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated)
|
||||
plb ; set the code field bank
|
||||
jmp (K_TS_BASE_TILE_DISP,x) ; go to the tile copy routine
|
||||
|
||||
; Execute the sprite tree. If there is only one sprite, control will immediately be passed to
|
||||
; the routine at K_TS_ONE_SPRITE. Otherwise, the control passed to the routines with a different
|
||||
; number of sprites. These routines need to copy the flattened sprite data and mask into the
|
||||
; direct page workspace to be used by the K_TS_SPRITE_TILE_DISP routine
|
||||
:sprites txy
|
||||
SpriteBitsToVBuffAddrs $0000;TwoSprites;ThreeSprites;FourSprites
|
||||
|
||||
; Dispatch vectors for the two, three and four sprite functions. These just
|
||||
; flatten the sprite data into the direct page workspace and then pass control
|
||||
; to the configurable routine which is set in SetTile and knows what to do
|
||||
; based on the tile properties (over/under, engine mode, etc.)
|
||||
;
|
||||
; NOTE: Could pull the CopyXXXSprites function inline and same the 3 cycles for the JMP,
|
||||
; - or - put the TYX into the macro and jump directly from there.
|
||||
TwoSprites tyx
|
||||
jmp CopyTwoSpritesDataAndMaskToDP
|
||||
|
||||
ThreeSprites tyx
|
||||
jmp CopyThreeSpritesDataAndMaskToDP
|
||||
|
||||
FourSprites tyx
|
||||
jmp CopyFourSpritesDataAndMaskToDP
|
||||
|
||||
; Now, implement the generic Two, Three and Four sprite routines for both Over and Under rendering. These
|
||||
; are fairly involved, so we try to only have a single implementation of them for now without excessve
|
||||
; specialization.
|
||||
|
||||
|
||||
FourSpriteLine mac
|
||||
; and [sprite_ptr3],y
|
||||
db $37,sprite_ptr3
|
||||
ora (sprite_ptr3),y
|
||||
; and [sprite_ptr2],y
|
||||
db $37,sprite_ptr2
|
||||
ora (sprite_ptr2),y
|
||||
; and [sprite_ptr1],y
|
||||
db $37,sprite_ptr1
|
||||
ora (sprite_ptr1),y
|
||||
; and [sprite_ptr0],y
|
||||
db $37,sprite_ptr0
|
||||
ora (sprite_ptr0),y
|
||||
<<<
|
||||
|
||||
FourSpritesFast
|
||||
tyx ; save for after compositing the sprites
|
||||
|
||||
ldy TileStore+TS_TILE_ADDR,x
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb
|
||||
jsr (K_TS_COPY_TILE_DATA,x)
|
||||
plb
|
||||
|
||||
pei DP2_SPRITEDATA_AND_TILESTORE_BANKS
|
||||
plb ; set the sprite data bank
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldy #{]line*SPRITE_PLANE_SPAN}
|
||||
lda tmp_tile_data+{]line*4}
|
||||
FourSpriteLine
|
||||
sta tmp_tile_data+{]line*4}
|
||||
|
||||
ldy #{]line*SPRITE_PLANE_SPAN}+2
|
||||
lda tmp_tile_data+{]line*4}+2
|
||||
FourSpriteLine
|
||||
sta tmp_tile_data+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
jmp (K_TS_APPLY_TILE_DATA,x)
|
||||
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
; Identical routines to those in Fast.s, but also set the opcode. Used to render solid
|
||||
; tiles when the engine mode has other capabilities turned on
|
||||
;
|
||||
; The following functions are defined here
|
||||
;
|
||||
; GenericOverSlow : Places data from tmp_sprite_data on top of the TileStore's tile
|
||||
; GenericUnderSlow : Places the TileStore's tile on top of tmp_sprite_data
|
||||
|
||||
ConstTile0Slow
|
||||
jsr FillPEAOpcode
|
||||
jmp ConstTile0Fast
|
||||
|
||||
SpriteOverASlow
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _SpriteOverAFast
|
||||
|
||||
SpriteOverVSlow
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _SpriteOverVFast
|
||||
|
||||
SpriteOver0Slow
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _SpriteOver0Fast
|
||||
|
||||
SpriteUnderASlow
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _SpriteUnderAFast
|
||||
|
||||
SpriteUnderVSlow
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
lda TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _SpriteUnderVFast
|
||||
|
||||
SpriteUnder0Slow
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _SpriteUnder0Fast
|
||||
|
||||
; Helper function; no stack manipulation
|
||||
FillPEAOpcode
|
||||
sep #$20
|
||||
lda #$F4
|
||||
]line equ 0
|
||||
lup 8
|
||||
sta: $0000+{]line*$1000},y
|
||||
sta: $0003+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; This is a stub; will be removed eventually
|
||||
_FillPEAOpcode
|
||||
jsr FillPEAOpcode
|
||||
plb ; Restore the TileStore bank
|
||||
rts
|
|
@ -0,0 +1,265 @@
|
|||
; Specialized routines that can be assigned to K_TS_ONE_SPRITE for rendering a single sprite into
|
||||
; a tile. There are more variants of this function because having a single sprite in a tile is a very
|
||||
; common scenario, so we put additional effort into optimizing this case.
|
||||
|
||||
;------------------------------
|
||||
; Section: Above Tile Renderers
|
||||
|
||||
; The simplest implementation. When drawing a sprite over Tile 0 in FAST mode, we can just copy the
|
||||
; sprite data into the coe field directly.
|
||||
|
||||
OneSpriteFastOver0
|
||||
ldy TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
phy ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
tax ; VBuff address from SpriteBitsToVBuffAddrs macro
|
||||
plb ; set to the code field bank
|
||||
|
||||
_OneSpriteFastOver0
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb ; Restore the TileStore bank
|
||||
rts
|
||||
|
||||
; Next implementation; drawing a sprite onto a regular tile. The 1-sprite dispatch preserves the
|
||||
; X-register, so it already points to the TileStore
|
||||
|
||||
OneSpriteFastOverV
|
||||
jsr FastCopyTileDataV
|
||||
bra _OneSpriteFastOver
|
||||
|
||||
OneSpriteFastOverA
|
||||
jsr FastCopyTileDataA
|
||||
|
||||
_OneSpriteFastOver
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
ldx sprite_ptr0
|
||||
plb
|
||||
|
||||
_OneSpriteFastOverA
|
||||
_OneSpriteFastOverV
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda tmp_tile_data+{]line*4}
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
lda tmp_tile_data+{]line*4}+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
plb
|
||||
rts
|
||||
|
||||
; This is the "SLOW" variant that fills in the PEA opcode specialized for Tile 0.
|
||||
|
||||
OneSpriteSlowOver0
|
||||
ldy TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
phy ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
tax ; VBuff address from SpriteBitsToVBuffAddrs macro
|
||||
plb ; set to the code field bank
|
||||
jsr FillPEAOpcode
|
||||
jmp _OneSpriteFastOver0
|
||||
|
||||
; Slow variant for regular tile.
|
||||
OneSpriteSlowOverV
|
||||
jsr FastCopyTileDataV
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
ldx sprite_ptr0
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _OneSpriteFastOverV
|
||||
|
||||
OneSpriteSlowOverA
|
||||
jsr FastCopyTileDataA
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
ldx sprite_ptr0
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _OneSpriteFastOverA
|
||||
|
||||
;------------------------------
|
||||
; Section: Below Tile Renderers
|
||||
|
||||
; Drawing under the zero tile is the same as not drawing a sprite fo both the fast and slow cases
|
||||
OneSpriteFastUnderA
|
||||
jsr FastCopyTileDataAndMaskA
|
||||
bra _OneSpriteFastUnder
|
||||
|
||||
OneSpriteFastUnderV
|
||||
jsr FastCopyTileDataAndMaskV
|
||||
|
||||
_OneSpriteFastUnder
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
ldx sprite_ptr0
|
||||
plb
|
||||
|
||||
_OneSpriteFastUnderA
|
||||
_OneSpriteFastUnderV
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
and tmp_tile_mask+{]line*4}
|
||||
ora tmp_tile_data+{]line*4}
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
and tmp_tile_mask+{]line*4}+2
|
||||
ora tmp_tile_data+{]line*4}+2
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
OneSpriteSlowUnderA
|
||||
jsr FastCopyTileDataAndMaskA
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
ldx sprite_ptr0
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _OneSpriteFastUnderA
|
||||
|
||||
OneSpriteSlowUnderV
|
||||
jsr FastCopyTileDataAndMaskV
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
pha ; and put on the stack for later. Has TileStore bank in high byte.
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x ; load the address of the code field
|
||||
ldx sprite_ptr0
|
||||
plb
|
||||
jsr FillPEAOpcode
|
||||
jmp _OneSpriteFastUnderV
|
||||
|
||||
;-------------------------------
|
||||
; Dynamic tiles with one sprite.
|
||||
|
||||
OneSpriteDynamicUnder
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataToDP
|
||||
tyx
|
||||
jmp DynamicUnder
|
||||
|
||||
OneSpriteDynamicOver
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataAndMaskToDP
|
||||
tyx
|
||||
jmp DynamicOver
|
||||
|
||||
|
||||
;-------------------------------
|
||||
; Two Layer tiles with one sprite. Just copy the data and go through the generic sprite path
|
||||
OneSpriteOver0TwoLyr
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataAndMaskToDP
|
||||
tyx
|
||||
jmp SpriteOver0TwoLyr
|
||||
|
||||
OneSpriteTwoLyrOverA
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataAndMaskToDP
|
||||
tyx
|
||||
jmp SpriteOverATwoLyr
|
||||
|
||||
OneSpriteTwoLyrOverV
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataAndMaskToDP
|
||||
tyx
|
||||
jmp SpriteOverVTwoLyr
|
||||
|
||||
OneSpriteTwoLyrUnderA
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataAndMaskToDP
|
||||
tyx
|
||||
jmp SpriteUnderATwoLyr
|
||||
|
||||
OneSpriteTwoLyrUnderV
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataAndMaskToDP
|
||||
tyx
|
||||
jmp SpriteUnderVTwoLyr
|
||||
|
||||
;-----------------------------------------
|
||||
; Dynamic two-layer tiles with one sprite.
|
||||
|
||||
OneSpriteDynamicOverTwoLyr
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataAndMaskToDP
|
||||
tyx
|
||||
jmp DynamicOverTwoLyr
|
||||
|
||||
OneSpriteDynamicUnderTwoLyr
|
||||
txy
|
||||
tax
|
||||
jsr _CopySpriteDataAndMaskToDP
|
||||
tyx
|
||||
jmp DynamicUnderTwoLyr
|
||||
|
||||
;-------------------------------------
|
||||
; Generic helpers
|
||||
_CopySpriteDataToDP
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta tmp_sprite_data+{]line*4}
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta tmp_sprite_data+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_CopySpriteMaskToDP
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta tmp_sprite_mask+{]line*4}
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta tmp_sprite_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_CopySpriteDataAndMaskToDP
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta tmp_sprite_data+{]line*4}
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta tmp_sprite_data+{]line*4}+2
|
||||
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta tmp_sprite_mask+{]line*4}
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta tmp_sprite_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
|
@ -0,0 +1,37 @@
|
|||
; Specialize routines for handling two sprites.
|
||||
TwoSpriteData mac
|
||||
lda (sprite_ptr1),y
|
||||
db $37,sprite_ptr0 ; and [sprite_ptr0],y
|
||||
ora (sprite_ptr0),y
|
||||
<<<
|
||||
|
||||
TwoSpriteMask mac
|
||||
db $B7,sprite_ptr1 ; lda [sprite_ptr1],y
|
||||
db $37,sprite_ptr0 ; and [sprite_ptr0],y
|
||||
<<<
|
||||
|
||||
CopyFourSpritesDataAndMaskToDP
|
||||
CopyThreeSpritesDataAndMaskToDP
|
||||
CopyTwoSpritesDataAndMaskToDP
|
||||
pei DP2_SPRITEDATA_AND_TILESTORE_BANKS
|
||||
plb
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldy #{]line*SPRITE_PLANE_SPAN}
|
||||
TwoSpriteData
|
||||
sta tmp_sprite_data+{]line*4}
|
||||
TwoSpriteMask
|
||||
sta tmp_sprite_mask+{]line*4}
|
||||
|
||||
ldy #{]line*SPRITE_PLANE_SPAN}+2
|
||||
TwoSpriteData
|
||||
sta tmp_sprite_data+{]line*4}+2
|
||||
TwoSpriteMask
|
||||
sta tmp_sprite_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
jmp (K_TS_SPRITE_TILE_DISP,x)
|
||||
|
|
@ -0,0 +1,376 @@
|
|||
; Collection of render function used when the engine is in "Two Layer" mode. Other than the Tile 0
|
||||
; routines, there's nothing in here that is particularly well optimized.
|
||||
|
||||
Tile0TwoLyr
|
||||
ldal TileStore+TS_WORD_OFFSET,x
|
||||
and #$00FF
|
||||
ora #$4800
|
||||
sta: $0004,y
|
||||
sta $1004,y
|
||||
sta $2004,y
|
||||
sta $3004,y
|
||||
sta $4004,y
|
||||
sta $5004,y
|
||||
sta $6004,y
|
||||
sta $7004,y
|
||||
inc
|
||||
inc
|
||||
sta: $0001,y
|
||||
sta $1001,y
|
||||
sta $2001,y
|
||||
sta $3001,y
|
||||
sta $4001,y
|
||||
sta $5001,y
|
||||
sta $6001,y
|
||||
sta $7001,y
|
||||
|
||||
sep #$20
|
||||
lda #$B1 ; This is a special case where we can set all the words to LDA (DP),y
|
||||
sta: $0000,y
|
||||
sta: $0003,y
|
||||
sta $1000,y
|
||||
sta $1003,y
|
||||
sta $2000,y
|
||||
sta $2003,y
|
||||
sta $3000,y
|
||||
sta $3003,y
|
||||
sta $4000,y
|
||||
sta $4003,y
|
||||
sta $5000,y
|
||||
sta $5003,y
|
||||
sta $6000,y
|
||||
sta $6003,y
|
||||
sta $7000,y
|
||||
sta $7003,y
|
||||
rep #$20
|
||||
plb
|
||||
rts
|
||||
|
||||
; Draw from the sprite buffer into a fully transparent tile
|
||||
SpriteOver0TwoLyr
|
||||
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x
|
||||
pha
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x
|
||||
plb
|
||||
|
||||
CopyTwoLayerOver tmp_sprite_data+0;$0003
|
||||
CopyTwoLayerOver tmp_sprite_data+4;$1003
|
||||
CopyTwoLayerOver tmp_sprite_data+8;$2003
|
||||
CopyTwoLayerOver tmp_sprite_data+12;$3003
|
||||
CopyTwoLayerOver tmp_sprite_data+16;$4003
|
||||
CopyTwoLayerOver tmp_sprite_data+20;$5003
|
||||
CopyTwoLayerOver tmp_sprite_data+24;$6003
|
||||
CopyTwoLayerOver tmp_sprite_data+28;$7003
|
||||
|
||||
sec
|
||||
lda _JTBL_CACHE
|
||||
sbc #SNIPPET_SIZE ; Advance to the next snippet (Reverse indexing)
|
||||
sta _JTBL_CACHE
|
||||
|
||||
clc
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
CopyTwoLayerOver tmp_sprite_data+2;$0000
|
||||
CopyTwoLayerOver tmp_sprite_data+6;$1000
|
||||
CopyTwoLayerOver tmp_sprite_data+10;$2000
|
||||
CopyTwoLayerOver tmp_sprite_data+14;$3000
|
||||
CopyTwoLayerOver tmp_sprite_data+18;$4000
|
||||
CopyTwoLayerOver tmp_sprite_data+22;$5000
|
||||
CopyTwoLayerOver tmp_sprite_data+26;$6000
|
||||
CopyTwoLayerOver tmp_sprite_data+30;$7000
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
TmpTileDataToCodeField
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x
|
||||
pha
|
||||
ldy TileStore+TS_CODE_ADDR_LOW,x
|
||||
plb
|
||||
|
||||
_TmpTileDataToCodeField
|
||||
|
||||
CopyTwoLayerOver tmp_tile_data+0;$0003
|
||||
CopyTwoLayerOver tmp_tile_data+4;$1003
|
||||
CopyTwoLayerOver tmp_tile_data+8;$2003
|
||||
CopyTwoLayerOver tmp_tile_data+12;$3003
|
||||
CopyTwoLayerOver tmp_tile_data+16;$4003
|
||||
CopyTwoLayerOver tmp_tile_data+20;$5003
|
||||
CopyTwoLayerOver tmp_tile_data+24;$6003
|
||||
CopyTwoLayerOver tmp_tile_data+28;$7003
|
||||
|
||||
sec
|
||||
lda _JTBL_CACHE
|
||||
sbc #SNIPPET_SIZE ; Advance to the next snippet (Reverse indexing)
|
||||
sta _JTBL_CACHE
|
||||
|
||||
clc
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
CopyTwoLayerOver tmp_tile_data+2;$0000
|
||||
CopyTwoLayerOver tmp_tile_data+6;$1000
|
||||
CopyTwoLayerOver tmp_tile_data+10;$2000
|
||||
CopyTwoLayerOver tmp_tile_data+14;$3000
|
||||
CopyTwoLayerOver tmp_tile_data+18;$4000
|
||||
CopyTwoLayerOver tmp_tile_data+22;$5000
|
||||
CopyTwoLayerOver tmp_tile_data+26;$6000
|
||||
CopyTwoLayerOver tmp_tile_data+30;$7000
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
; Copy a tile into the tile data buffer and then render to the code field
|
||||
CopyTileATwoLyr
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
ldal TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta tmp_tile_data+{]line*4}
|
||||
ldal tiledata+{]line*4}+32,x
|
||||
sta tmp_tile_mask+{]line*4}
|
||||
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta tmp_tile_data+{]line*4}+2
|
||||
ldal tiledata+{]line*4}+32+2,x
|
||||
sta tmp_tile_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
jmp _TmpTileDataToCodeField
|
||||
|
||||
CopyTileVTwoLyr
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
ldal TileStore+TS_TILE_ADDR,x
|
||||
tax
|
||||
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta tmp_tile_data+{]dest*4}
|
||||
ldal tiledata+{]src*4}+32,x
|
||||
sta tmp_tile_mask+{]dest*4}
|
||||
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta tmp_tile_data+{]dest*4}+2
|
||||
ldal tiledata+{]src*4}+32+2,x
|
||||
sta tmp_tile_mask+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
jmp _TmpTileDataToCodeField
|
||||
|
||||
; Handle sprites + tiles. Strategy is to merge the sprite and tile data and write it to the
|
||||
; temporary space an defer the actual work to the _TmpTileDataToCodeField helper
|
||||
SpriteOverATwoLyr
|
||||
ldy TileStore+TS_TILE_ADDR,x
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda tiledata+{]line*4},y
|
||||
and tmp_sprite_mask+{]line*4}
|
||||
ora tmp_sprite_data+{]line*4}
|
||||
sta tmp_tile_data+{]line*4}
|
||||
|
||||
lda tiledata+{]line*4}+32,y
|
||||
and tmp_sprite_mask+{]line*4}
|
||||
sta tmp_tile_mask+{]line*4}
|
||||
|
||||
lda tiledata+{]line*4}+2,y
|
||||
and tmp_sprite_mask+{]line*4}+2
|
||||
ora tmp_sprite_data+{]line*4}+2
|
||||
sta tmp_tile_data+{]line*4}+2
|
||||
|
||||
lda tiledata+{]line*4}+32+2,y
|
||||
and tmp_sprite_mask+{]line*4}+2
|
||||
sta tmp_tile_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
plb
|
||||
jmp TmpTileDataToCodeField
|
||||
|
||||
SpriteOverVTwoLyr
|
||||
ldy TileStore+TS_TILE_ADDR,x
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb
|
||||
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
lda tiledata+{]src*4},y
|
||||
and tmp_sprite_mask+{]dest*4}
|
||||
ora tmp_sprite_data+{]dest*4}
|
||||
sta tmp_tile_data+{]dest*4}
|
||||
|
||||
lda tiledata+{]src*4}+32,y
|
||||
and tmp_sprite_mask+{]dest*4}
|
||||
sta tmp_tile_mask+{]dest*4}
|
||||
|
||||
lda tiledata+{]src*4}+2,y
|
||||
and tmp_sprite_mask+{]dest*4}+2
|
||||
ora tmp_sprite_data+{]dest*4}+2
|
||||
sta tmp_tile_data+{]dest*4}+2
|
||||
|
||||
lda tiledata+{]src*4}+32+2,y
|
||||
and tmp_sprite_mask+{]dest*4}+2
|
||||
sta tmp_tile_mask+{]dest*4}+2
|
||||
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
plb
|
||||
jmp TmpTileDataToCodeField
|
||||
|
||||
SpriteUnderATwoLyr
|
||||
ldy TileStore+TS_TILE_ADDR,x
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda tmp_sprite_data+{]line*4}
|
||||
and tiledata+{]line*4}+32,y
|
||||
ora tiledata+{]line*4},y
|
||||
sta tmp_tile_data+{]line*4}
|
||||
|
||||
lda tiledata+{]line*4}+32,y
|
||||
and tmp_sprite_mask+{]line*4}
|
||||
sta tmp_tile_mask+{]line*4}
|
||||
|
||||
lda tmp_sprite_data+{]line*4}+2
|
||||
and tiledata+{]line*4}+32+2,y
|
||||
ora tiledata+{]line*4}+2,y
|
||||
sta tmp_tile_data+{]line*4}+2
|
||||
|
||||
lda tiledata+{]line*4}+32+2,y
|
||||
and tmp_sprite_mask+{]line*4}+2
|
||||
sta tmp_tile_mask+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
plb
|
||||
jmp TmpTileDataToCodeField
|
||||
|
||||
SpriteUnderVTwoLyr
|
||||
ldy TileStore+TS_TILE_ADDR,x
|
||||
pei DP2_TILEDATA_AND_TILESTORE_BANKS
|
||||
plb
|
||||
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
lda tmp_sprite_data+{]dest*4}
|
||||
and tiledata+{]src*4}+32,y
|
||||
ora tiledata+{]src*4},y
|
||||
sta tmp_tile_data+{]dest*4}
|
||||
|
||||
lda tiledata+{]src*4}+32,y
|
||||
and tmp_sprite_mask+{]dest*4}
|
||||
sta tmp_tile_mask+{]dest*4}
|
||||
|
||||
lda tmp_sprite_data+{]dest*4}+2
|
||||
and tiledata+{]src*4}+32+2,y
|
||||
ora tiledata+{]src*4}+2,y
|
||||
sta tmp_tile_data+{]dest*4}+2
|
||||
|
||||
lda tiledata+{]src*4}+32+2,y
|
||||
and tmp_sprite_mask+{]dest*4}+2
|
||||
sta tmp_tile_mask+{]dest*4}+2
|
||||
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
plb
|
||||
jmp TmpTileDataToCodeField
|
||||
|
||||
; Macro to fill in the code field from a direct page temporary buffer
|
||||
;
|
||||
; ]1 : direct page address with data, the mask direct page address is data + 32
|
||||
; ]2 : code field offset
|
||||
;
|
||||
; Y is the code field address
|
||||
CopyTwoLayerOver mac
|
||||
lda {]1}+32 ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
lda {]1} ; load the tile data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
mixed cmp #$FFFF ; All 1's in the mask is fully transparent
|
||||
beq transparent
|
||||
|
||||
lda #$004C ; JMP instruction
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda #$29
|
||||
sta: $0002,x ; AND #$0000 opcode
|
||||
lda #$09
|
||||
sta: $0005,x ; ORA #$0000 opcode
|
||||
|
||||
lda _OP_CACHE ; Get the LDA (dp),y instruction for this column
|
||||
sta: $0000,x
|
||||
|
||||
lda {]1}+32 ; insert the tile mask and data into the exception
|
||||
sta: $0003,x ; handler.
|
||||
lda {]1}
|
||||
sta: $0006,x
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,x
|
||||
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the second background layer
|
||||
transparent
|
||||
lda #$4800 ; put a PHA after the offset
|
||||
sta: {]2}+1,y
|
||||
lda _OP_CACHE
|
||||
sta: {]2},y
|
||||
next
|
||||
eom
|
|
@ -0,0 +1,92 @@
|
|||
; Functions to handle rendering sprites into 8x8 tile buffers for dirty tile rendering. Because we
|
||||
; are rendering directly to the graphics screen instead of the code field, we can map the direct
|
||||
; page into Bank 01 and use that to avoid writing the merge sprite and tile data to an intermediate
|
||||
; buffer.
|
||||
|
||||
;DirtyTileSpriteProcs dw _TBDirtySpriteTile_00,_TBDirtySpriteTile_0H,_TBDirtySpriteTile_V0,_TBDirtySpriteTile_VH
|
||||
|
||||
; Optimization Note: The single-sprite blitter seems like it could be made faster by taking advantage of
|
||||
; the fact that only a single set of sprite data needs to be read, but the extra overhead
|
||||
; of using the direct page and setting up and restoring registers wipes out the 2 cycle
|
||||
; per word advantage.
|
||||
;
|
||||
; A = screen address
|
||||
; X = address of sprite data
|
||||
; Y = address of tile data
|
||||
; B = tile data bank
|
||||
|
||||
_OneDirtySprite_00
|
||||
_OneDirtySprite_0H
|
||||
|
||||
phd
|
||||
sei
|
||||
clc
|
||||
tcd
|
||||
_R0W1
|
||||
|
||||
_ODS_Line 0,0,$0
|
||||
_ODS_Line 1,1,$A0
|
||||
tdc
|
||||
adc #320
|
||||
tcd
|
||||
_ODS_Line 2,2,$0
|
||||
_ODS_Line 3,3,$A0
|
||||
tdc
|
||||
adc #320
|
||||
tcd
|
||||
_ODS_Line 4,4,$0
|
||||
_ODS_Line 5,5,$A0
|
||||
tdc
|
||||
adc #320
|
||||
tcd
|
||||
_ODS_Line 6,6,$0
|
||||
_ODS_Line 7,7,$A0
|
||||
|
||||
_R0W0
|
||||
cli
|
||||
pld
|
||||
rts
|
||||
|
||||
|
||||
_OneDirtySprite_V0
|
||||
_OneDirtySprite_VH
|
||||
phd
|
||||
sei
|
||||
clc
|
||||
tcd
|
||||
_R0W1
|
||||
|
||||
_ODS_Line 0,7,$0
|
||||
_ODS_Line 1,6,$A0
|
||||
tdc
|
||||
adc #320
|
||||
tcd
|
||||
_ODS_Line 2,5,$0
|
||||
_ODS_Line 3,4,$A0
|
||||
tdc
|
||||
adc #320
|
||||
tcd
|
||||
_ODS_Line 4,3,$0
|
||||
_ODS_Line 5,2,$A0
|
||||
tdc
|
||||
adc #320
|
||||
tcd
|
||||
_ODS_Line 6,1,$0
|
||||
_ODS_Line 7,0,$A0
|
||||
|
||||
_R0W0
|
||||
cli
|
||||
pld
|
||||
rts
|
||||
|
||||
|
||||
; Build up from here
|
||||
_FourDirtySprites
|
||||
lda TileStore+TS_VBUFF_ADDR_0,y
|
||||
sta spriteIdx
|
||||
lda TileStore+TS_VBUFF_ADDR_1,y
|
||||
sta spriteIdx+4
|
||||
lda TileStore+TS_VBUFF_ADDR_2,y
|
||||
sta spriteIdx+8
|
||||
lda TileStore+TS_VBUFF_ADDR_3,y
|
||||
sta spriteIdx+12
|
|
@ -0,0 +1,150 @@
|
|||
; Functions to handle rendering sprite information into buffers for updates to the
|
||||
; code field. Due to lack of parallel structure, the sprites are combined with the
|
||||
; tile data and then written to a single direct page buffer. The data is read from
|
||||
; this buffer and then applied to the code field
|
||||
|
||||
; Merge a single block of sprite data with a tile
|
||||
_OneSprite_00
|
||||
_OneSprite_H0
|
||||
ldx TileStore+TS_VBUFF_ADDR_0,y
|
||||
lda TileStore+TS_TILE_ADDR,y
|
||||
tay
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda tiledata+{]line*TILE_DATA_SPAN},y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta tmp_sprite_data+{]line*4}
|
||||
|
||||
lda tiledata+{]line*TILE_DATA_SPAN}+2,y
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta tmp_sprite_data+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
_OneSprite_V0
|
||||
_OneSprite_VH
|
||||
ldx TileStore+TS_VBUFF_ADDR_0,y
|
||||
lda TileStore+TS_TILE_ADDR,y
|
||||
tay
|
||||
|
||||
]line equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
lda tiledata+{]line*TILE_DATA_SPAN},y
|
||||
andl spritemask+{]dest*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]dest*SPRITE_PLANE_SPAN},x
|
||||
sta tmp_sprite_data+{]dest*4}
|
||||
|
||||
lda tiledata+{]line*TILE_DATA_SPAN}+2,y
|
||||
andl spritemask+{]dest*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]dest*SPRITE_PLANE_SPAN}+2,x
|
||||
sta tmp_sprite_data+{]dest*4}+2
|
||||
]line equ ]line-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
|
||||
; Merge two blocks of sprite data. This is more involved because we need to use the
|
||||
; direct page pointers to stack the sprite information
|
||||
_TwoSprite_00
|
||||
_TwoSprite_H0
|
||||
lda TileStore+TS_VBUFF_ADDR_0,y
|
||||
sta sprite_0
|
||||
lda TileStore+TS_VBUFF_ADDR_1,y
|
||||
sta sprite_1
|
||||
ldx TileStore+TS_TILE_ADDR,y
|
||||
|
||||
; line 0
|
||||
lda tiledata+{0*TILE_DATA_SPAN},x
|
||||
and [sprite_1]
|
||||
ora (sprite_1)
|
||||
and [sprite_0]
|
||||
ora (sprite_0)
|
||||
sta tmp_sprite_data+{0*4}
|
||||
|
||||
ldy #{0*SPRITE_PLANE_SPAN}+2
|
||||
lda tiledata+{0*TILE_DATA_SPAN}+2,x
|
||||
and [sprite_1],y
|
||||
ora (sprite_1),y
|
||||
and [sprite_0],y
|
||||
ora (sprite_0),y
|
||||
sta tmp_sprite_data+{0*4}+2
|
||||
|
||||
; line 1
|
||||
ldy #{1*SPRITE_PLANE_SPAN}
|
||||
lda tiledata+{1*TILE_DATA_SPAN},x
|
||||
and [sprite_1],y
|
||||
ora (sprite_1),y
|
||||
and [sprite_0],y
|
||||
ora (sprite_0),y
|
||||
sta tmp_sprite_data+{1*4}
|
||||
|
||||
ldy #{1*SPRITE_PLANE_SPAN}+2
|
||||
lda tiledata+{1*TILE_DATA_SPAN}+2,x
|
||||
and [sprite_1],y
|
||||
ora (sprite_1),y
|
||||
and [sprite_0],y
|
||||
ora (sprite_0),y
|
||||
sta tmp_sprite_data+{1*4}+2
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; Merge three blocks of sprite data. This is more involved because we need to use the
|
||||
; direct page pointers to stack the sprite information
|
||||
_ThreeSprite_00
|
||||
_ThreeSprite_H0
|
||||
lda TileStore+TS_VBUFF_ADDR_0,y
|
||||
sta sprite_0
|
||||
lda TileStore+TS_VBUFF_ADDR_1,y
|
||||
sta sprite_1
|
||||
lda TileStore+TS_VBUFF_ADDR_2,y
|
||||
sta sprite_2
|
||||
ldx TileStore+TS_TILE_ADDR,y
|
||||
|
||||
; line 0
|
||||
lda tiledata+{0*TILE_DATA_SPAN},x
|
||||
and [sprite_2]
|
||||
ora (sprite_2)
|
||||
and [sprite_1]
|
||||
ora (sprite_1)
|
||||
and [sprite_0]
|
||||
ora (sprite_0)
|
||||
sta tmp_sprite_data+{0*4}
|
||||
|
||||
ldy #{0*SPRITE_PLANE_SPAN}+2
|
||||
lda tiledata+{0*TILE_DATA_SPAN}+2,x
|
||||
and [sprite_2],y
|
||||
ora (sprite_2),y
|
||||
and [sprite_1],y
|
||||
ora (sprite_1),y
|
||||
and [sprite_0],y
|
||||
ora (sprite_0),y
|
||||
sta tmp_sprite_data+{0*4}+2
|
||||
|
||||
; line 1
|
||||
ldy #{1*SPRITE_PLANE_SPAN}
|
||||
lda tiledata+{1*TILE_DATA_SPAN},x
|
||||
and [sprite_2],y
|
||||
ora (sprite_2),y
|
||||
and [sprite_1],y
|
||||
ora (sprite_1),y
|
||||
and [sprite_0],y
|
||||
ora (sprite_0),y
|
||||
sta tmp_sprite_data+{1*4}
|
||||
|
||||
ldy #{1*SPRITE_PLANE_SPAN}+2
|
||||
lda tiledata+{1*TILE_DATA_SPAN}+2,x
|
||||
and [sprite_2],y
|
||||
ora (sprite_2),y
|
||||
and [sprite_1],y
|
||||
ora (sprite_1),y
|
||||
and [sprite_0],y
|
||||
ora (sprite_0),y
|
||||
sta tmp_sprite_data+{1*4}+2
|
||||
|
||||
rts
|
|
@ -0,0 +1,5 @@
|
|||
; sprite stamp pixel data
|
||||
spritedata ENT
|
||||
; ds 65535
|
||||
ds 65536
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
; sprite stamp masks
|
||||
spritemask ENT
|
||||
; ds 65535
|
||||
ds 65536
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
; Bank of memory that holds the 8x8 tile data
|
||||
tiledata ENT
|
||||
; ds 65535
|
||||
ds 65536
|
||||
|
|
@ -1,5 +1,88 @@
|
|||
; Collection of data tables
|
||||
; Bank of memory that holds the core sprite and tile store data structures
|
||||
|
||||
put ../Defs.s
|
||||
put TileStoreDefs.s
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
put ../blitter/Template.s
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
|
||||
TileStore ENT
|
||||
ds {TILE_STORE_SIZE*TILE_STORE_NUM}
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
; A list of dirty tiles that need to be updated in a given frame
|
||||
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
DirtyTileCount ENT
|
||||
ds 2
|
||||
DirtyTiles ENT
|
||||
ds TILE_STORE_SIZE ; At most this many tiles can possibly be updated at once
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
_Sprites ENT
|
||||
ds SPRITE_REC_SIZE*MAX_SPRITES
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
; A double-sized table of lookup values. It is double-width and double-height so that,
|
||||
; if we know a tile's address position of (X + 41*Y), then any relative tile store address
|
||||
; can be looked up by adding a constant value.
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
TileStoreLookupYTable ENT
|
||||
]line equ 0
|
||||
lup TS_LOOKUP_HEIGHT
|
||||
dw ]line
|
||||
]line equ ]line+{2*TS_LOOKUP_SPAN}
|
||||
--^
|
||||
|
||||
; Width of tile store is 41 elements
|
||||
TileStoreData mac
|
||||
dw ]1+0,]1+2,]1+4,]1+6,]1+8,]1+10,]1+12,]1+14
|
||||
dw ]1+16,]1+18,]1+20,]1+22,]1+24,]1+26,]1+28,]1+30
|
||||
dw ]1+32,]1+34,]1+36,]1+38,]1+40,]1+42,]1+44,]1+46
|
||||
dw ]1+48,]1+50,]1+52,]1+54,]1+56,]1+58,]1+60,]1+62
|
||||
dw ]1+64,]1+66,]1+68,]1+70,]1+72,]1+74,]1+76,]1+78
|
||||
dw ]1+80
|
||||
<<<
|
||||
; Create a lookup table with two runs of offsets, plus an overlap area on the end (41+41+1 = 83 = TS_LOOKUP_SPAN)
|
||||
TileStoreLookup ENT
|
||||
|
||||
; First copy
|
||||
]row equ 0
|
||||
lup TILE_STORE_HEIGHT
|
||||
TileStoreData ]row*2*TILE_STORE_WIDTH
|
||||
TileStoreData ]row*2*TILE_STORE_WIDTH
|
||||
dw ]row*2*TILE_STORE_WIDTH,]row*2*TILE_STORE_WIDTH+2
|
||||
]row equ ]row+1
|
||||
--^
|
||||
|
||||
; Second copy
|
||||
]row equ 0
|
||||
lup TILE_STORE_HEIGHT
|
||||
TileStoreData ]row*2*TILE_STORE_WIDTH
|
||||
TileStoreData ]row*2*TILE_STORE_WIDTH
|
||||
dw ]row*2*TILE_STORE_WIDTH,]row*2*TILE_STORE_WIDTH+2
|
||||
]row equ ]row+1
|
||||
--^
|
||||
|
||||
; Last two rows
|
||||
TileStoreData 0*2*TILE_STORE_WIDTH
|
||||
TileStoreData 0*2*TILE_STORE_WIDTH
|
||||
dw 0*2*TILE_STORE_WIDTH,0*2*TILE_STORE_WIDTH+2
|
||||
TileStoreData 1*2*TILE_STORE_WIDTH
|
||||
TileStoreData 1*2*TILE_STORE_WIDTH
|
||||
dw 1*2*TILE_STORE_WIDTH,1*2*TILE_STORE_WIDTH+2
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
; Other data tables
|
||||
|
||||
; Col2CodeOffset
|
||||
;
|
||||
|
@ -19,21 +102,21 @@
|
|||
;
|
||||
; 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
|
||||
|
||||
]step equ 0
|
||||
dw CODE_TOP ; There is a spot where we load Col2CodeOffet-2,x
|
||||
Col2CodeOffset lup 82
|
||||
Col2CodeOffset ENT
|
||||
lup 82
|
||||
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
|
||||
]step equ ]step+1
|
||||
--^
|
||||
dw CODE_TOP+{81*PER_TILE_SIZE}
|
||||
|
||||
; A parallel table to Col2CodeOffset that holds the offset to the exception handler address for each column
|
||||
SNIPPET_SIZE equ 32
|
||||
]step equ 0
|
||||
dw SNIPPET_BASE
|
||||
JTableOffset lup 82
|
||||
JTableOffset ENT
|
||||
lup 82
|
||||
dw SNIPPET_BASE+{{81-]step}*SNIPPET_SIZE}
|
||||
]step equ ]step+1
|
||||
--^
|
||||
|
@ -46,7 +129,7 @@ JTableOffset lup 82
|
|||
;
|
||||
; These tables are reversed to be parallel with the JTableOffset and Col2CodeOffset tables above. The
|
||||
; physical word index that each instruction is intended to be placed at is in the comment.
|
||||
CodeFieldEvenBRA
|
||||
CodeFieldEvenBRA ENT
|
||||
bra *+6 ; 81 -- need to skip over the JMP loop that passed control back
|
||||
bra *+9 ; 80
|
||||
bra *+12 ; 79
|
||||
|
@ -130,7 +213,7 @@ CodeFieldEvenBRA
|
|||
bra *-6 ; 1
|
||||
bra *-3 ; 0
|
||||
|
||||
CodeFieldOddBRA
|
||||
CodeFieldOddBRA ENT
|
||||
bra *+9 ; 81 -- need to skip over two JMP instructions
|
||||
bra *+12 ; 80
|
||||
bra *+15 ; 79
|
||||
|
@ -240,7 +323,7 @@ TileStoreYTable ENT
|
|||
|
||||
; 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
|
||||
NextCol ENT
|
||||
]step equ 0
|
||||
lup 41
|
||||
dw ]step
|
||||
|
@ -252,16 +335,12 @@ NextCol
|
|||
]step = ]step+2
|
||||
--^
|
||||
|
||||
; A double-sized table of lookup values. This is basically the cross-product of TileStoreYTable and
|
||||
; NextCol. If is double-width and double-height so that, if we know a tile's address position
|
||||
; of (X + 41*Y), then any relative tile store address can be looked up by adding a constan value.
|
||||
;TileStore2DLookup ds {26*41*2}*4
|
||||
|
||||
; This is a double-length table that holds the right-edge adresses of the playfield on the physical
|
||||
; screen. At most, it needs to hold 200 addresses for a full height playfield. It is double-length
|
||||
; so that code can pick any offset and copy values without needing to check for a wrap-around. If the
|
||||
; playfield is less than 200 lines tall, then any values after 2 * PLAYFIELD_HEIGHT are undefined.
|
||||
RTable ds 400
|
||||
RTable ENT
|
||||
ds 400
|
||||
ds 400
|
||||
|
||||
; Array of addresses for the banks that hold the blitter.
|
||||
|
@ -271,17 +350,22 @@ BlitBuff ENT
|
|||
; The blitter table (BTable) is a double-length table that holds the full 4-byte address of each
|
||||
; line of the blit fields. We decompose arrays of pointers into separate high and low words so
|
||||
; that everything can use the same indexing offsets
|
||||
BTableHigh ds 208*2*2
|
||||
BTableLow ds 208*2*2
|
||||
BTableHigh ENT
|
||||
ds 208*2*2
|
||||
BTableLow ENT
|
||||
ds 208*2*2
|
||||
|
||||
; A shorter table that just holds the blitter row addresses
|
||||
BRowTableHigh ds 26*2*2
|
||||
BRowTableLow ds 26*2*2
|
||||
BRowTableHigh ENT
|
||||
ds 26*2*2
|
||||
BRowTableLow ENT
|
||||
ds 26*2*2
|
||||
|
||||
; A double-length table of addresses for the BG1 bank. The BG1 buffer is 208 rows of 256 bytes each and
|
||||
; the first row starts $1800 bytes in to center the buffer in the bank
|
||||
]step equ $1800
|
||||
BG1YTable lup 208
|
||||
BG1YTable ENT
|
||||
lup 208
|
||||
dw ]step
|
||||
]step = ]step+256
|
||||
--^
|
||||
|
@ -292,11 +376,135 @@ BG1YTable lup 208
|
|||
--^
|
||||
|
||||
; Repeat
|
||||
BG1YOffsetTable lup 26
|
||||
BG1YOffsetTable ENT
|
||||
lup 26
|
||||
dw 1,1,1,2,2,2,2,2,1,1,1,0,0,0,0,0
|
||||
--^
|
||||
|
||||
; Other Toolset variables
|
||||
OneSecondCounter ENT
|
||||
dw 0
|
||||
OldOneSecVec ENT
|
||||
ds 4
|
||||
Timers ENT
|
||||
ds TIMER_REC_SIZE*MAX_TIMERS
|
||||
Overlays ENT
|
||||
dw 0 ; count
|
||||
ds 8 ; only support one or now (start_line, end_line, function call)
|
||||
|
||||
; From the IIgs ref
|
||||
DefaultPalette ENT
|
||||
dw $0000,$0777,$0841,$072C
|
||||
dw $000F,$0080,$0F70,$0D00
|
||||
dw $0FA9,$0FF0,$00E0,$04DF
|
||||
dw $0DAF,$078F,$0CCC,$0FFF
|
||||
|
||||
; 0. Full Screen : 40 x 25 320 x 200 (32,000 bytes (100.0%))
|
||||
; 1. Sword of Sodan : 34 x 24 272 x 192 (26,112 bytes ( 81.6%))
|
||||
; 2. ~NES : 32 x 25 256 x 200 (25,600 bytes ( 80.0%))
|
||||
; 3. Task Force : 32 x 22 256 x 176 (22,528 bytes ( 70.4%))
|
||||
; 4. Defender of the World : 35 x 20 280 x 160 (22,400 bytes ( 70.0%))
|
||||
; 5. Rastan : 32 x 20 256 x 160 (20,480 bytes ( 64.0%))
|
||||
; 6. Game Boy Advanced : 30 x 20 240 x 160 (19,200 bytes ( 60.0%))
|
||||
; 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%))
|
||||
ScreenModeWidth ENT
|
||||
dw 320,272,256,256,280,256,240,288,160,288,160,320
|
||||
ScreenModeHeight ENT
|
||||
dw 200,192,200,176,160,160,160,128,144,192,102,1
|
||||
|
||||
; VBuff arrays for each sprite. We need at least a 3x3 block for each sprite and the shape of the
|
||||
; array must match the TileStore structure. The TileStore is 41 blocks wide.
|
||||
;
|
||||
; It is *critical* that this array be placed in a memory location that is greater than the largest
|
||||
; TileStore offset because the engine maintaines a per-sprite pointer equal to the VBuff array
|
||||
; address minut the TileStore offset for the top-left corner of that sprite. This allows all of
|
||||
; the sprites to share the same table, but the result of the subtraction has to be positive.
|
||||
;
|
||||
; Each block of data contains fixed offsets for the relative position of vbuff addresses. There
|
||||
; are multiple copies of the array to handle cases where a sprite needs to transition across the
|
||||
; boundary.
|
||||
;
|
||||
; For example. If a sprite is drawn in the last column, but is two blocks wide, the TileIndex
|
||||
; value for the first column is $52 and the second column is $00. Since the pointer to the
|
||||
; VBuffArray is pre-adjusted by the first column's size, the first offset value will be read
|
||||
; from (VBuffArray - $52)[$52] = VBuffArray[0], which is correct. However, the second column will be
|
||||
; read from (VBuffArray - $52)[$00] which is one row off from the correct value's location.
|
||||
;
|
||||
; The wrapping also need to account for vertical wrapping. Consider a 16x16 sprite with its top-left
|
||||
; conder inside the physical tile that is the bottom-right-most tile in the Tile Store. So, the
|
||||
; lookup index for this tile is (26*41*2)-2 = 2130. When using the lookup table, each step to the
|
||||
; right or down will cause wrap-around. So the lookup addresses look like this
|
||||
;
|
||||
; +------+------+ +------+------+
|
||||
; | $852 | $800 | | $000 | $004 |
|
||||
; +------+------+ --> +------+------+
|
||||
; | $052 | $000 | | $030 | $034 |
|
||||
; +------+------+ +------+------+
|
||||
;
|
||||
; We need to maintain 9 different lookup table variations, which is equal to the number of tile
|
||||
; in the largest sprite (3x3 tiles = 9 different border cases)
|
||||
|
||||
;COL_BYTES equ 4 ; VBUFF_TILE_COL_BYTES
|
||||
;ROW_BYTES equ 384 ; VBUFF_TILE_ROW_BYTES
|
||||
|
||||
; Define the offset values
|
||||
;___NA_NA___ equ 0
|
||||
;ROW_0_COL_0 equ {{0*COL_BYTES}+{0*ROW_BYTES}}
|
||||
;ROW_0_COL_1 equ {{1*COL_BYTES}+{0*ROW_BYTES}}
|
||||
;ROW_0_COL_2 equ {{2*COL_BYTES}+{0*ROW_BYTES}}
|
||||
;ROW_1_COL_0 equ {{0*COL_BYTES}+{1*ROW_BYTES}}
|
||||
;ROW_1_COL_1 equ {{1*COL_BYTES}+{1*ROW_BYTES}}
|
||||
;ROW_1_COL_2 equ {{2*COL_BYTES}+{1*ROW_BYTES}}
|
||||
;ROW_2_COL_0 equ {{0*COL_BYTES}+{2*ROW_BYTES}}
|
||||
;ROW_2_COL_1 equ {{1*COL_BYTES}+{2*ROW_BYTES}}
|
||||
;ROW_2_COL_2 equ {{2*COL_BYTES}+{2*ROW_BYTES}}
|
||||
|
||||
; Allocate an amount of space equal to a TileStore block because we could have vertical wrap around.
|
||||
; The rest of the values are in just the first few rows following this block
|
||||
;
|
||||
; The first block of 4 values is the "normal" case, (X in [0, N-3], Y in [0, M-3]), so no wrap around is needed
|
||||
; The second block is (X = N-1, Y in [0, M-3])
|
||||
; The third block is (X = N-2, Y in [0, M-3])
|
||||
; The fourth block is (X in [0, N-3], Y = M-1)
|
||||
; The fifth block is (X = N-1, Y = M-1)
|
||||
; The sixth block is (X = N-2, Y = M-1)
|
||||
; The seventh block is (X in [0, N-3], Y = M-2)
|
||||
; The eighth block is (X = N-1, Y = M-2)
|
||||
; The ninth block is (X = N-2, Y = M-2)
|
||||
|
||||
VBuffVertTableSelect ENT ; 51 entries
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,48,24
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,48,24
|
||||
VBuffHorzTableSelect ENT
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,0,0,0,0,0,16,8
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,0,0,0,0,0,0
|
||||
dw 0,0,0,0,0,0,0,0,0,16,8
|
||||
|
||||
VBuffStart ds TILE_STORE_SIZE
|
||||
VBuffArray ENT
|
||||
ds {TILE_STORE_WIDTH*2}*3
|
||||
|
||||
; Convert sprite index to a bit position
|
||||
_SpriteBits ENT
|
||||
dw $0001,$0002,$0004,$0008,$0010,$0020,$0040,$0080,$0100,$0200,$0400,$0800,$1000,$2000,$4000,$8000
|
||||
_SpriteBitsNot ENT
|
||||
dw $FFFE,$FFFD,$FFFB,$FFF7,$FFEF,$FFDF,$FFBF,$FF7F,$FEFF,$FDFF,$FBFF,$F7FF,$EFFF,$DFFF,$BFFF,$7FFF
|
||||
|
||||
; Steps to the different sprite stamps
|
||||
_stamp_step ENT
|
||||
dw 0,12,24,36
|
||||
|
||||
blt_return
|
||||
stk_save
|
|
@ -0,0 +1,113 @@
|
|||
; Tile storage parameters
|
||||
TILE_DATA_SPAN equ 4
|
||||
TILE_STORE_WIDTH equ 41
|
||||
TILE_STORE_HEIGHT equ 26
|
||||
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} ; tile descriptor for this location
|
||||
TS_DIRTY equ {TILE_STORE_SIZE*1} ; Flag. Used to prevent a tile from being queued 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}
|
||||
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 or $8000.
|
||||
TS_JMP_ADDR equ {TILE_STORE_SIZE*7} ; const value, address of the 32-byte snippet space for this tile
|
||||
TS_SCREEN_ADDR equ {TILE_STORE_SIZE*8} ; cached value of on-screen location of tile. Used for DirtyRender.
|
||||
|
||||
; TODO: Move these arrays into the K bank to support direct dispatch via jmp (abs,x)
|
||||
; TS_BASE_TILE_COPY equ {TILE_STORE_SIZE*9} ; derived from TS_TILE_ID to optimize tile copy to support sprite rendering
|
||||
; TS_BASE_TILE_DISP equ {TILE_STORE_SIZE*10} ; derived from TS_TILE_ID to optimize base (non-sprite) tile dispatch in the Render function
|
||||
; TS_DIRTY_TILE_DISP equ {TILE_STORE_SIZE*11} ; derived from TS_TILE_ID to optimize dirty tile dispatch in the Render function
|
||||
|
||||
TILE_STORE_NUM equ 12 ; Need this many parallel arrays
|
||||
|
||||
; 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.
|
||||
|
||||
MAX_SPRITES equ 16
|
||||
SPRITE_REC_SIZE equ 42
|
||||
|
||||
; 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.
|
||||
|
||||
; These values are set by the user
|
||||
SPRITE_STATUS equ {MAX_SPRITES*0}
|
||||
SPRITE_ID equ {MAX_SPRITES*2}
|
||||
SPRITE_X equ {MAX_SPRITES*4}
|
||||
SPRITE_Y equ {MAX_SPRITES*6}
|
||||
VBUFF_ADDR equ {MAX_SPRITES*8} ; Base address of the sprite's stamp in the data/mask banks
|
||||
|
||||
; These values are cached / calculated during the rendering process
|
||||
TS_LOOKUP_INDEX equ {MAX_SPRITES*10} ; The index from the TileStoreLookup table that corresponds to the top-left corner of the sprite
|
||||
TS_COVERAGE_SIZE equ {MAX_SPRITES*12} ; Representation of how many TileStore tiles (NxM) are covered by this sprite
|
||||
SPRITE_DISP equ {MAX_SPRITES*14} ; Cached address of the specific stamp based on sprite flags
|
||||
SPRITE_CLIP_LEFT equ {MAX_SPRITES*16}
|
||||
SPRITE_CLIP_RIGHT equ {MAX_SPRITES*18}
|
||||
SPRITE_CLIP_TOP equ {MAX_SPRITES*20}
|
||||
SPRITE_CLIP_BOTTOM equ {MAX_SPRITES*22}
|
||||
IS_OFF_SCREEN equ {MAX_SPRITES*24}
|
||||
SPRITE_WIDTH equ {MAX_SPRITES*26}
|
||||
SPRITE_HEIGHT equ {MAX_SPRITES*28}
|
||||
SPRITE_CLIP_WIDTH equ {MAX_SPRITES*30}
|
||||
SPRITE_CLIP_HEIGHT equ {MAX_SPRITES*32}
|
||||
TS_VBUFF_BASE equ {MAX_SPRITES*34} ; Finalized VBUFF address based on the sprite position and tile offsets
|
||||
VBUFF_ARRAY_ADDR equ {MAX_SPRITES*36} ; Fixed address where this sprite's VBUFF addresses are stores. The array is the same shape as TileStore, but much smaller
|
||||
|
||||
; 52 rows by 82 columns + 2 extra rows and columns for sprite sizes
|
||||
;
|
||||
; 53 rows = TILE_STORE_HEIGHT + TILE_STORE_HEIGHT + 1
|
||||
; 83 cols = TILE_STORE_WIDTH + TILE_STORE_WIDTH + 1
|
||||
;
|
||||
; TILE_STORE_WIDTH equ 41
|
||||
; TILE_STORE_HEIGHT equ 26
|
||||
|
||||
TS_LOOKUP_WIDTH equ 82
|
||||
TS_LOOKUP_HEIGHT equ 52
|
||||
TS_LOOKUP_BORDER equ 2
|
||||
TS_LOOKUP_SPAN equ {TS_LOOKUP_WIDTH+TS_LOOKUP_BORDER}
|
||||
TS_LOOKUP_ROWS equ {TS_LOOKUP_HEIGHT+TS_LOOKUP_BORDER}
|
||||
|
||||
; Blitter template constants
|
||||
PER_TILE_SIZE equ 3
|
||||
SNIPPET_SIZE equ 32
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
;
|
||||
; Timer implementation
|
||||
;
|
||||
; The engire provides four timer slot that can be used by one-shot or
|
||||
; recurring timers. Each timer is given an initial tick count, a
|
||||
; reset tick count (0 = one-shot), and an action to perform.
|
||||
;
|
||||
; The timers handle overflow, so if a recurring timer has a tick count of 3
|
||||
; and 7 VBL ticks have passed, then the timer will be fired twice and
|
||||
; a tick count of 2 will be set.
|
||||
;
|
||||
; As such, the timers are appropriate to drive physical and other game
|
||||
; behaviors at a frame-independent rate.
|
||||
;
|
||||
; A collection of 4 timers that are triggered when their countdown
|
||||
; goes below zero. Each timer takes up 16 bytes
|
||||
;
|
||||
; A timer can fire multiple times during a singular evaluation. For example, if the
|
||||
; timer delay is set to 1 and 3 VBL ticks happen, then the timer delta is -2, will fire,
|
||||
; have the delay added and get -1, fire again, increment to zero, first again and then
|
||||
; finally reset to 1.
|
||||
;
|
||||
; +0 counter decremented by the number of ticks since last run
|
||||
; +2 reset copied into counter when triggered. 0 turns off the timer.
|
||||
; +4 addr long address of timer routine
|
||||
; +8 user 8 bytes of user data space for timer state
|
||||
MAX_TIMERS equ 4
|
||||
TIMER_REC_SIZE equ 16
|
|
@ -0,0 +1,43 @@
|
|||
; A collection of tile blitters used in the dirty renderer. These renderers copy data directly
|
||||
; to the graphics screen. Also, because the dirty render assumes that the screen is not moving,
|
||||
; there is no support for two layer tiles.
|
||||
|
||||
; Address table of the rendering functions
|
||||
DirtyTileProcs dw _TBDirtyTile_00,_TBDirtyTile_0H,_TBDirtyTile_V0,_TBDirtyTile_VH
|
||||
|
||||
; Normal and horizontally flipped tiles. The horizontal variant is selected by choosing
|
||||
; and appropriate value for the X register, so these can share the same code.
|
||||
;
|
||||
; B = Bank 01
|
||||
; X = address of tile data
|
||||
; Y = screen address
|
||||
_TBDirtyTile_00
|
||||
_TBDirtyTile_0H
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta: $0000+{]line*160},y
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta: $0002+{]line*160},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; Vertically flipped tile renderers
|
||||
;
|
||||
; B = Bank 01
|
||||
; X = address of tile data
|
||||
; Y = screen address
|
||||
_TBDirtyTile_V0
|
||||
_TBDirtyTile_VH
|
||||
]line equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta: $0000+{]dest*160},y
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta: $0002+{]dest*160},y
|
||||
]line equ ]line-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
|
@ -0,0 +1,181 @@
|
|||
_ClearDirtyTiles
|
||||
bra :hop
|
||||
:loop
|
||||
jsr _PopDirtyTile
|
||||
:hop
|
||||
lda DirtyTileCount
|
||||
bne :loop
|
||||
rts
|
||||
|
||||
|
||||
; Append a new dirty tile record
|
||||
;
|
||||
; A = result of _GetTileStoreOffset for X, Y
|
||||
;
|
||||
; The main purpose of this function is to
|
||||
;
|
||||
; 1. Avoid marking the same tile dirty multiple times, and
|
||||
; 2. Pre-calculating all of the information necessary to render the tile
|
||||
_PushDirtyTile
|
||||
tax
|
||||
|
||||
; alternate entry point if the x-register is already set
|
||||
_PushDirtyTileX
|
||||
lda TileStore+TS_DIRTY,x
|
||||
bne :occupied2
|
||||
|
||||
inc ; any non-zero value will work
|
||||
sta TileStore+TS_DIRTY,x ; and is 1 cycle faster than loading a constant value
|
||||
|
||||
txa
|
||||
ldx DirtyTileCount ; 4
|
||||
sta DirtyTiles,x ; 6
|
||||
inx ; 2
|
||||
inx ; 2
|
||||
stx DirtyTileCount ; 4 = 18
|
||||
rts
|
||||
:occupied2
|
||||
txa ; Make sure TileStore offset is returned in the accumulator
|
||||
rts
|
||||
|
||||
; alternate entry point if the Y-register is already set
|
||||
_PushDirtyTileY
|
||||
lda TileStore+TS_DIRTY,y
|
||||
bne :occupied2
|
||||
|
||||
inc ; any non-zero value will work
|
||||
sta TileStore+TS_DIRTY,y ; and is 1 cycle faster than loading a constant value
|
||||
|
||||
tya
|
||||
ldy DirtyTileCount ; 4
|
||||
sta DirtyTiles,y ; 6
|
||||
iny ; 2
|
||||
iny ; 2
|
||||
sty DirtyTileCount ; 4 = 18
|
||||
rts
|
||||
:occupied2
|
||||
tya ; Make sure TileStore offset is returned in the accumulator
|
||||
rts
|
||||
|
||||
; Remove a dirty tile from the list and return it in state ready to be rendered. It is important
|
||||
; that the core rendering functions *only* use _PopDirtyTile to get a list of tiles to update.
|
||||
_PopDirtyTile
|
||||
ldy DirtyTileCount
|
||||
bne _PopDirtyTile2
|
||||
rts
|
||||
|
||||
_PopDirtyTile2 ; alternate entry point
|
||||
dey
|
||||
dey
|
||||
sty DirtyTileCount ; remove last item from the list
|
||||
|
||||
ldx DirtyTiles,y ; load the offset into the Tile Store
|
||||
lda #$FFFF
|
||||
stal TileStore+TS_DIRTY,x ; clear the occupied backlink
|
||||
rts
|
||||
|
||||
; An optimized subroutine that runs through the dirty tile list and executes a callback function
|
||||
; for each dirty tile. This is an unrolled loop, so we avoid the need to track a register and
|
||||
; decrement on each iteration.
|
||||
;
|
||||
; Also, if we are handling less than 8 dirty tiles, we use a code path that does not
|
||||
; need to use an index register
|
||||
;
|
||||
; Bank = Tile Store
|
||||
; D = Page 2
|
||||
_PopDirtyTilesFast
|
||||
ldx DP2_DIRTY_TILE_COUNT ; This is pre-multiplied by 2
|
||||
bne pdtf_not_empty ; If there are no items, exit
|
||||
at_exit rts
|
||||
pdtf_not_empty
|
||||
cpx #16 ; If there are >= 8 elements, then
|
||||
bcs full_chunk ; do a full chunk
|
||||
|
||||
jmp (at_table,x)
|
||||
at_table da at_exit,at_one,at_two,at_three
|
||||
da at_four,at_five,at_six,at_seven
|
||||
|
||||
full_chunk txa
|
||||
sbc #16 ; carry set from branch
|
||||
sta DP2_DIRTY_TILE_COUNT ; fall through
|
||||
tay ; use the Y-register for the index
|
||||
|
||||
; Because all of the registers get used in the subroutine, we
|
||||
; push the values from the DirtyTiles array onto the stack and then pop off
|
||||
; the values as we go
|
||||
|
||||
ldx DirtyTiles+14,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+12,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+10,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+8,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+6,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+4,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+2,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
ldy DP2_DIRTY_TILE_COUNT
|
||||
ldx DirtyTiles+0,y
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
jmp _PopDirtyTilesFast
|
||||
|
||||
; These routines just handle between 1 and 7 dirty tiles
|
||||
at_seven
|
||||
ldx DirtyTiles+12
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
at_six
|
||||
ldx DirtyTiles+10
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
at_five
|
||||
ldx DirtyTiles+8
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
at_four
|
||||
ldx DirtyTiles+6
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
at_three
|
||||
ldx DirtyTiles+4
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
at_two
|
||||
ldx DirtyTiles+2
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jsr _RenderTile
|
||||
|
||||
at_one
|
||||
ldx DirtyTiles+0
|
||||
stz TileStore+TS_DIRTY,x
|
||||
jmp _RenderTile
|
Loading…
Reference in New Issue