; Test driver to exercise graphics routines.

                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

tiledata        EXT                           ; tileset buffer
TileSetPalette  EXT

; Keycodes
LEFT_ARROW      equ   $08
RIGHT_ARROW     equ   $15
UP_ARROW        equ   $0B
DOWN_ARROW      equ   $0A

; Direct page space
MyUserId        equ   0
BankLoad        equ   2
StartX          equ   4
StartY          equ   6
TileMapWidth    equ   8
TileMapHeight   equ   10
ScreenWidth     equ   12
ScreenHeight    equ   14
MaxGlobalX      equ   16
MaxGlobalY      equ   18
MaxBG0X         equ   20
MaxBG0Y         equ   22
OldOneSecondCounter equ 26
appTmp0         equ   28
appTmp1         equ   30
appTmp2         equ   32
PlayerX         equ   34
PlayerY         equ   36
PlayerXVel      equ   38
PlayerYVel      equ   40
PlayerStanding  equ   42
PlayerGlobalX   equ   44
PlayerGlobalY   equ   46
LastHFlip       equ   48
SpriteFrame     equ   50
SpriteToggle    equ   52
SpriteCount     equ   54

                phk
                plb

                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

                _MTStartUp                    ; GTE requires the miscellaneous toolset to be running

                lda   #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; +ENGINE_MODE_DYN_TILES
                jsr   GTEStartUp              ; Load and install the GTE User Tool

; Initialize local variables

                stz   StartX
                stz   StartY
                stz   frameCount
                stz   bg1offset
                stz   LastHFlip
                stz   SpriteCount
                stz   SpriteToggle

; Initialize the graphics screen playfield

                pea   #160
                pea   #200
                _GTESetScreenMode

; Load a tileset

                pea   #0
                pea   #511
                pea   #^tiledata
                pea   #tiledata
                _GTELoadTileSet

                pea   $0000
                pea   #^TileSetPalette
                pea   #TileSetPalette
                _GTESetPalette

; Set up our level data

                jsr   BG0SetUp
                jsr   SetLimits

                jsr   AllocBank               ; Alloc 64KB for Load/Unpack
                sta   BankLoad                ; Store "Bank Pointer"
                ldx   #BG1DataFile            ; Load the background file into the bank
                jsr   LoadFile

                pea   #164                    ; Fill everything
                pea   #200
                pea   #256
                lda   BankLoad
                pha
                pea   $0000
                pea   $0000                   ; default flags
                _GTECopyPicToBG1

                lda   #193                    ; Tile ID of '0'
                jsr   InitOverlay             ; Initialize the status bar
                pha
                _GTEGetSeconds
                pla
                sta   OldOneSecondCounter
                jsr   UdtOverlay

                pha                         ; space for result
                pea   #15
                pea   ^UpdateBG1Offset
                pea   UpdateBG1Offset
                pea   $0000
                _GTEAddTimer
                pla

; Initialize the sprite's global position (this is tracked outside of the tile engine)

                lda   #16
                sta   PlayerGlobalX
                sta   PlayerX
                lda   MaxGlobalY
                sec
                sbc   #64                     ; 32 for tiles, 16 for sprite
                sta   PlayerGlobalY
                sta   PlayerY

                stz   PlayerXVel
                stz   PlayerYVel

; Create the sprites

HERO_SIZE       equ   {SPRITE_16X16}
HERO_FLAGS      equ   HERO_SIZE                                 ; no extra H/V bits for now
HERO_FRAME_1    equ   {SPRITE_16X16+1}
HERO_VBUFF_1    equ   VBUFF_SPRITE_START+0*VBUFF_SPRITE_STEP
HERO_FRAME_2    equ   {SPRITE_16X16+7}
HERO_VBUFF_2    equ   VBUFF_SPRITE_START+1*VBUFF_SPRITE_STEP
HERO_FRAME_3    equ   {SPRITE_16X8+65}
HERO_VBUFF_3    equ   VBUFF_SPRITE_START+2*VBUFF_SPRITE_STEP
HERO_FRAME_4    equ   {SPRITE_16X8+71}
HERO_VBUFF_4    equ   VBUFF_SPRITE_START+3*VBUFF_SPRITE_STEP
HERO_SLOT_1     equ   1
HERO_SLOT_2     equ   2

                pea   HERO_FRAME_1
                pea   HERO_VBUFF_1
                _GTECreateSpriteStamp

                pea   HERO_FRAME_2
                pea   HERO_VBUFF_2
                _GTECreateSpriteStamp

                pea   HERO_FRAME_3
                pea   HERO_VBUFF_3
                _GTECreateSpriteStamp

                pea   HERO_FRAME_4
                pea   HERO_VBUFF_4
                _GTECreateSpriteStamp

                DO    0
                lda   #SPRITE_16X16
                sta   SpriteFlags1
                lda   #SPRITE_16X8
                sta   SpriteFlags2
                ELSE
                lda   #SPRITE_16X16+SPRITE_COMPILED
                sta   SpriteFlags1
                lda   #SPRITE_16X8+SPRITE_COMPILED
                sta   SpriteFlags2

                pha                                ; Space for result
                pea   HERO_SIZE
                pea   HERO_VBUFF_1
                _GTECompileSpriteStamp
                pla
                sta   HeroFrames1+2
                sta   HeroFrames1+6

                pha                                ; Space for result
                pea   HERO_SIZE
                pea   HERO_VBUFF_2
                _GTECompileSpriteStamp
                pla
                sta   HeroFrames1+0
                sta   HeroFrames1+4

                pha                                ; Space for result
                pea   HERO_SIZE
                pea   HERO_VBUFF_3
                _GTECompileSpriteStamp
                pla
                sta   HeroFrames2+2
                sta   HeroFrames2+6

                pha                                ; Space for result
                pea   HERO_SIZE
                pea   HERO_VBUFF_4
                _GTECompileSpriteStamp
                pla
                sta   HeroFrames2+0
                sta   HeroFrames2+4
                FIN

                pea   HERO_SLOT_1                   ; Put the player in slot 1
                lda   SpriteFlags1
                pha
                lda   HeroFrames1
                pha
                pei   PlayerX
                pei   PlayerY
                _GTEAddSprite

                pea   HERO_SLOT_2
                lda   SpriteFlags2
                pha
                lda   HeroFrames2
                pha
                pei   PlayerX
                lda   PlayerY
                clc
                adc   #16
                pha
                _GTEAddSprite

