;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                        ;;
;;  VGA.INC                                               ;;
;;                                                        ;;
;;  640x480 mode 0x12 VGA functions for MenuetOS          ;;
;;                                                        ;;
;;  Paul Butcher, paul.butcher@asa.co.uk                  ;;
;;                                                        ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



paletteVGA:

;16 colour palette
       mov    dx,0x3c8
       mov    al,0
       out    dx,al

       mov    ecx,16
       mov    dx,0x3c9
       xor    eax,eax

     palvganew:

       mov al,0
       test ah,4
       jz palvgalbl1
       add al,31
       test ah,8
       jz palvgalbl1
       add al,32
     palvgalbl1:
       out dx,al  ; red 0,31 or 63
       mov al,0
       test ah,2
       jz palvgalbl2
       add al,31
       test ah,8
       jz palvgalbl2
       add al,32
     palvgalbl2:
       out dx,al  ; blue 0,31 or 63
       mov al,0
       test ah,1
       jz palvgalbl3
       add al,31
       test ah,8
       jz palvgalbl3
       add al,32
     palvgalbl3:
       out dx,al  ; green 0,31 or 63
       add ah,1
       loop palvganew

       ret


vga_putimage:
; pushad
 call    [disable_mouse]
 push ebp ;
 push esi ;
 push edi ;

 push eax ;
 push ebx ; +8 [ptrImage]
 push ecx ; +4 [BH]
 push edx ; +0 [xy]

 movzx eax,word [esp+2]   ; eax:=x
 movzx ebx,word [esp+0]   ; ebx:=y
 mov ecx,[0x3010]         ;
 add eax,[ecx-twdw]     ; eax+=Xwin
 add ebx,[ecx-twdw+4]   ; ebx+=Ywin
 mov ecx,ebx              ; ecx = y+Ywin
 mov edx,eax              ; edx = x+Xwin

 imul ebx, 640*4          ; (y+Ywin)*BytesPerScanLine
 shl eax,2                ; (x+Xwin)*BytesPerPixel
 add eax,ebx              ;
 mov edi,eax              ; store copy
        add eax,[0xfe80]         ; +AddrLFB
 ;entry point in LFB >> EAX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrLFB

 shr edi,5                ; change from 4 to 1/8 BytesPerPixel
 add edi,0xa0000          ; + VGABasePtr
 ;VGA start address >> EDI:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrVGA

 mov ebx, [0xfe00]        ; ScreenXSize
 inc ebx                  ; +1
 imul ebx,ecx             ; *(y+Ywin)
 mov ebp, ebx             ;
 add ebp, edx             ; +(x+Xwin)
 add ebp, WinMapAddress   ; ebp:=(y+Ywin)*(ScreenXSize+1)+(x+Xwin)+AddrBuffer

 mov esi,[esp+8] ; esi:=AddrImg
 movzx ecx,word [esp+6] ; ecx:=B
 movzx ebx,word [esp+4] ; ebx:=H

 ; check limits while draw ?

 push ecx ; B
 push eax ; LFB address

 mov eax,[0x3010]
 mov ecx,[eax+draw_data-0x3000+0]
 cmp ecx,0
 jnz dbcblimitlset_vga

 mov ecx,[eax+draw_data-0x3000+4]
 cmp ecx,0
 jnz dbcblimitlset_vga

 mov ecx,[eax+draw_data-0x3000+8]
 cmp ecx,[0xfe00] ; ecx <> Screen X size
 jnz dbcblimitlset_vga

 mov ecx,[eax+draw_data-0x3000+12]
 cmp ecx,[0xfe04] ; ecx <> Screen Y size
 jnz dbcblimitlset_vga

 pop eax ; LFB address
 pop ecx ; B

 push dword 0

 jmp pimvga

      dbcblimitlset_vga:

 pop eax ; LFB address
 pop ecx ; B

 push dword 1

pimvga:
 push edi
 push esi
 push eax  ; LFB address
 push ecx  ; B
 push ebx  ; H
 push edx  ; x+Xwin

 mov ebx,[0x3010]
 mov bl,[ebx+0xe]
 mov bh,[esp+6*4]

 cld

 npvga:

   cmp bl,[ds:ebp]
   jnz impvgano

;   cmp bh,0
;   jz impvgayes

