; BGIFONT.INC v1.0 beta
;
; Written in pure assembler by Ivushkin Andrey aka Willow
;
; Created: December 16, 2004
;
; Last changed: August 27, 2006
;
; Compile with FASM

; BGI constants
BGI_NODRAW   equ 0x10000
BGI_ITALIC   equ 0x20000
BGI_BOLD     equ 0x40000
BGI_HALEFT   equ 0x0
BGI_HARIGHT  equ 0x1000
BGI_HACENTER equ 0x2000
BGI_VABOTTOM equ 0x0
BGI_VATOP    equ 0x4000
BGI_VACENTER equ 0x8000

BGI_FREE     equ 0x80000000
BGI_HAMASK   equ 0x3000
BGI_VAMASK   equ 0xc000

; Freetext structure
struc BGIfree FontName,XY,Angle,ScaleX,ScaleY,StrPtr,StrLen,Color,Align
{
    dd FontName ;0
    dd XY	    ;4
    dd Angle	;8
    dd ScaleX	;12
    dd ScaleY	;16
    dd StrPtr	;20
    dd StrLen	;24
    dd Color	;28
    dd Align	;32
}

; font options structure
struc BGIrec FontName,CharsCount,FirstChar,UpperMargin,LowerMargin,\
    Widths,FirstData,EOF,font_data
{
 .FontName     dd ?  ; 0
 .CharsCount   db ?  ; 4
 .FirstChar    db ?  ; 5
 .UpperMargin  db ?  ; 6
 .LowerMargin  db ?  ; 7
 .Widths       dd ?  ; 8
 .FirstData    dd ?  ; 12
 .EOF	       dd ?    ; 16
 .font_data    dd ?  ; 20 follows (Offsets)
}

macro BGIfont_GetID
{
    call _BGIfont_GetID
}

macro BGIfont_Prepare
{
    call _BGIfont_Prepare
}

macro BGIfont_Freetext
{
    call _BGIfont_Freetext
}

macro BGIfont_Outtext
{
    call _BGIfont_Outtext
}

macro _FI name,_size
{
    db name
if BGI_LEVEL eq KERNEL
    dw _size
end if
}

BGIfont_names:
_FI 'LCOM',11485   ;7
_FI 'EURO',8117    ;5
_FI 'GOTH',13816   ;6
_FI 'LITT',3596    ;8
_FI 'TRIP',11932   ;14
_FI 'SCRI',8490    ;11
_FI 'SMAL',4162    ;13
_FI 'TSCR',12134   ;15
_FI 'SANS',8453    ;10
_FI 'SIMP',9522    ;12
BGIfont_names_end:

macro BGIfont_Init
{
; in:  ecx - number of fonts to load;
;      esi-> _FI structure
;      edi-> where to load
    push edi
if  BGI_LEVEL eq KERNEL
    mov  edi,0x40000
end if
  .nfont:
    mov  edx,[esi]
if  BGI_LEVEL eq KERNEL
    movzx ebx,word[esi+4]
    mov  [BGIfont_Prepare.okflag],'N'
end if
    call _BGIfont_Prepare
if ~ BGI_LEVEL eq KERNEL
    add  esi,4
else
    push esi
    test eax,eax
    jz	 .fail
    mov  [BGIfont_Prepare.okflag],'*'
  .fail:
    mov  esi,BGIfont_Prepare.font
    call boot_log
    pop  esi
    add  esi,6
end if
    loop .nfont
    dph2 _BGI_BOLD,300,550
;    movzx edi,byte[0x40000]
    pop  edi
}

BGIfont_get2head:
    shr  ecx,28 ; font #
    sub  ecx,4
    jb	 .exit2	; invalid #
    mov  edi,[BGIfont_Ptr]
    inc  edi
    cmp  cl,[edi-1]
    jae  .exit2 ; # too large
    jecxz .ex
  .fnext:
    mov  edi,[edi+16]
    loop .fnext
    jmp  .ex
  .exit2:
    xor  edi,edi
  .ex:
    ret

