; Test driver to exercise graphics routines.

                    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

                    mx         %00

; Feature flags
NO_INTERRUPTS       equ        0                       ; turn off for crossrunner debugging
NO_MUSIC            equ        1                       ; turn music + tool loading off

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

; Typical init
                    phk
                    plb

                    jsl        EngineStartUp

                    lda        #^MyPalette               ; Fill Palette #0 with our colors
                    ldx        #MyPalette
                    ldy        #0
                    jsl        SetPalette

                    ldx        #5                        ; Mode 0 is full-screen, mode 5 is 256x160
                    ldx        #320
                    ldy        #200
                    jsl        SetScreenMode

; Set up our level data
                    jsr        BG0SetUp
                    jsr        TileAnimInit
                    jsr        SetLimits

                    jsr        InitOverlay             ; Initialize the status bar
                    stz        frameCount
                    ldal       OneSecondCounter
                    sta        oldOneSecondCounter
                    jsr        UdtOverlay

; Allocate a buffer for loading files
                    jsl        AllocBank               ; Alloc 64KB for Load/Unpack
                    sta        BankLoad                ; Store "Bank Pointer"

; Load in the 256 color background into BG1 buffer
                    brl        :nobackground
DoLoadBG1
                    lda        BankLoad
                    ldx        #BG1DataFile
                    jsr        LoadFile

                    ldx        BankLoad
                    lda        #0
                    ldy        BG1DataBank
                    jsl        CopyPicToBG1

; Copy the palettes into place

                    stz        tmp0
:ploop
                    lda        tmp0
                    tay
                    asl
                    asl
                    asl
                    asl
                    asl
                    clc
                    adc        #$7E00
                    tax

                    lda        BankLoad
                    jsl        SetPalette

                    inc        tmp0
                    lda        tmp0
                    cmp        #16
                    bcc        :ploop

; Bind the SCBs

                    lda        BankLoad
                    ora        #$8000                     ; set high bit to bind to BG1 Y-position
                    ldx        #$7D00
                    jsl        SetSCBArray
: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

                    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}

                    lda        #MUSHROOM_ID              ; 16x16 sprite, tile ID = 145
                    ldx        #80
                    ldy        #152
                    jsl        AddSprite

                    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

; Draw the initial screen

                    lda        #DIRTY_BIT_BG0_REFRESH  ; Redraw all of the tiles on the next Render
                    tsb        DirtyBits
                    jsl        Render

; Set up a very specific test.  First, we draw a sprite into the sprite plane, and then
; leave it alone.  We are just testing the ability to merge sprite plane data into 
; the play field tiles.
EvtLoop
                    jsl        ReadControl

; Check the buttons first
                    pha

                    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
:not_v
                    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
:not_q

                    cmp        #'d'
                    bne        :not_d
                    lda        StartX
                    cmp        MaxBG0X
                    bcs        :do_render
                    inc
                    jsl        SetBG0XPos
                    bra        :do_render
:not_d

                    cmp        #'a'
                    bne        :not_a
                    lda        StartX
                    beq        :do_render
                    dec
                    jsl        SetBG0XPos
                    bra        :do_render
:not_a

                    cmp        #'s'
                    bne        :not_s
                    lda        StartY
                    cmp        MaxBG0Y
                    bcs        :do_render
                    inc
                    jsl        SetBG0YPos
                    bra        :do_render
:not_s

                    cmp        #'w'
                    bne        :not_w
                    lda        StartY
                    beq        :do_render
                    dec
                    jsl        SetBG0YPos
                    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
: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
: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

                    lda        PlayerID
                    ldx        PlayerX
                    ldy        PlayerY
                    jsl        MoveSprite             ; Move the sprite to this local position

; Update the timers
                    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_vsync2
                    lda        #0
                    jsl        SetBorderColor
:no_vsync2

; Update the performance counters

                    inc        frameCount
                    ldal       OneSecondCounter
                    cmp        oldOneSecondCounter
                    beq        :noudt
                    sta        oldOneSecondCounter
                    jsr        UdtOverlay
                    stz        frameCount
:noudt
                    brl        EvtLoop

; Exit code
Exit
                    jsl        EngineShutDown

                    _QuitGS    qtRec

                    bcs        Fatal
Fatal               brk        $00

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
PlayerGlobalX       ds         2
PlayerGlobalY       ds         2

PlayerID            ds         2
PlayerX             ds         2
PlayerXOld          ds         2
PlayerY             ds         2
PlayerYOld          ds         2
PlayerLastPos       ds         2
PlayerXVel          ds         2
PlayerYVel          ds         2
KeyState            ds         2
PlayerStanding      ds         2
MaxGlobalX          ds         2
MaxGlobalY          ds         2
MaxBG0X             ds         2
MaxBG0Y             ds         2

oldOneSecondCounter  ds    2
frameCount           ds    2

PLAYER_X_MIN        equ   0
PLAYER_X_MAX        equ   160-4
PLAYER_Y_MIN        equ   0
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
                    lda        TileMapWidth
                    asl
                    asl
                    sta        MaxGlobalX
                    sec
                    sbc        ScreenWidth
                    sta        MaxBG0X

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

