iigs-game-engine/src/Tool.s
2023-06-02 00:38:35 -05:00

1125 lines
30 KiB
ArmAsm

; Toolbox wrapper for the GTE library. Implemented as a user tool
;
; 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
adrl {_CTEnd-_CallTable}/4
adrl _TSBootInit-1
adrl _TSStartUp-1
adrl _TSShutDown-1
adrl _TSVersion-1
adrl _TSReset-1
adrl _TSStatus-1
adrl _TSReserved-1
adrl _TSReserved-1
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
adrl _TSRenderDirty-1
adrl _TSSetBG1Displacement-1
adrl _TSSetBG1Rotation-1
adrl _TSClearBG1Buffer-1
adrl _TSSetBG1Scale-1
adrl _TSGetAddress-1
adrl _TSCompileSpriteStamp-1
adrl _TSSetAddress-1
adrl _TSUpdateOverlay-1
adrl _TSEnableSprites-1
adrl _TSEnableBackground-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
lda #0
clc
rtl
; 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 = tool set number in low byte and function number in high byte
;
; StartUp(dPageAddr, capFlags, userId)
_TSStartUp
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
stal tool_direct_page ; Stash a copy in memory
txa
and #$00FF ; Get just the tool number
sta ToolNum
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)
lda EngineMode ; $0000 = system tool, $8000 = user tool set
and #$8000
pha
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
pld ; Restore the caller's direct page
:exit
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
tcd ; Set the direct page for the toolset
phb
jsr _SetDataBank
jsr _CoreShutDown ; Shut down the library
plb
lda EngineMode ; $0000 = system tool, $8000 = user tool set
and #$8000
pha
pei ToolNum
pea $0000 ; Set WAP to null
pea $0000
_SetWAP
pld ; Restore the direct page
:inactive
lda #0
clc
rtl
_TSVersion
lda #$0100 ; Version 1
sta 7,s
lda #0
clc
rtl
_TSReset
lda #0
clc
rtl
; Check the WAP values in the A, Y registers
_TSStatus
sta 1,s
tya
ora 1,s
sta 1,s ; 0 if WAP is null, non-zero if WAP is set
lda #0
clc
rtl
_TSReserved
txa
xba
ora #$00FF ; Put error code $FF in the accumulator
sec
rtl
; SetScreenMode(width, height)
_TSSetScreenMode
:height equ FirstParam
:width equ FirstParam+2
_TSEntry
lda :height,s
tay
lda :width,s
tax
jsr _SetScreenMode
_TSExit #0;#4
; ReadControl()
_TSReadControl
:output equ FirstParam
_TSEntry
jsr _ReadControl
sta :output,s
_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(flags)
_TSRender
:flags equ FirstParam+0
_TSEntry
lda :flags,s
cmp #$FFFF ; Hack! Special mode...
beq :nes
bit #RENDER_WITH_SHADOWING
beq :no_shadowing
jsr _RenderWithShadowing
bra :done
:no_shadowing
bit #RENDER_PER_SCANLINE
beq :no_scanline
jsr _RenderScanlines
bra :done
:no_scanline
jsr _Render
bra :done
:nes
jsr _RenderNES
:done
_TSExit #0;#2
; RenderDirty(flags)
_TSRenderDirty
:flags equ FirstParam+0
_TSEntry
lda :flags,s
jsr _RenderDirty
_TSExit #0;#2
; LoadTileSet(Start, Finish, Pointer)
_TSLoadTileSet
:TSPtr equ FirstParam
:finish equ FirstParam+4
:start equ FirstParam+6
_TSEntry
lda :TSPtr+2,s ; stuff the pointer in the direct page
sta tmp1
lda :TSPtr,s
sta tmp0
lda :start,s ; put the range in the registers
tax
lda :finish,s
tay
jsr _LoadTileSet
_TSExit #0;#8
; CreateSpriteStamp(spriteDescriptor: Word, vbuffAddr: Word)
_TSCreateSpriteStamp
:vbuff equ FirstParam
:spriteId equ FirstParam+2
_TSEntry
lda :vbuff,s
tay
lda :spriteId,s
jsr _CreateSpriteStamp
_TSExit #0;#4
; AddSprite(spriteSlot, spriteFlags, vbuff | cbuff, spriteX, spriteY)
_TSAddSprite
:spriteY equ FirstParam+0
:spriteX equ FirstParam+2
:vbuff equ FirstParam+4
:spriteFlags equ FirstParam+6
:spriteSlot equ FirstParam+8
_TSEntry
lda :spriteX,s
and #$00FF
xba
sta :spriteX,s
lda :spriteY,s
and #$00FF
ora :spriteX,s
tay
lda :spriteSlot,s
tax
lda :spriteFlags,s
jsr _AddSprite
lda :spriteFlags,s
tax
lda :vbuff,s
tay
lda :spriteSlot,s
jsr _UpdateSprite
_TSExit #0;#10
; MoveSprite(spriteSlot, x, y)
_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
; UpdateSprite(spriteSlot, spriteFlags, vbuff)
_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
; CopyPicToBG1(width, height, stride, ptr, flags)
_TSCopyPicToBG1
:flags equ FirstParam+0
:ptr equ FirstParam+2
:stride equ FirstParam+6
:height equ FirstParam+8
:width equ FirstParam+10
_TSEntry
; Lots of parameters for this function, so pass them on the direct page
:src_width equ tmp6
:src_height equ tmp7
:src_stride equ tmp8
:src_flags equ tmp9
lda :width,s
sta :src_width
lda :height,s
sta :src_height
lda :stride,s
sta :src_stride
ldy BG1DataBank ; Pick the target data bank
lda :flags,s
sta :src_flags
; bit #$0001
; beq *+4
; ldy BG1AltBank
lda :ptr+2,s
tax
lda :ptr,s
jsr _CopyToBG1
_TSExit #0;#12
_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_id equ FirstParam+4
:output_x equ FirstParam+6
:output_y equ FirstParam+8
_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
sta :output_x,s
sta :output_y,s
bra :out
:ok
txa
sta :output_x,s
tya
sta :output_y,s
; Load the tile at that tile store location
jsr _GetTileStoreOffset0 ; Get the address of the X,Y tile position
tax
lda TileStore+TS_TILE_ID,x
:out
sta :output_id,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 :numTicks,s
tay
lda :flags,s
ror ; put low bit into carry
lda :callback,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)
;
; Overlays are handled as quasi-sprites. They need to be included in the y-sorted list of "stuff", but they are not drawn like
; sprites. As such, they set a special flag in the SPRITE_ID field which allows them to be ignored for other purposes. Also,
; they are not added into the "normal" sprite range on 0 - 15, but are stored in locations 16 and up to further seggregate them from
; the rest of the system. A lot of the SPRITE_* locations are repurposed for Overlay-specific information.
_TSSetOverlay
:proc equ FirstParam+0
:bottom equ FirstParam+4
:top equ FirstParam+6
_TSEntry
ldx #0 ; Always just use the first spot
lda #SPRITE_OVERLAY
; lda #SPRITE_OVERLAY+SPRITE_HIDE ; Type 2 overlays re-use the HIDE bit
sta Overlays+OVERLAY_ID,x
stz Overlays+OVERLAY_FLAGS,x
lda :top,s
sta Overlays+OVERLAY_TOP,x
lda :bottom,s
; dec
sta Overlays+OVERLAY_BOTTOM,x
sec
sbc :top,s
; inc
sta Overlays+OVERLAY_HEIGHT,x
lda :proc,s
sta Overlays+OVERLAY_PROC,x
lda :proc+2,s
sta Overlays+OVERLAY_PROC+2,x
ldx #{MAX_SPRITES+0}*2 ; Adjust to call the generic routine
jsr _InsertSprite
_TSExit #0;#8
; UpdateOverlay(top, bottom, proc)
_TSUpdateOverlay
:proc equ FirstParam+0
:bottom equ FirstParam+4
:top equ FirstParam+6
_TSEntry
ldx #0
stz Overlays+OVERLAY_FLAGS,x
lda :top,s
sta Overlays+OVERLAY_TOP
lda :bottom,s
; dec
sta Overlays+OVERLAY_BOTTOM
sec
sbc :top,s
; inc
sta Overlays+OVERLAY_HEIGHT,x
lda :proc,s
sta Overlays+OVERLAY_PROC
lda :proc+2,s
sta Overlays+OVERLAY_PROC+2
ldx #{MAX_SPRITES+0}*2 ; Adjust to call the generic routings
jsr _UpdateSprite
_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
jsr _Refresh
_TSExit #0;#0
; SetBG1Displacement(offset)
_TSSetBG1Displacement
:offset equ FirstParam+0
_TSEntry
lda :offset,s
and #$001E
sta BG1OffsetIndex
_TSExit #0;#2
; SetBG1Rotation(rotIndex)
_TSSetBG1Rotation
:rotIndex equ FirstParam+0
x_angles EXT
y_angles EXT
_TSEntry
lda :rotIndex,s
and #$003F ; only 64 angles to choose from
asl
tax
ldal x_angles,x ; load the address of addresses for this angle
tay
phx
jsr _ApplyBG1XPosAngle
plx
ldal y_angles,x ; load the address of addresses for this angle
tay
jsr _ApplyBG1YPosAngle
_TSExit #0;#2
_TSClearBG1Buffer
:value equ FirstParam+0
_TSEntry
lda :value,s
jsr _ClearBG1Buffer
_TSExit #0;#2
_TSSetBG1Scale
:sIndex equ FirstParam+0
_TSEntry
lda :value,s
sta BG1Scaling
_TSExit #0;#2
; Pointer GetAddress(addrId)
_TSGetAddress
:tblId equ FirstParam+0
:output equ FirstParam+2
_TSEntry
lda #0
sta :output,s
sta :output+2,s
lda :tblId,s
cmp #scanlineHorzOffset
bne :next_1
lda StartXMod164Tbl
sta :output,s
lda StartXMod164Tbl+2
sta :output+2,s
bra :out
:next_1 cmp #scanlineHorzOffset2
bne :next_2
lda BG1StartXMod164Tbl
sta :output,s
lda BG1StartXMod164Tbl+2
sta :output+2,s
bra :out
:next_2 cmp #rawDrawTile
bne :next_3
lda #_DrawTileToScreen
sta :output,s
lda #^_DrawTileToScreen
sta :output+2,s
bra :out
:next_3
:out
_TSExit #0;#2
; SetAddress(addrId, Pointer)
_TSSetAddress
:ptr equ FirstParam+0
:tblId equ FirstParam+4
_TSEntry
lda :tblId,s
cmp #scanlineHorzOffset
bne :next_1
lda :ptr,s
sta StartXMod164Tbl
lda :ptr+2,s
sta StartXMod164Tbl+2
brl :out
:next_1
cmp #scanlineHorzOffset2
bne :next_2
lda :ptr,s
sta BG1StartXMod164Tbl
lda :ptr+2,s
sta BG1StartXMod164Tbl+2
brl :out
:next_2 cmp #vblCallback
bne :next_3
lda :ptr,s
ora :ptr+2,s
beq :vbl_restore
lda :ptr,s
stal _VblTaskPatch+1 ; long addressing because we're patching code in the K bank
lda :ptr+1,s
stal _VblTaskPatch+2
brl :out
:vbl_restore
lda #_TaskStub
stal _VblTaskPatch+1
lda #>_TaskStub
stal _VblTaskPatch+2
brl :out
:next_3 cmp #extSpriteRenderer
bne :next_4
lda :ptr,s
sta ExtSpriteRenderer
lda :ptr+2,s
sta ExtSpriteRenderer+2
bra :out
:next_4 cmp #extBG0TileUpdate
bne :next_5
lda :ptr,s
sta ExtUpdateBG0Tiles
lda :ptr+2,s
sta ExtUpdateBG0Tiles+2
bra :out
:next_5 cmp #userTileCallback
bne :next_6
lda :ptr,s
ora :ptr+2,s
beq :utd_restore
lda :ptr,s
stal _UTDPatch+1 ; long addressing because we're patching code in the K bank
lda :ptr+1,s
stal _UTDPatch+2
brl :out
:utd_restore
lda #UserHook1
stal _UTDPatch+1
lda #>UserHook1
stal _UTDPatch+2
brl :out
:next_6
:out
_TSExit #0;#6
; CompileSpriteStamp(spriteId, vbuffAddr)
_TSCompileSpriteStamp
:vbuff equ FirstParam
:spriteId equ FirstParam+2
:output equ FirstParam+4
_TSEntry
lda :vbuff,s
tax
lda :spriteId,s
jsr _CompileStampSet
sta :output,s
_TSExit #0;#4
; EnableSprites(bool)
_TSEnableSprites
:enable equ FirstParam
_TSEntry
lda :enable
beq :turn_off
lda #CTRL_SPRITE_DISABLE
trb GTEControlBits
bra :done
:turn_off
lda #CTRL_SPRITE_DISABLE
tsb GTEControlBits
:done
_TSExit #0;#2
; EnableBackground(bool)
_TSEnableBackground
:enable equ FirstParam
_TSEntry
lda :enable,s
beq :turn_off
lda #CTRL_BKGND_DISABLE
trb GTEControlBits
bra :done
:turn_off
lda #CTRL_BKGND_DISABLE
tsb GTEControlBits
:done
_TSExit #0;#2
; 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/Dirty.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/Rotation.s
put blitter/Template.s
put blitter/TemplateUtils.s
put blitter/Blitter.s
put blitter/PEISlammer.s