; *****************************************************************************
; *****************************************************************************
;
;                       Redraw the whole screen
;
; *****************************************************************************
; *****************************************************************************

_ScrCount:dw    0

Screen: push    es,ax,bx,cx,dx,si,di,bp
        mov     ax,[_ScrCount]          ; redraw screen
        cmp     ax,0                    ; only if screen count is zero.
        jnz     _NoPaint

        test    byte [PPUCtrl2],8
        jz      _NoRScrn

        push    cx                      ; Draw the background
        call    RedrawScreen
        pop     cx
_NoRScrn:

        test    byte [PPUCtrl2],16      ; Check if sprites being drawn
        jz      _NoSprites
        mov     bx,SpriteRAM+252
        mov     al,64
_Sprites:
        call    DrawSprite
        sub     bx,4
        dec     al
        jnz     _Sprites
_NoSprites:
        call    ScreenCopy
_NoPaint:
        pop     bp,di,si,dx,cx,bx,ax,es
        ret

; *****************************************************************************
;
;                               Redraw screen
;
;                     From ScanLine cl to Scanline ch !
;
;       To be implemented - horizontal scrolling.
;
; *****************************************************************************

RedrawScreen:
        mov     dl,[PPUVScroll]         ; dx = top line of screen,real coords
        xor     dh,dh

        push    cx                      ; dx = start line for redraw
        xor     ch,ch
        add     dx,cx
        pop     cx

        clc
        sub     ch,cl                   ; and do ch lines
        inc     ch
        ;
        ; At this point. dx is the first real screen line we want to write
        ; if you think of the screen as being 512 x 480 we must write
        ; the line in dx at screen scanline dl
        ;
        ; because they are normally done in chunks of 8, we need to make
        ; the current scan line (cl) up to the 8th line,so we can work
        ; in whole scan lines from there on.
        ;
        test    dx,7                    ; are we at a border anyway
        jz      NoMakeToEdge

        call    MakeBufferForDx         ; make tile buffer for the line
                                        ; that contains Dx.
        ;
        ; we need to start part way through the tile buffer -
        ; so we calculate the start position as 320 * (dl & 7)
        ;
        mov     ax,dx                   ; ax = dx & 7
        and     ax,7
        shl     ax,6                    ; ax = bx = * 64
        mov     bx,ax
        shl     ax,2                    ; ax = 256* bx = 64*
        add     ax,bx                   ; ax = 320*

        mov     bx,TileBuffer
        add     bx,ax                   ; bx is where we start drawing from
       
PadToStart:
        call    LineCopy                ; copy bx to scanline cl
        add     bx,320                  ; do the next tilebuffer line
        inc     cl                      ; next scan line
        dec     ch                      ; decrement lines to copy
        jz      RSExit
        inc     dx                      ; keep going until we've reached
        test    dx,7                    ; a tile border.
        jnz     PadToStart

        ;
        ;       at this point , we can write in whole scan blocks.
        ;

NoMakeToEdge:
        call    MakeBufferForDx         ; make a buffer for the current line
        mov     bx,TileBuffer
DrawScreen:
        call    LineCopy                ; copy bx to scanline cl
        add     bx,320                  ; do the next tilebuffer line
        inc     cl                      ; and the next scanline
        dec     ch                      ; decrement lines to copy
        jz      RSExit                  ; not finished yet
        inc     dx                      ; next scroll line
        test    dx,7
        jnz     DrawScreen              ; go back and do another
        jmp     NoMakeToEdge

RSExit: ret

; *****************************************************************************
;
;         Make the TileBuffer for the tile line CONTAINING DX
;         DX = 0..479 and is a pointer into the 50 tile lines that
;         make up the name table map.
;
; *****************************************************************************

MakeBufferForDX:
        push    ax,bx,cx,dx,si,di

_MDF1:  cmp     dx,480                  ; first make sure
        jb      _MDFRange               ; that dx isn't >= 480
        sub     dx,480                  ; it could be if you really scroll !
        jmp     _MDF1
        ;
        ;   first we have to get the home table, then if we are on the
        ;   bottom half of the virtual screen, we use its vertical pair
        ;   got by toggling 800h bit
        ;
_MDFRange:
        mov     bl,[PPUCtrl1]           ; get the address of the name table
        and     bl,3                    ; that is the 'home' table
        xor     bh,bh
        shl     bx,10                   ; bx = 000,400,800,C00
        add     bx,02000h               ; bx = 2000,2400,2800,2C00

        shr     dx,3                    ; convert 0..399 into 0..49
        cmp     dx,30                   ; if line < 25 then use this one.
        jl      _MDF2
        xor     bx,0800h                ; else use its vertical twin.
        sub     dx,30                   ; dx is now an vertical offset.

_MDF2:  mov     cl,dl                   ; save the tile vertical # in cl
        shl     dx,5                    ; dx = dx * 32

        mov     al,[PPUHScroll]         ; horizontal scrolling
        cmp     al,0
        jne     _MDFHscroll

        ;
        ;   only if there is no horizontal scrolling.
        ;

        call    MapPPUAddress           ; convert into a real address
        add     bx,PPURam               ; bx now ^ tile table base

        add     dx,bx                   ; dx ^ tile line
        mov     di,dx                   ; di = the tiles

        add     bx,03C0h                ; si = table base + 3C0h
        mov     si,bx                   ; e.g. the attribute table

        mov     dl,cl                   ; dl = vertical tile position
        mov     dh,0                    ; dh = horizontal tile position
        mov     bx,TileBuffer           ; bx = the buffer.
        mov     ch,32                   ; do 32 characters.
        call    RenderLine              ; Render that line into the tile buffer