;   call voodoodbcplimit
;   jnz impvgano

; impvgayes:

   push eax  ; LFB address
   push ebx  ; app no.
   push ecx  ; B
   push edx  ; x+Xwin

   mov edx,[esi] ; color
   mov [eax],dx
   shr edx,16
   mov [eax+2],dl

   mov eax,[esi] ; color
   mov ecx,[esp] ; x+Xwin
   and ecx,0x07  ; modulo 8
   call setvgapixel ; eax=color, ecx=x%8, edi=VGA address

   pop edx
   pop ecx
   pop ebx
   pop eax

 impvgano:

   add esi,3 ; esi+=3 ptrImage+=3
   add eax,4 ; eax+=4 LFBaddr +=4
   inc ebp
   inc edx ; x+Xwin+n

   test edx,0x07  ; test modulo 8
   jnz impvgacont
   inc edi

        impvgacont:
   dec ecx ; B--
   jnz npvga

      pop edx
      pop ebx
      pop ecx
      pop eax
      pop esi
      pop edi

      add edi,640/8  ; add one VGA line
      add eax,640*4  ; add one LFB line

      sub ebp, ecx ;  -B
      add ebp, [0xfe00] ;
      inc ebp ; ptrBuffer:=ptrBuffer-B+Screen_Xsize+1

      push ecx
      lea ecx,[ecx+ecx*2] ;
      add esi,ecx ; ptrImage:=ptrImage+B*3
      pop ecx

      dec ebx ; H--
      jnz near pimvga

      add esp,4  ; jump saved limit byte
      pop edx
      pop ecx
      pop ebx
      pop eax
      pop edi
      pop esi
      pop ebp
      
;      call  [draw_pointer]
;      call    [disable_mouse]
;      popad
      ret


VGA_putpixel:

 ; eax = x
 ; ebx = y

 mov     ecx,eax
 mov     eax, [esp+32-8+4] ; color

 imul    ebx, 640*4        ; y*BytesPerLine (Vesa2.0 32)
 lea     edx, [ebx+ecx*4]  ; + x*BytesPerPixel (Vesa2.0 32)

 mov     edi,edx
 add     edi, [0xfe80]     ; + LFB address
 mov     [edi], eax        ; write to LFB for Vesa2.0

 shr     edx,5             ; change BytesPerPixel to 1/8
 mov     edi,edx
 add     edi, 0x0a0000     ; address of pixel in VGA area

 and     ecx,0x07          ; bit no. (modulo 8)

setvgapixel:
 cli
 ; edi = address, eax = 24bit colour, ecx = bit no. (modulo 8)

 push   eax
 mov    ebx,eax            ; color

 ;mov    al,0x08
 ;mov    dx,0x03ce
 ;out    dx,al             ; select GDC bit mask register

 inc    cl
 mov    ax, 0x100
 shr    ax,cl
 mov    dx,0x03cf
 out    dx,al              ; set bit mask for pixel

 mov    dl,0
 mov    eax,ebx
 and    eax,0x000000ff     ; blue
 cmp    eax,85
 jle    p13green
 or     dl,0x01
 cmp    eax,170
 jle    p13green
 or     dl,0x08

p13green:
 and    ebx,0x0000ff00     ; green
 cmp    ebx,85*256
 jle    p13red
 or     dl,0x02
 cmp    ebx,170*256
 jle    p13red
 or     dl,0x08

p13red:
 pop    ebx
 and    ebx,0x00ff0000     ; red
 cmp    ebx,85*256*256
 jle    p13cont
 or     dl,0x04
 cmp    ebx,170*256*256
 jle    p13cont
 or     dl,0x08

p13cont:
 mov    al,[edi]           ; dummy read
 mov    [edi],dl

 sti
 ret