EvtLoop
                pha
                _GTEReadControl
                pla

                jsr   HandleKeys                   ; Do the generic key handlers
                bcs   :do_more
                brl   do_render

:do_more
                bit   #PAD_BUTTON_A
                beq   :no_a
                pha
                jsr   handle_a
                pla
:no_a
                and   #$007F
                cmp   #LEFT_ARROW
                bne   *+5
                jmp   handle_left

                cmp   #RIGHT_ARROW
                bne   *+5
                jmp   handle_right

                cmp   #' '
                bne   :not_stop
                stz   PlayerXVel
                bra   do_render

:not_stop
                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
                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        StartY
                pei        StartX
                pei        StartY
                _GTESetBG0Origin
                bra        do_render
:not_s

                cmp        #'w'
                bne        :not_w
                lda        StartY
                beq        do_render
                dec        StartY
                pei        StartX
                pei        StartY
                _GTESetBG0Origin
                bra   do_render
:not_w

do_render
                jsr   UpdatePlayerPos        ; Apply forces
                jsr   ApplyCollisions        ; Check if we run into things
                jsr   UpdateCameraPos        ; Moves the screen

                pea   HERO_SLOT_1
                pei   PlayerX
                pei   PlayerY
                _GTEMoveSprite                    ; Move the sprite to this local position

                pea   HERO_SLOT_2
                pei   PlayerX
                lda   PlayerY
                clc
                adc   #16
                pha
                _GTEMoveSprite

                lda    StartX
                lsr
                pha
                lda    StartY
                lsr
                pha
                _GTESetBG1Origin

;                pea    #RENDER_BG1_HORZ_OFFSET
               pea    #RENDER_WITH_SHADOWING
;                pea    #0
                _GTERender

; Update the performance counters

                inc   frameCount
                pha
                _GTEGetSeconds
                pla
                cmp   OldOneSecondCounter
                beq   :noudt
                sta   OldOneSecondCounter
                jsr   UdtOverlay
                stz   frameCount
:noudt
                brl   EvtLoop


handle_a
                lda   PlayerStanding
                beq   :no_jump
                lda   #-9
                sta   PlayerYVel
:no_jump        rts

handle_left
                lda   PlayerXVel
                bpl   :ok
                cmp   #-4
                bcc   :out
:ok
                dec   PlayerXVel
:out
                jmp   do_render

handle_right    lda   PlayerXVel
                bmi   :ok
                cmp   #6
                bcs   :out
:ok
                inc   PlayerXVel
:out
                jmp   do_render


; Simple updates with gravity and collisions.  It's important that eveything in this
; subroutine be done against the VBL tick count
UpdatePlayerPos
            lda  PlayerGlobalY
            clc
            adc  PlayerYVel
            bpl  :not_neg_y
            lda  #0

:not_neg_y
            cmp  MaxGlobalY
            bcc  *+4
            lda  MaxGlobalY
            sta  PlayerGlobalY

            lda  PlayerGlobalX
            clc
            adc  PlayerXVel
            bpl  :not_neg
            lda  #0

:not_neg
            cmp  MaxGlobalX
            bcc  *+4
            lda  MaxGlobalX
            sta  PlayerGlobalX
            rts

ApplyCollisions

; Convert global to local coordinates

            lda  PlayerGlobalX
            sec
            sbc  StartX
            sta  PlayerX

            lda  PlayerGlobalY
            sec
            sbc  StartY
            sta  PlayerY