BGIfont_GetName:
; in: ecx-fontID;
; out: edx-font name.
    call BGIfont_get2head
    xor  edx,edx
    test edi,edi
    jz   .ex
    mov  edx,[edi]
  .ex:
    ret

macro dps2 _str
{
if ~ BGI_LEVEL eq KERNEL
  if LOAD_MSG eq 1
    dps _str
  end if
else
    pusha
    mov  esi,BGIfont_Prepare.okflag
    mov  byte[esi], _str
    call boot_log
    popa
end if
}

macro dph2 num,x,y
{
if  BGI_LEVEL eq KERNEL
    pusha
    mov  eax,0x00080100
    mov  ebx,num
    mov  ecx,x shl 16+y
    mov  edx,0xFF0000
    call display_number
    popa
end if
}

_BGIfont_GetID:
; in:  edx-font name;
; out: eax-fontID, edi->BGIrec
    push ecx edi
    mov  edi,[BGIfont_Ptr]
    movzx ecx,byte[edi] ; ecx-font count
    mov  eax,ecx
    inc  edi ; edi->FontName
    jecxz .ex
  .fnext:
    cmp  edx,[edi]
    jne  .floop
    sub  eax,ecx
    add  eax,4
    shl  eax,28
    jmp  .ex
  .floop:
    mov  edi,[edi+16]
    loop .fnext
  .num0:
    xor  eax,eax
  .ex:
    pop  edi ecx
    ret

_BGIfont_Prepare:
; in:  edx-font name, edi->pointer to load fonts (fonts_count)
; out: eax-ID of new font loaded; eax=0 error
    cmp  [BGIfont_Ptr],0
    jne  .already
    mov  [BGIfont_Ptr],edi
  .already:
    pusha
    mov  edi,[BGIfont_Ptr]
    movzx ecx,byte[edi] ; ecx-font count
    mov  eax,ecx
    inc  edi ; edi->FontName
    jecxz .fload
  .fnext:
    cmp  edx,[edi]
    jne  .loop
    sub  eax,ecx
    inc  eax
    jmp  .cr_id
  .loop:
    mov  edi,[edi+16]
    loop .fnext
  .fload:
    mov  dword[.font],edx ; filename
    mov  esi,edi     ; esi->FontName
    mov  [.dest],edi ; ptr to load font
if ~ BGI_LEVEL eq KERNEL
        mov     eax, 70
        mov     ebx, .fontattr
        mcall
        test    eax, eax
        jnz     .fail
        dps2    '1'
        mov     eax, [.fileattr+32]
        mov     [.fsize], eax
    mov  ebx,.fontinfo
    mov  eax,70
    mcall	     ; ebx - file size
else
    push edi esi edx
    mov  eax,.font
    xor  ebx,ebx
    mov  esi,12
    mov  ecx,ebx
    mov  edx,edi
    call fileread
    pop  edx esi edi
    mov  ebp,edi
    add  ebp,ebx
    cmp  ebp,0x50000
    ja	 .fail
end if
    cmp  dword[edi],0x08084b50 ; 'PK',8,8
    jne  .fail
    dps2 '2'
    inc  edi
    mov  eax,26 ; #EOF
    mov  ecx,253
    cld
    repne scasb  ; skip Copyright
    test ecx,ecx
    jz	 .fail
    dps2  '3'
    cmp  edx,[edi+2] ; FontName
    jne  .fail
    dps2  '4'
    movzx ecx,word[edi] ; HeaderSize
    sub  ebx,ecx  ; Filesize-Headersize
    movzx eax,word[edi+6] ; FontSize
    cmp  eax,ebx
    jb	 .fail	  ; file truncated
    add  ecx,[.dest]
    dps2  '5'
    cmp  byte[ecx],'+'	; ParPrefix
    jne  .fail