; Set the scroll position based on the global cooridinate of the player
; Try to center the player on the screen
UpdateCameraPos
                    lda        ScreenWidth
                    lsr
                    sta        tmp0
                    lda        PlayerGlobalX
                    sec
                    sbc        tmp0
                    bpl        :x_pos
                    lda        #0
:x_pos              cmp        MaxBG0X
                    bcc        :x_ok
                    lda        MaxBG0X
:x_ok               jsl        SetBG0XPos

                    lda        ScreenHeight
                    lsr
                    sta        tmp0
                    lda        PlayerGlobalY
                    sec
                    sbc        tmp0
                    bpl        :y_pos
                    lda        #0
:y_pos              cmp        MaxBG0Y
                    bcc        :y_ok
                    lda        MaxBG0Y
:y_ok               jsl        SetBG0YPos

                    lda        StartY
                    lsr
                    jsl        SetBG1YPos
                    rts

; Convert the global coordinates to adjusted local coordinated (compensating for wrap-around)
UpdatePlayerLocal
            lda  PlayerGlobalX
            sec
            sbc  StartX
;            jsr  AdjustLocalX
            sta  PlayerX

            lda  PlayerGlobalY
            sec
            sbc  StartY
;            jsr  AdjustLocalY
            sta  PlayerY
            rts

; Simple updates with gravity and collisions.  It's important that eveything in this
; subroutine be done against 
UpdatePlayerPos
            stz  PlayerStanding
            lda  PlayerYVel
            bmi  :no_ground_check

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

            ldx  PlayerX
            lda  PlayerY
            clc
            adc  #16
            tay
            jsr  GetTileAt
            and  #$1FF
            cmp  #EMPTY_TILE
            beq  :no_ground_check

            lda  PlayerGlobalY
            and  #$fff8
            sta  PlayerGlobalY
            stz  PlayerYVel
            lda  #1
            sta  PlayerStanding

:no_ground_check
            lda  PlayerGlobalY
            clc
            adc  PlayerYVel
            bpl  *+5
            lda  #0

            cmp  MaxGlobalY
            bcc  *+5
            lda  MaxGlobalY
            sta  PlayerGlobalY

            lda  PlayerGlobalX
            clc
            adc  PlayerXVel
            bpl  *+5
            lda  #0

            cmp  MaxGlobalX
            bcc  *+5
            lda  MaxGlobalX
            sta  PlayerGlobalX

            ldx  LastHFlip
            lda  PlayerXVel
            beq  :no_dxv
            bpl  :pos_dxv
            ldx  #SPRITE_HFLIP
            inc
            bra  :no_dxv
:pos_dxv
            ldx  #0
            dec
:no_dxv
            sta  PlayerXVel
            stx  LastHFlip

            ldx  #0
            lda  PlayerStanding
            bne  :too_fast

            lda  PlayerYVel
            inc
            bmi  :is_neg
            cmp  #4
            bcs  :too_fast
:is_neg
            ldx  #SPRITE_VFLIP
            sta  PlayerYVel
:too_fast

            txa
            ora  LastHFlip
            ora  #SPRITE_ID
            sta  SpriteFrame

            lda  SpriteCount
            eor  SpriteToggle
            sta  SpriteCount

; If the player is standing and XVel != 0, pick a frame
            lda  PlayerStanding
            beq  :frame
            lda  PlayerXVel
            beq  :frame

            jsl  GetVBLTicks
            and  #$0003
            inc
            and  #$0003
            asl
            adc  SpriteFrame
            sta  SpriteFrame
:frame
            lda  SpriteFrame
            ora  SpriteCount
            tax

            lda  PlayerID
            jsl  UpdateSprite                          ; Change the tile ID and / or flags

            rts

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
                    adrl       BG1DataFile             ; pathname

eofRec              dw         2                       ; pCount
                    ds         2                       ; refNum
                    ds         4                       ; eof

readRec             dw         4                       ; pCount
                    ds         2                       ; refNum
                    ds         4                       ; dataBuffer
                    ds         4                       ; requestCount
                    ds         4                       ; transferCount

closeRec            dw         1                       ; pCount
                    ds         2                       ; refNum

qtRec               adrl       $0000
                    da         $00

vsync               dw         $0000


LoadFile
                    stx        openRec+4               ; X=File, A=Bank (high word) assumed zero for low
                    stz        readRec+4
                    sta        readRec+6

:openFile           _OpenGS    openRec
                    bcs        :openReadErr
                    lda        openRec+2
                    sta        eofRec+2
                    sta        readRec+2

                    _GetEOFGS  eofRec
                    lda        eofRec+4
                    sta        readRec+8
                    lda        eofRec+6
                    sta        readRec+10

                    _ReadGS    readRec
                    bcs        :openReadErr

:closeFile          _CloseGS   closeRec
                    clc
                    lda        eofRec+4                ; File Size
                    rts

:openReadErr        jsr        :closeFile
                    nop
                    nop

                    PushWord   #0
                    PushLong   #msgLine1
                    PushLong   #msgLine2
                    PushLong   #msgLine3
                    PushLong   #msgLine4
                    _TLTextMountVolume
                    pla
                    cmp        #1
                    bne        :loadFileErr
                    brl        :openFile
:loadFileErr        sec
                    rts

msgLine1            str        'Unable to load File'
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