vga_drawbar:
;     pushad
 call    [disable_mouse]
     sub edx,ebx ; edx:=Yend-Ystart=H
     sub ecx,eax ; ecx:=Xend-Xstat=B

     push ebp ; +24
     push esi ; +20
     push edi ; +16
     push eax ; +12
     push ebx ; +8
     push ecx ; +4
     push edx ; +0

     mov ecx,[0x3010] ;
     add eax,[ecx-twdw] ; eax:=Xwin+x
     add ebx,[ecx-twdw+4] ; ebx:=Ywin+y
     mov ecx, eax ; ecx:=(x+Xwin)
     mov edx, ebx ; edx:=(y+Ywin)

     imul ebx, 640/8  ;
     mov edi, ebx ; edi:=BytesPerScanLine*(y+Ywin)
     shr eax, 3 ;
     add edi, eax ;  + (x+Xwin)*BytesPerPixel
     add edi,0xa0000  ; + VGAbaseaddress

     mov eax, [0xfe00] ; ScreenXSize
     inc eax ; +1
     imul eax,edx ; *(y+Ywin)
     mov ebp, eax ;
     add ebp, ecx ; +(x+Win)
     add ebp, WinMapAddress ; +AddrBuffer

     mov eax, [0xfe08]  ; BytesPerScanLine - LFB
     mul edx            ; *(y+Ywin)
     mov esi,eax
     add esi,ecx
     add esi,ecx
     add esi,ecx
     add esi,ecx        ; + 4*(x+Xwin)
     add esi,[0xfe80]   ; +AddrLFB

; edi:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel + AddrVGA
; esi:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel + AddrLFB
; ebp:=(y+Ywin)*(ScreenXSize+1)+(x+Xwin)+AddrBuffer

; x size

     mov eax,[esp+4] ; B [esp+4]
     mov ebx,[esp+0] ; H

     mov edx,[esp+16] ; color
     test edx,0x80000000
     jz nodbglvga

     ; no color glide for VGA - set to half glide
     shr ebx,1  ; H/2
     sub edx,ebx
     mov [esp+16],edx
     mov ebx,[esp+0] ; reset to H

   nodbglvga:
     ; check limits ?

     push eax
     push ecx

     mov eax,[0x3010]

     mov ecx,[eax+draw_data-0x3000+0]
     cmp ecx,0
     jnz dbcblimitlset_vga2

     mov ecx,[eax+draw_data-0x3000+4]
     cmp ecx,0
     jnz dbcblimitlset_vga2

     mov ecx,[eax+draw_data-0x3000+8]
     cmp ecx,[0xfe00]
     jnz dbcblimitlset_vga2

     mov ecx,[eax+draw_data-0x3000+12]
     cmp ecx,[0xfe04]
     jnz dbcblimitlset_vga2

     pop ecx
     pop eax

     push dword 0

     jmp dbnewpivga

   dbcblimitlset_vga2:

     pop ecx ; x+Xwin
     pop eax ; B

     push dword 1

   dbnewpivga:

     push eax; B
     push ebx ; H
     push edi
     push esi
     push ecx ; x+Xwin

     mov   ebx,[0x3010]
     movzx ebx,byte[ebx+0xe]

     cld

     dbnpvga:

       mov dl,[ds:ebp]

       cmp dl,bl
       jnz dbimpvgano

;       mov edx,[esp+5*4] ; check limit?
;       cmp edx,0
;       jz dbimpvgayes

;       call voodoodbcplimit
;       jnz  dbimpvgano

;     dbimpvgayes:

       push eax ; B
       push ebx
       push ecx ; x+Xwin

       mov eax,[esp+12+20+16+4] ; color
       mov ebx,eax

       mov [esi],bx    ; write LFB pixel
       shr  ebx,16
       mov  [esi+2],bl

       and ecx,0x07 ; modulo 8
       call setvgapixel ; eax=color, ecx=x%8, edi=VGA address

       pop ecx
       pop ebx
       pop eax

     dbimpvgano:

       add esi,4    ; ptrLFB+=4
       inc ebp  ; address buffer
       inc ecx  ; x posn++
       test ecx,0x07  ; test modulo 8
       jnz dbvgacont
       inc edi  ; VGA screen ptr++

     dbvgacont:
       dec eax  ; B--  NB ecx in Vesa20 fn?
       jnz dbnpvga

   dbnpvgad:

     pop ecx
     pop esi
     pop edi
     pop ebx
     pop eax

     add esi,[0xfe08]            ; ptrLFB+=BytesPerScanLine
     add edi,640/8               ; ptrScreen+=BytesPerScanLine

     add ebp,[0xfe00]            ;
     sub ebp, eax                ; was ecx in vesa20 fn?
     inc ebp                     ; ptrBuffer:=ptrBuffer-B+BytesPerLine+1

     dec ebx                     ; H--
     jz nodbnewpivga             ; H<>0

     jmp dbnewpivga

   nodbnewpivga:

     add esp,7*4   ; NB includes limit check flag
     ;pop ebx
     ;pop eax
     ;pop edi
     ;pop esi
     pop ebp

     ;pop edx
     ;pop ecx