; font is valid, let's fill parameter table
    dps2  '>'
    mov  [esi],edx ; FontName
    mov  edx,eax
    add  eax,ecx
    mov  [esi+16],eax ; Font EOF
    movzx eax,word[ecx+5]
    add  eax,ecx
    mov  [esi+12],eax
    lea  edi,[esi+4]  ; edi->CharsCount
    lea  esi,[ecx+1] ; esi->ParPrefix+1
    xor  eax,eax
    lodsw
    stosb  ; CharsCount
    inc  esi
    movsb  ; FirstChar
    add  esi,3
    lodsw
    stosb  ; UpperMargin
    movsb  ; LowerMargin
    add  esi,5 ; esi->offsets
    mov  eax,[esi]
    push edi ; edi->Widths
; prepare moving data
    add  edi,12 ; edi->offsets
    lea  ecx,[edx-16]
    rep  movsb
    pop  edi ; edi->Widths
    mov  [edi+8],esi ; EOF
;    mov  eax,[edi]
    movzx ecx,byte[edi-4] ; CharsCount
    lea  eax,[edi+12+ecx*2] ; eax->widths
    stosd  ; edi->FirstData
    add  eax,ecx
    stosd  ; edi->EOF
    mov  eax,[esp] ; eax->fonts_count
    inc  byte[eax] ; increase font counter
    movzx eax,byte[eax]
  .cr_id:
    add  eax,0x3   ; create unique ID
    shl  eax,28    ; to easy use in color(ecx)
    jmp  .exit
  .fail:
    xor  eax,eax
  .exit:
    mov  [esp+28],eax
    popa
    ret

if ~ BGI_LEVEL eq KERNEL
.fontinfo:
	dd 0
	dd 0
	dd 0
.fsize	dd 0
.dest	dd 0
.fontfullname:
	db BGIFONT_PATH
.font	db 'FONT.CHR',0

.fontattr:
        dd      5
        dd      0
        dd      0
        dd      0
        dd      .fileattr
        db      0
        dd      .fontfullname
.fileattr rd 40/4
else
  .dest   dd 0
  .font   db 'FONT    CHR'
  .okflag db ' ',0
end if

BGIfont_Coo:
; y->word[txt.y1], x->word[txt.x1]
    fild [txt.y1] ;y
    fmul st0,st0; y*y
    fild [txt.x1] ;x
    fmul st0,st0; x*x
    faddp  ; x*x+y*y
    fsqrt  ; sqrt, angle
    fild [txt.y1];y
    fabs
    fild [txt.x1] ; x
    fabs
    fpatan ; arctg(y/x)
  .skip:
    cmp  [txt.x1],0
    jge  .xplus
    fchs
    fadd st0,st3
  .xplus:
    cmp  [txt.y1],0
    jge  .yplus
    fchs
  .yplus:
    fadd st0,st2
    fsincos
    fmul st0,st2
    fiadd [txt.x0]
    fistp [txt.x1] ; x=r*cos a
    fmulp ; y=r*sin a,angle
    fiadd [txt.y0]
    fistp [txt.y1]
    ret

_BGIfont_Freetext:
; in: ebx-BGIfree structure
; out: eax-new drawing coords
    mov  edx,[ebx]
    call _BGIfont_GetID
    test eax,eax
    jnz  .fexists
    ret
  .fexists:
    pusha
    fninit
    fldpi
    fld  [pi180]
    fimul dword[ebx+8]
    fst  [BGIangle]
    mov  esi,[ebx+28]
    and  esi,0xffffff
    add  esi,eax
    mov  eax,[ebx+32]
    and  [deform],0
    test eax,BGI_ITALIC
    jz	 .norm
    mov  [deform],0.4
  .norm:
    mov  ebp,eax
    or	  ebp,BGI_FREE
    mov  eax,[ebx+12]
    mov  [Xscale],eax
    mov  eax,[ebx+16]
    mov  [Yscale],eax
    mov  ecx,[ebx+20]
    mov  edx,ebp
    and  edx,BGI_FREE+BGI_VAMASK+BGI_HAMASK
    add  edx,[ebx+24]
    mov  eax,[ebx+4]
    mov  ebx,esi
    add  ebx,0x6000000
    mov  [esp+4],edx
    mov  [esp+20],ecx
    jmp  txt

    pi180 dd 0.017453