_MDFExit:
        pop     di,si,dx,cx,bx,ax
        ret

        ;
        ;       Horizontal Scrolling
        ;

_MDFHScroll:
        push    bx,cx,dx                ; save page addr & tile vertical

        call    MapPPUAddress           ; convert into a real address
        add     bx,PPURam               ; bx now ^ tile table base

        add     dx,bx                   ; dx ^ tile line
        mov     di,dx                   ; di = the tiles

        add     bx,03C0h                ; si = table base + 3C0h
        mov     si,bx                   ; e.g. the attribute table

        mov     al,[PPUHScroll]         ; al = # tiles to scroll
        shr     al,3                    ; = hscroll / 8
        xor     ah,ah                   ; add it to the table base.
        add     di,ax

        mov     dl,cl                   ; dl = vertical tile position
        mov     dh,al                   ; dh = horizontal tile position
        mov     bx,TileBuffer           ; bx = the buffer.
        mov     ch,32                   ; do 32 characters - scroll#
        sub     ch,al

        call    RenderLine              ; Render that line into the tile buffer

        pop     dx,cx,bx                ; restore tilevert & page
        xor     bx,0400h                ; make bx point to the other page
        call    MapPPUAddress           ; points to page in RAM
        add     bx,PPURam
        add     dx,bx
        mov     di,dx                   ; di = the tiles
        add     bx,03C0h                ; si = table base + 3C0h
        mov     si,bx                   ; e.g. the attribute table

        mov     ah,[PPUHScroll]         ; al = 32 - HScroll/8
        shr     ah,3
        mov     al,32
        sub     al,ah
        xor     ah,ah                   ; ax = al * 32
        shl     ax,3

        mov     dl,cl                   ; dl = vertical tile position
        mov     dh,0                    ; dh = horizontal tile position
        mov     bx,TileBuffer           ; bx = the buffer.
        add     bx,ax
        mov     ch,[PPUHScroll]         ; do scroll#/8 + 1 characters
        shr     ch,3
        inc     ch

        call    RenderLine              ; Render that line into the tile buffer

        jmp     _MDFExit

; *****************************************************************************
;
;         Copy Data at DS:BX (256 pixels) out to Scan Line Cl
;                  adjust for horizontal scrolling
;
; *****************************************************************************

LineCopy:
        push    es,si,di,cx,bx,ax
        mov     al,[PPUHScroll]         ; add the scrolling offset
        and     al,7
        xor     ah,ah
        add     bx,ax

#if LineSize=320
        xor     ch,ch                   ; cx = line number
        add     cx,cx
        mov     si,cx
        add     si,[LineTable]
        mov     di,[si]                 ; get address from table
        cmp     di,0                    ; some we can't do
        jz      LineCopyExit
#endif
#if LineSize=256
        mov     ch,cl                   ; 256 byte lines... cx = cl * 256
        sub     ch,8
        xor     cl,cl
        mov     di,cx
#endif
        mov     es,[VSSegment]          ; es = VGA Screen
        mov     si,bx                   ; si = bx
        mov     cx,128                  ; copy 256 bytes
        rep     movsw
LineCopyExit:
        pop     ax,bx,cx,di,si,es
        ret

; *****************************************************************************
;
;                          Switch to Graphics Mode
;
; *****************************************************************************

ShowGraphic:
        mov     ah,1                    ; turn off the cursor
        mov     ch,020h
        int     010h
        mov     ah,0                    ; switch to 320x200 VGA mode
        mov     al,013h
        int     010h
        call    SetPalette
        ret


; *****************************************************************************
;
;                             Switch to Text Mode
;
; *****************************************************************************
ShowText:
        mov     ah,0                    ; switch to 80x25 colour mode
        mov     al,3
        int     010h
        mov     ah,1                    ; turn cursor back on
        mov     cx,0B0Ch
        int     010h
        ret

; *****************************************************************************
;
;                  Copy Virtual Screen to Real Screen
;
; *****************************************************************************

ScreenCopy:
        push    ax,cx,ds,es,si,di
        mov     ax,[VSSegment]          ; ds:si ^ screen line
        mov     ds,ax
        mov     es,0A000h
#if LineSize=320
        mov     si,32
        mov     di,32
        mov     al,200
#else
        mov     di,0
        mov     si,0
        mov     al,0
#endif
ScrCopy2:
        mov     cx,128                  ; words to copy
        rep     movsw
        add     si,LineSize-256
        add     di,LineSize-256

        dec     al
        jnz     ScrCopy2

        pop     di,si,es,ds,cx,ax
        ret

ClearVS:push    ax,bx,es
        mov     es,[VSSegment]
        xor     bx,bx
        xor     ax,ax
CVS1:   mov     es:[bx],ax
        inc     bx
        inc     bx
        jnz     CVS1
        pop     es,bx,ax
        ret