; Collision testing

            inc  PlayerYVel
            stz  PlayerStanding

; Check if the player is standing on the ground at their current local position

            pha                         ; space for result
            pei  PlayerX
            lda  PlayerY
            clc
            adc  #24
            pha
            _GTEGetTileAt
            pla

; Decide if mario's feet are on a "ground" tile (blocks, pipes, etc.)
            and  #TILE_ID_MASK
            cmp  #64
            bcc  :not_ground

            lda  PlayerYVel
            bmi  :not_ground

            lda  PlayerGlobalY
            and  #$fff8
            sta  PlayerGlobalY
            stz  PlayerYVel                     ; Stop falling when we hit the ground
            lda  #1
            sta  PlayerStanding
            bra  :y_ok

:not_ground
            lda  PlayerYVel
            bmi  :y_ok
            cmp  #8
            bcc  :y_ok
            lda  #7
            sta  PlayerYVel
:y_ok

            ldx  LastHFlip                     ; Update sprite frame based on actions
            lda  PlayerXVel
            beq  :no_dxv
            bpl  :pos_dxv
            ldx  #SPRITE_HFLIP
            bra  :no_dxv
:pos_dxv
            ldx  #0
:no_dxv
            sta  PlayerXVel
            stx  LastHFlip

            lda  SpriteCount
            eor  SpriteToggle
            sta  SpriteCount

; If the player is standing and XVel != 0, pick a frame

            ldx  #2
            lda  PlayerXVel
            beq  :frame

            jsr  _GetVBLTicks
            and  #$0006
            tax
:frame
            pea   HERO_SLOT_1
            pei   LastHFlip
            lda   HeroFrames1,x
            pha

            pea   HERO_SLOT_2
            pei   LastHFlip
            lda   HeroFrames2,x
            pha

            _GTEUpdateSprite
            _GTEUpdateSprite
            
            rts

HeroFrames1  dw    HERO_VBUFF_2,HERO_VBUFF_1,HERO_VBUFF_2,HERO_VBUFF_1
HeroFrames2  dw    HERO_VBUFF_4,HERO_VBUFF_3,HERO_VBUFF_4,HERO_VBUFF_3

; 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        appTmp0
            lda        PlayerGlobalX
            sec
            sbc        appTmp0
            bpl        :x_pos
            lda        #0
:x_pos      cmp        MaxBG0X
            bcc        :x_ok
            lda        MaxBG0X
:x_ok       sta        StartX

            lda        ScreenHeight
            lsr
            sta        appTmp0
            lda        PlayerGlobalY
            sec
            sbc        appTmp0
            bpl        :y_pos
            lda        #0
:y_pos      cmp        MaxBG0Y
            bcc        :y_ok
            lda        MaxBG0Y
:y_ok       sta        StartY

            pei        StartX
            pei        StartY
            _GTESetBG0Origin

            rts

; Timer callback to animate the background
UpdateBG1Offset
                ldal bg1offset
                pha
                inc
                inc
                stal bg1offset
                _GTESetBG1Displacement
                rtl
bg1offset       ds   2

; Exit code
Exit
                _GTEShutDown
Quit
                _QuitGS    qtRec

                bcs   Fatal
Fatal           brk   $00

qtRec           adrl  $0000
                da    $00

; Sprite VBUFF / Compile tokens
SpriteFlags1    ds    2
SpriteFlags2    ds    2

; Color palette
MyDirectPage    ds    2

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
                sta   MaxGlobalX
                sec
                sbc   ScreenWidth
                sta   MaxBG0X

                lda   TileMapHeight
                asl
                asl
                asl
                sta   MaxGlobalY
                sec
                sbc   ScreenHeight
                sta   MaxBG0Y

; Check if the current StartX and StartY are out of bounds
                lda   StartX
                cmp   MaxBG0X
                bcc   :x_ok
                lda   MaxBG0X
:x_ok           pha

                lda   StartY
                cmp   MaxBG0Y
                bcc   :y_ok
                lda   MaxBG0Y
:y_ok           pha
                _GTESetBG0Origin

                rts

; Load a binary file in the BG1 buffer
DoLoadBG1
                lda   BankLoad
                ldx   #BG1DataFile
                jsr   LoadFile

;                ldx   BankLoad
;                lda   #0
;                ldy   BG1DataBank
;                jsl   CopyBinToBG1

                pea   #256                      ; fill the whole buffer
                pea   #208
                pei   BankLoad
                pea   $0008                     ; skip header
                _GTECopyPicToBG1
                rts

_GetVBLTicks
            PushLong  #0
            _GetTick
            pla
            plx
            rts

BG1DataFile     strl  '1/bg1.bin'

frameCount      equ   24

                PUT        ../StartUp.s
                PUT        ../../shell/Overlay.s
                PUT        gen/App.TileMapBG0.s
