;***********************************************************************
; BOS, Christoffer Bubach 2004.
; Textmode screen "driver".
;***********************************************************************

;-------;
; TODO: ;
;----------------------------------------------------------;
; - Have 80*25 values in vars so that they can             ;
;   be changed when higher text res. is supported.         ;
;                                                          ;
; - Make all function have (e)ax as standard input reg?    ;
;----------------------------------------------------------;


; Change cursor attribs. IN: CX = cursor attribs
;------------------------------------------------
changecursor:
                push    eax
                push    edx

                mov     dx, 0x3D4
                mov     al, 0x0A
                mov     ah, ch
                out     dx, ax
                inc     ax
                mov     ah, cl
                out     dx, ax

                pop     edx
                pop     eax
                ret



; Clear the screen.
;--------------------
cls:
                push    edx
                push    ecx

                mov     ecx, 25
          .loop:
                call    scroll_up
                loop    .loop

                mov     dh, 0x00
                mov     dl, 0x00
                call    setcursorxy

                pop     ecx
                pop     edx
                ret



; Get the cursor pos. OUT: DH = X   DL = Y
;------------------------------------------
getcursorxy:
                push    eax
                push    ebx

                call    getcursor
                mov     ax, bx
                mov     dl, 80
                div     dl
                mov     dl, al
                mov     dh, ah

                pop     ebx
                pop     eax
                ret



; Get the cursor pos. OUT: BX = Offset
;--------------------------------------
getcursor:
                push    eax
                push    edx

                mov     dx, 0x3D4
                mov     al, 0eh
                out     dx, al
                inc     dx
                in      al, dx
                mov     bh, al
                mov     al, 0x0F
                dec     dx
                out     dx, al
                inc     dx
                in      al, dx
                mov     bl, al

                pop     edx
                pop     eax
                ret



; Set the cursor to:  DH = X   DL = Y
;--------------------------------------
setcursorxy:
                push    eax
                push    ebx
                push    edx

                movzx   bx, dl
                mov     ax, bx
                shl     ax, 4
                shl     bx, 6
                add     bx, ax
                movzx   ax, dh
                add     bx, ax

                call    setcursor

                pop     edx
                pop     ebx
                pop     eax
                ret



; Set the cursor to:  BX = Offset
;---------------------------------
setcursor:
                push    eax
                push    ebx
                push    edx

                mov     al, 0x0E
                mov     ah, bh
                mov     dx, 0x3D4
                out     dx, ax
                inc     ax
                mov     ah, bl
                out     dx, ax

                pop     edx
                pop     ebx
                pop     eax
                ret



; cursor position +1
;--------------------
inccursor:
                push    ebx

                call    getcursor
                cmp     bx, 0x7CF
                jne     .cont
                call    scroll_up
                jmp     .end

          .cont:
                inc     bx
                call    setcursor

           .end:
                pop     ebx
                ret



; cursor position -1
;--------------------
deccursor:
                push    ebx

                call    getcursor
                cmp     bx, 0
                je      .end

                dec     bx
                call    setcursor

           .end:
                pop     ebx
                ret




; Backspace - delete last typed char.
;--------------------------------------
backspace:
                push    ebx

                call    deccursor      ; If we are at pos. 0 this would delete..

                mov     bh, 0x07       ; ..the char in front on the cursor.
                mov     bl, byte ' '   ; Rewrite when i feel for it...
                call    print_char

                call    deccursor

                pop     ebx
                ret




; Print char. IN: bl = char, bh = attrib 
;----------------------------------------
print_char:
                pushad
                push    ebx

                cmp     bl, 13   ; check for enter
                jne     .cont
                call    new_line
                jmp     .done

          .cont:
                cmp     bl, 10   ; ignore
                je      .done

                call    getcursor

                movzx   eax, bx
                pop     ebx
                mov     [es:(eax*2 + 0xb8000)], bx

                call    inccursor
                push    ebx

          .done:
                pop     ebx
                popad
                ret




; Print 32-bit hex value.
;          IN: eax = value, bh = color.
;--------------------------------------------
          hex2ascii db   "0123456789ABCDEF"

print_hex32:
          push    eax
          push    ebx
          push    ecx
          push    edx
          push    esi

          mov     ecx, 8
          lea     esi, [hex2ascii]
.print_it:
          rol     eax, 4
          movzx   edx, al
          and     dl, 0x0F
          mov     bl, [esi+edx]
          call    print_char
          loop    .print_it

          pop     esi
          pop     edx
          pop     ecx
          pop     ebx
          pop     eax
          ret




; Display a asciiz message on the screen.
;       Input: ESI = Message, AL = COLOR.
;--------------------------------------------
print:
                pushad

                mov     bh, al

   .displaychar:
                lodsb
                or      al, al
                jz      .done

                mov     bl, al
                call    print_char
                jmp     .displaychar

          .done:
                popad
                ret




; Make a new line (CR, LF).
;-----------------------------------
new_line:
                push    edx
                push    eax

                call    getcursorxy
                cmp     dl, 0x18
                jb      .newline

                call    scroll_up
                jmp     .done

       .newline:
                call    getcursorxy
                mov     dh, 0x00
                inc     dl
                call    setcursorxy

          .done:
                pop     eax
                pop     edx
                ret





; Scrolling..
;--------------
scroll_up:      pushad
                call    _scroll_up
                popad

       .mv_curs:
                mov     bx, 80*24
                call    setcursor
                ret

     _scroll_up:
                push    edi
                push    esi

                mov     edi, 0b8000h
                mov     esi, 0b8000h+160
                mov     ecx, (160*24)/4
                rep     movsd

                mov     edi, 0b8000h+160*24
                mov     ecx, 80/2
                mov     eax, 07000700h
                rep     stosd

                pop     esi
                pop     edi
                ret

