; 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 _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 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 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 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 :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 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 :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 :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 bra :out :next_1 cmp #scanlineHorzOffset2 bne :next_2 lda :ptr,s sta BG1StartXMod164Tbl lda :ptr+2,s sta BG1StartXMod164Tbl+2 bra :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 bra :out :vbl_restore lda #_TaskStub stal _VblTaskPatch+1 lda #>_TaskStub stal _VblTaskPatch+2 bra :out :next_3 :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 ; 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