_BGIfont_Outtext:
; in: ebx-[x][y], ecx-color, edx-string, esi-length
    pusha
    mov  ebp,esi
if ~ BGI_LEVEL eq KERNEL
    mov  eax,ebx
    mov  ebx,ecx
    mov  ecx,edx
    mov  edx,esi
end if
; in: eax-[x][y], ebx-color, ecx-string, edx-length
txt:
if  ~ BGI_LEVEL eq KERNEL
  if  BGI_WINDOW_CLIP eq 1
    pusha
    mov  eax,9
    mov  ebx,BGI_PRC_INFO
    mov  ecx,-1
    mcall
    popa
  end if
end if
    mov  [.y0],ax
    shr  eax,16
    mov  [.x0],ax
    mov  ecx,ebx ; color
    and  ebx,0xfffffff
    mov  [.color],ebx
    call BGIfont_get2head
    test edi,edi
    jz   .exit
    mov  ecx,[esp+4]; str length
    mov  esi,[esp+20]; str ptr
    movzx eax,byte[edi+5]
    push ecx
    and  ecx,0xff
    jnz  .lenok
    add  esp,4
    jmp  .ex2
  .lenok:
    pusha
    push dword[txt.y0]
    and  dword[txt.y0],0
    xor  edx,edx
    mov  ebx,[edi+8]
   .next:
    call txt.BGIfont_GetChar
    movzx eax,byte[ebx+eax]
    add  edx,eax
    loop .next
    mov  ecx,edx ; ecx - x size
    movzx dx,byte[edi+6]
    mov  [BGIheight],dx
    mov  ebx,[esp+36]
    and  ebx,BGI_HAMASK
    cmp  ebx,BGI_HARIGHT
    je   .nova
    ja   .subv
    xor  ecx,ecx
    jmp  .nova
  .subv:
    shr  cx,1
  .nova:
    mov  ebx,[esp+36]
    and  ebx,BGI_VAMASK
    cmp  ebx,BGI_VATOP
    je   .def
    ja   .subh
    xor  edx,edx
    jmp  .def
  .subh:
    shr  dx,1
  .def:
    call txt.BGIfont_Deform
    pop  dword[txt.y0]
    popa
    pop  ebx
    mov  ax,[txt.y1]
    sub  [txt.y0],ax
    mov  ax,[txt.x1]
    sub  [txt.x0],ax
    xor  eax,eax
    cld
.mloop:
    push [.y0]
    pop  [.y]
    push [.x0]
    pop  [.x]
    call .BGIfont_GetChar
    push esi
    lea  esi,[edi+20] ; offset
    movzx edx,word[esi+eax*2] ; ofs1
    add  edx,[edi+12]
    inc  eax
    cmp  al,[edi+4]
    je	 .eof
    movzx eax,word[esi+eax*2]; ofs2
    add   eax,[edi+12]
    jmp   .prc_vec
  .eof:
    mov  eax,[edi+16] ; ofs2=eof
  .prc_vec:  ; edx-vec cmd ifs, eax-cmd limit
    mov  [.vec_end],eax
    push ecx
  .vec_loop:
    mov  ax,word[edx]
    push edx
    mov  ecx,eax
    and  eax,0x8080 ; op
    and  ecx,0x7f ; xx
    mov  edx,[edx+1]
    and  edx,0x7f ; yy
    cmp  edx,63
    jbe  .positive
    sub  edx,128  ; yy-=128
  .positive:
    cmp  ecx,63
    jbe  .positive2
    sub  ecx,128  ; xx-=128
  .positive2:
    call .BGIfont_Deform
    cmp  eax,0x8080
    jne  .noline
    test ebp,BGI_NODRAW
    jnz  .noline