;     popad
     ret


vga_drawbackground_tiled:
 call    [disable_mouse]
     push ebp
     push eax
     push ebx
     push ecx
     push edx

     mov edx,dword [0x400000-8] ; B
     add edx,dword [WinMapAddress-8] ; +B
     add edx,dword [WinMapAddress-8] ; +B
     push edx

     mov eax,[draw_data+32+0] ; x start:=(x+Xwin)
     mov ebx,[draw_data+32+4] ; y start:=(y+Ywin)
     mov ecx,eax
     mov edx,ebx

     imul edx, 640*4          ; (y+Ywin)*BytesPerScanLine
     shl ecx,2                ; (x+Xwin)*BytesPerPixel
     add ecx,edx              ;
     mov ebp,ecx              ; store copy
     add ecx,[0xfe80]         ; +AddrLFB
  ;entry point in LFB >> ECX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+Addr

     shr ebp,5                ; change from 4 to 1/8 BytesPerPixel
     add ebp,0xa0000          ; + VGABasePtr
  ;VGA start address >> EBP:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrV


     call calculate_edi

   dp3vga:                            ; MAIN LOOP

     cmp [edi+WinMapAddress],byte 1     ; ptrBuffer^<>byte(1)
     je  ybgpvga

     jmp nbgpvga

   ybgpvga:

     push eax  ; x
     push ebx  ; y
     push ecx  ; LFB address

     mov ecx,dword [WinMapAddress-8]    ; B
     xor edx,edx                   ; edx:=0
     div ecx                       ; Xstart/B

     ; eax=Int(qn) edx:=Rem

     lea esi,[edx+edx*2]           ; esi:=edx*3

     mov ecx,dword [WinMapAddress-4]    ; ecx:=H
     mov eax,[esp+4]               ; eax:=Ystart
     xor edx,edx                   ;
     div ecx                       ; Ystart/H

     mov eax,edx                   ; eax:=Rem
     xor edx,edx                   ;
     mov ebx,[esp+12]              ; ebx:=B*3
     mul ebx                       ;
     add esi,eax                   ;

     mov eax,[esi+0x300000]        ; color
     and eax,0xffffff

     mov ecx, [esp]   ; LFB address
     mov ebx,eax      ; copy color
     mov [ecx],bx
     shr ebx,16
     mov [ecx+2],bl

     xchg edi, ebp
     mov  ecx,[esp+8]     ; x position
     and  ecx,0x07        ; x modulo 8
     call setvgapixel     ; eax=color, ecx=x%8, edi=VGA address
     xchg ebp, edi

     pop ecx
     pop ebx
     pop eax

   nbgpvga:

     inc eax                       ; x++
     cmp eax,[draw_data+32+8]         ; X > xend?
     jg  nodp3vga

     test eax,0x07                 ; x test modulo 8
     jnz hook1vga
     inc ebp                       ; VGA address++

   hook1vga:
     add ecx,4                     ; LFB address += 4
     inc edi                       ; ptrBuffer++
     add esi,3                     ; ptrImage+=3
     jmp dp3vga

   nodp3vga:

     mov eax,[draw_data+32+0]         ; x+Xwin
     inc ebx                       ; y position
     mov ecx,eax
     mov edx,ebx

     imul edx, 640*4          ; (y+Ywin)*BytesPerScanLine
     shl ecx,2                ; (x+Xwin)*BytesPerPixel
     add ecx,edx              ;
     mov ebp,ecx              ; store copy
     add ecx,[0xfe80]         ; +AddrLFB
    ;entry point in LFB >> ECX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+Addr


     shr ebp,5                ; change from 4 to 1/8 BytesPerPixel
     add ebp,0xa0000          ; + VGABasePtr
   ;VGA start address >> EBP:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrV


     call calculate_edi

     cmp ebx,[draw_data+32+12]         ; Y > yend
     jg  dp4vga

     jmp dp3vga

   dp4vga:

     add esp,4

     pop edx
     pop ecx
     pop ebx
     pop eax
     pop ebp

     ret