; draw vector
if ~ BGI_LEVEL eq KERNEL
    push eax
    mov  ebx,dword[.x1]
    mov  ecx,dword[.y1]
  if BGI_WINDOW_CLIP eq 1
    movzx eax,[.x]
    cmp  eax,dword[BGI_PRC_INFO+42]
    ja   .nobold
    movzx eax,[.y]
    cmp  eax,dword[BGI_PRC_INFO+46]
    ja  .nobold
    xor  eax,eax
    cmp  ax,bx
    jg   .nobold
    cmp  ax,cx
    jg   .nobold
  end if
    mov  edx,[.color]
; \begin{diamond}[18.08.2006]
; starting from K0530 kernel interprets flag 0x1000000 as
; negate existing pixels colors, disregarding passed color
; we do not want this
    and  edx, 0xFFFFFF
; \end{diamond}[18.08.2006]
    mov  eax,38
    mcall
    test ebp,BGI_BOLD
    jz	 .nobold
    test ebp,BGI_FREE
    jnz  .free5
  .free5:
    add  ebx,1 shl 16+1
    mcall
  .nobold:
    pop  eax
else
    pusha
    mov  eax,dword[.x1]
    mov  ebx,dword[.y1]
    mov  ecx,[.color]
;    call syscall_drawline
    test dword[esp+8],BGI_BOLD
    jz	 .nobold
    add  eax,1 shl 16+1
;    call syscall_drawline
  .nobold:
    popa
end if
  .noline:
    pop  edx
    test eax,eax
    je	 .eovecs  ; op=0
    push [.y1]
    pop  [.y]
    push [.x1]
    pop  [.x]
    add  edx,2
    cmp  edx,[.vec_end]
    jb	 .vec_loop
  .eovecs:
    pop  ecx esi
    push [.y]
    pop  [.y0]
    push [.x]
    pop  [.x0]
    loop .mloop1
    jmp  .exit
  .mloop1:
    jmp  .mloop
  .exit:
    mov  eax,dword[.y0]
    mov  [esp+28],eax
  .ex2:
    popa
    ret

.BGIfont_Deform:
    test ebp,BGI_FREE
    jnz  .free0
    movzx ebx,byte[.color+3] ;ebx=scale
    imul ecx,ebx
    add  ecx,2
    shr  ecx,2
    imul edx,ebx
    add  edx,2
    shr  edx,2
    neg  edx
    mov  [.x1],cx
    mov  [.y1],dx
    jmp  .add
  .free0:
    mov  [.x1],cx
    mov  [.y1],dx
    fild [.y1]
    fld  st0
    fmul [Yscale]
    fchs
    fistp [.y1]
    fmul [deform]
    fiadd [.x1]
    fmul [Xscale]
    fistp [.x1]
    cmp  [BGIangle],0
    je	 .add
    call BGIfont_Coo
    jmp  .eax
  .add:
    mov  cx,[.x0]
    add  [.x1],cx
    mov  cx,[.y0]
    add  [.y1],cx
  .eax:
    ret

.BGIfont_GetChar:
; in:  esi -> string; edi -> BGIrec
; out: esi -> next char; al - char obtained
    lodsb  ; al - char from str
    sub  al,[edi+5]
    jb	 .out
    cmp  al,[edi+4]
    jb	 .in
  .out:
    xor  al,al ; al - 1st symbol available
  .in:
    ret

.y0	 dw ?
.x0	 dw ?

.x1	 dw ?
.x	 dw ?
.y1	 dw ?
.y	 dw ?

.color	 dd ?
.vec_end dd ?
BGIfont_Ptr  dd 0
BGIheight dw ?
deform dd ?
BGIangle dd ?
Xscale  dd ?
Yscale  dd ?