; ----------



vga_drawbackground_stretch:
 call    [disable_mouse]

     push ebp
     push eax
     push ebx
     push ecx
     push edx

     mov edx,dword [WinMapAddress-8] ; B
     add edx,dword [WinMapAddress-8] ; +B
     add edx,dword [WinMapAddress-8] ; +B
     push edx

     mov eax,[draw_data+32+0] ; x start:=(x+Xwin)
     mov ebx,[draw_data+32+4] ; y start:=(y+Ywin)
     mov ecx,eax
     mov edx,ebx

     imul edx, 640*4          ; (y+Ywin)*BytesPerScanLine
     shl ecx,2                ; (x+Xwin)*BytesPerPixel
     add ecx,edx              ;
     mov ebp,ecx              ; store copy
     add ecx,[0xfe80]         ; +AddrLFB
   ;entry point in LFB >> ECX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+Addr

     shr ebp,5                ; change from 4 to 1/8 BytesPerPixel
     add ebp,0xa0000          ; + VGABasePtr
   ;VGA start address >> EBP:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrV


     call calculate_edi

   sdp3vga:                            ; MAIN LOOP

     cmp [edi+WinMapAddress],byte 1     ; ptrBuffer^<>byte(1)
     je  sybgpvga

     jmp snbgpvga

   sybgpvga:

     push eax   ; x
     push ebx   ; y
     push ecx   ; LFB address

     mov   eax,dword [WinMapAddress-8]  ; B
     xor   edx,edx
     mov   ebx,[esp+8]             ; Xstart
     mul   ebx                     ; B*Xstart
     xor   edx,edx
     mov   ebx,[0xfe00]            ; x screen width
     div   ebx                     ; B*Xstart/xwidth
     lea   esi,[eax+eax*2]         ; *3
     mov   eax,dword [WinMapAddress-4]  ; H
     xor   edx,edx
     mov   ebx,[esp+4]             ; Ystart
     mul   ebx                     ; H*Ystart
     xor   edx,edx
     mov   ebx,[0xfe04]            ; y screen height
     div   ebx                     ; H*Ystart/yheight

     xor   edx,edx
     mov   ebx,[esp+12]             ; B*3
     mul   ebx                     ;
     add   esi,eax
     mov   eax,[esi+0x300000]      ; color
     and   eax,0xffffff

     mov   ecx, [esp]   ; LFB address
     mov   ebx,eax      ; copy color
     mov   [ecx],bx
     shr   ebx,16
     mov   [ecx+2],bl

     xchg  edi, ebp
     mov   ecx,[esp+8]     ; x position
     and   ecx,0x07        ; x modulo 8
     call  setvgapixel     ; eax=color, ecx=x%8, edi=VGA address
     xchg  ebp, edi        ; ebp+=3

     pop ecx
     pop ebx
     pop eax

   snbgpvga:

     inc eax                       ; x++
     cmp eax,[draw_data+32+8]         ; X > xend?
     jg  snodp3vga

     test eax,0x07                 ; x test modulo 8
     jnz shook1vga
     inc ebp                       ; VGA address++

   shook1vga:
     add ecx,4                     ; LFB address += 4
     inc edi                       ; ptrBuffer++
     add esi,3                     ; ptrImage+=3
     jmp sdp3vga

   snodp3vga:

     mov eax,[draw_data+32+0]         ; x+Xwin
     inc ebx                       ; y position
     mov ecx,eax
     mov edx,ebx

     imul edx, 640*4          ; (y+Ywin)*BytesPerScanLine
     shl ecx,2                ; (x+Xwin)*BytesPerPixel
     add ecx,edx              ;
     mov ebp,ecx              ; store copy
     add ecx,[0xfe80]         ; +AddrLFB
  ;entry point in LFB >> ECX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+Addr


     shr ebp,5                ; change from 4 to 1/8 BytesPerPixel
     add ebp,0xa0000          ; + VGABasePtr
          ;VGA start address >> EBP:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+A


     call calculate_edi

     cmp ebx,[draw_data+32+12]        ; Y > yend
     jg  sdp4vga

     jmp sdp3vga

   sdp4vga:

     add esp,4

     pop edx
     pop ecx
     pop ebx
     pop eax
     pop ebp

     ret


