; Vesa Graphics 3.5 object file
; by Thomas Lack¢, http://togye.host.sk
IDEAL
MODEL LARGE,PASCAL
P486

DATASEG

  struc TRect
    Left   dw ?
    Top    dw ?
    Right  dw ?
    Bottom dw ?
  ends
  struc TFont
    Width       dw ?
    Height      dw ?
    Data        dd ?
    Widths      dd ?
    FirstChar   db ?
    LastChar    db ?
    DefaultChar db ?
  ends
  struc TPtrList
    Count dw ?
    Items dd ?
  ends

  extrn RangeCheck:byte,XorMode:byte,RGB255:byte,VisibleWindow:TRect
  extrn GrMode:byte,VideoMode:word
  extrn RWin:byte,WWin:byte, SegA000,RVideoPage,WVideoPage
  extrn CanvasWidth,CanvasHeight,ScreenWidth,ScreenHeight
  extrn CanvasX,CanvasY,LineSize
  extrn Color, XP,YP
  extrn Font:TFont, Remains, ImageAddr:dword, ImageMode:byte

  extrn GetPixel:dword,GetRed:dword,GetGreen:dword,GetBlue:dword
  extrn PutPixel:dword,PutRed:dword,PutGreen:dword,PutBlue:dword
  extrn HBorders:dword,HLine:dword,VLine:dword,Bar:dword
  extrn GetLine:dword,PutLine:dword,PutTransparentLine:dword
  extrn PutNextPixel:dword, OnModeChange:TPtrList

  extrn GetReady:proc

  Mode320x200 = 13h
  iShowed  = 80h
  iDrawing = 40h

CODESEG

;*********************
;*   GLOBAL MACROS   *
;*********************

macro movAL Dest,Src
  mov  al,[Src]
  mov  [Dest],al
endm

macro movAX Dest,Src
  mov  ax,[Src]
  mov  [Dest],ax
endm

macro movEAX Dest,Src
  mov  eax,[Src]
  mov  [Dest],eax
endm

macro movOffs Dest,Name
  mov  ax,offset Name
  mov  [Dest],eax
endm

macro movAddr Dest,Name
  mov  ax,seg Name
  shl  eax,16
  movOffs Dest,Name
endm

macro inc2 X
  inc  X
  inc  X
endm

macro dec2 X
  dec  X
  dec  X
endm

macro lodsbFS
  db 64h ;fs:
  lodsb
endm

macro lodswFS
  db 64h ;fs:
  lodsw
endm

macro lodsbGS
  db 65h ;gs:
  lodsb
endm

macro InitCoor1 X,Y,Reg
  mov  ax,[Y]
  mov  bx,ax
  shl  ax,8
  shl  bx,6
  add  ax,bx
  add  ax,[X]
  IFNB <Reg>
   xchg Reg,ax
  ELSE
   xchg di,ax
   mov  es,[SegA000]
  ENDIF
endm

macro InitRCoor8 X,Y,Reg
  mov  ax,[Y]
  mov  bx,[X]
  call GetRCoor
  IFNB <Reg>
   xchg Reg,ax
  ELSE
   xchg di,ax
   mov  es,[SegA000]
  ENDIF
endm

macro InitWCoor8 X,Y
  mov  ax,[Y]
  mov  bx,[X]
  call GetWCoor
endm

macro InitRCoor16 X,Y,Reg
  mov  ax,[Y]
  mov  bx,[X]
  shl  bx,1
  call GetRCoor
  IFNB <Reg>
   xchg Reg,ax
  ELSE
   xchg di,ax
   mov  es,[SegA000]
  ENDIF
endm

macro InitWCoor16 X,Y
  mov  ax,[Y]
  mov  bx,[X]
  shl  bx,1
  call GetWCoor
endm

macro CheckRange CheckProc,Lab
  cmp  [RangeCheck],0
  je   @@norangecheck
  call near CheckProc
  IFNB <Lab>
   jc   Lab
  ELSE
   jc   @@exit
  ENDIF
@@norangecheck:
endm

macro jxor Lab
  cmp  [XorMode],0
  IFNB <Lab>
   jne  Lab
  ELSE
   jne  @@xor
  ENDIF
endm

macro jnxor Lab
  cmp  [XorMode],0
  je   Lab
endm

macro VesaError Lab
  cmp  al,4Fh
  jne  Lab
  cmp  ah,1
  je   Lab
endm

macro IncWPageOnCarry Lab
  jnc  Lab
  call IncWVideoPage
endm

macro IncWPageOnZero Lab
  jnz  Lab
  call IncWVideoPage
endm

macro IncWPageOnDI0 Lab
  or   di,di
  IncWPageOnZero Lab
endm

;**************************
;*   PRIVATE PROCEDURES   *
;**************************
public SetMode,ResetSize

proc GetRCoor near ; AX ® y, BX ® x, AX ¯ screen offset
  imul [LineSize]
  add  ax,bx
  adc  dx,0
  cmp  [RVideoPage],dx
  je   @@nopgch
  push ax
  call far SetRVideoPage
  pop  ax
@@nopgch:
  ret
endp

proc GetWCoor near ; AX ® y, BX ® x, ES:DI ¯ screen
  imul [LineSize]
  add  ax,bx
  adc  dx,0
  xchg di,ax
  cmp  [WVideoPage],dx
  je   @@nopgch
  call far SetWVideoPage
@@nopgch:
  mov  es,[SegA000]
  ret
endp

Empty2:  retf 2
Empty4:  retf 4
Empty6:  retf 6
Empty8:  retf 8
Empty10: retf 10
Empty12: retf 12

proc SetMode near Mode:byte
  movAL GrMode,Mode
  cmp  al,1
  jne  @@check8
  ; VGA mode
  movAddr GetPixel,GetPixel1
  movOffs GetRed,  GetPixel1
  movOffs GetGreen,GetPixel1
  movOffs GetBlue, GetPixel1
  movOffs PutPixel,PutPixel1
  movOffs PutRed,  PutPixel1
  movOffs PutGreen,PutPixel1
  movOffs PutBlue, PutPixel1
  movOffs HBorders,HBorders1
  movOffs HLine,HLine1
  movOffs VLine,VLine1
  movOffs Bar,Bar1
  movOffs GetLine,GetLine1
  movOffs PutLine,PutLine1
  movOffs PutTransparentLine,PutTransparentLine1
  ret
@@check8:
  cmp  al,8
  jne  @@check16
  ; 8-bit
  movAddr GetPixel,GetPixel8
  movOffs GetRed,  GetPixel8
  movOffs GetGreen,GetPixel8
  movOffs GetBlue, GetPixel8
  movOffs PutPixel,PutPixel8
  movOffs PutRed,  PutPixel8
  movOffs PutGreen,PutPixel8
  movOffs PutBlue, PutPixel8
  movOffs HBorders,HBorders8
  movOffs HLine,HLine8
  movOffs VLine,VLine8
  movOffs Bar,Bar8
  movOffs GetLine,GetLine8
  movOffs PutLine,PutLine8
  movOffs PutTransparentLine,PutTransparentLine8
  ret
@@check16:
  cmp  al,16
  jne  @@none
  ; 16-bit
  movAddr GetPixel,GetPixel16
  movOffs GetRed,  GetPixel16
  movOffs GetGreen,GetPixel16
  movOffs GetBlue, GetPixel16
  movOffs PutPixel,PutPixel16
  movOffs PutRed,  PutPixel16
  movOffs PutGreen,PutPixel16
  movOffs PutBlue, PutPixel16
  movOffs HBorders,HBorders16
  movOffs HLine,HLine16
  movOffs VLine,VLine16
  movOffs Bar,Bar16
  movOffs GetLine,GetLine16
  movOffs PutLine,PutLine16
  movOffs PutTransparentLine,PutTransparentLine16
  ret
@@none: ; no mode
  movAddr GetPixel,Empty4
  mov  [GetRed],  eax
  mov  [GetGreen],eax
  mov  [GetBlue], eax
  movOffs PutPixel,Empty6
  mov  [PutRed],  eax
  mov  [PutGreen],eax
  mov  [PutBlue], eax
  movOffs HBorders,Empty8
  mov  [HLine],eax
  mov  [VLine],eax
  movOffs Bar,Empty10
  mov  [GetLine],eax
  mov  [PutLine],eax
  movOffs PutTransparentLine,Empty12
  ret
endp

proc ResetSize near
  xor  ax,ax
  mov  [CanvasWidth],ax
  mov  [CanvasHeight],ax
  mov  [CanvasX],ax
  mov  [CanvasY],ax
  mov  [LineSize],ax
  mov  [ScreenWidth],ax
  mov  [ScreenHeight],ax
  ret
endp

;******************
;*   VIDEO PAGE   *
;******************
public SetRVideoPage,IncRVideoPage,DecRVideoPage
public SetWVideoPage,IncWVideoPage,DecWVideoPage

proc GetRVideoPage near ; DX ¯ page
  mov  ax,4F05h
  mov  bl,[RWin]
  mov  bh,1
  int  10h
  ret
endp

proc SetRVideoPage ; DX ® page
  cmp  [GrMode],1
  je   @@exit
  mov  bl,[RWin]
  cmp  bl,[WWin]
  jne  @@just
  mov  [WVideoPage],dx
@@just:
  mov  [RVideoPage],dx
  mov  ax,4F05h
  xor  bh,bh
  int  10h
@@exit:
  ret
endp

proc IncRVideoPage ; (registers are saved)
uses ax,bx,dx
  cmp  [GrMode],1
  je   @@exit
  inc  [RVideoPage]
  mov  bl,[RWin]
  cmp  bl,[WWin]
  jne  @@just
  inc  [WVideoPage]
@@just:
  mov  ax,4F05h
  xor  bh,bh
  mov  dx,[RVideoPage]
  int  10h
@@exit:
  ret
endp

proc DecRVideoPage ; (registers are saved)
uses ax,bx,dx
  cmp  [GrMode],1
  je   @@exit
  dec  [RVideoPage]
  mov  bl,[RWin]
  cmp  bl,[WWin]
  jne  @@just
  dec  [WVideoPage]
@@just:
  mov  ax,4F05h
  xor  bh,bh
  mov  dx,[RVideoPage]
  int  10h
@@exit:
  ret
endp

proc GetWVideoPage near ; DX ¯ page
  mov  ax,4F05h
  mov  bl,[WWin]
  mov  bh,1
  int  10h
  ret
endp

proc SetWVideoPage ; DX ® page
  cmp  [GrMode],1
  je   @@exit
  mov  bl,[WWin]
  cmp  bl,[RWin]
  jne  @@just
  mov  [RVideoPage],dx
@@just:
  mov  [WVideoPage],dx
  mov  ax,4F05h
  xor  bh,bh
  int  10h
@@exit:
  ret
endp

proc IncWVideoPage ; (registers are saved)
uses ax,bx,dx
  cmp  [GrMode],1
  je   @@exit
  inc  [WVideoPage]
  mov  bl,[WWin]
  cmp  bl,[RWin]
  jne  @@just
  inc  [RVideoPage]
@@just:
  mov  ax,4F05h
  xor  bh,bh
  mov  dx,[WVideoPage]
  int  10h
@@exit:
  ret
endp

proc DecWVideoPage ; (registers are saved)
uses ax,bx,dx
  cmp  [GrMode],1
  je   @@exit
  dec  [WVideoPage]
  mov  bl,[WWin]
  cmp  bl,[RWin]
  jne  @@just
  dec  [RVideoPage]
@@just:
  mov  ax,4F05h
  xor  bh,bh
  mov  dx,[WVideoPage]
  int  10h
@@exit:
  ret
endp

;**************************
;*   VESA MODE HANDLING   *
;**************************
public SetMaxVisibleWindow,GetModeInfo
public InitGraph,GetVideoMode,CloseGraph

struc TModeInfo
  Mode      dw ?
  WinA      db ?
  WinB      db ?
  WinK      dw ?
  WinSize   dw ?
  SegA      dw ?
  SegB      dw ?
  WinFunc   dd ?
  LineSize  dw ?
  Width     dw ?
  Height    dw ?
  xWidth    db ?
  xHeight   db ?
  Planes    db ?
  PixelSize db ?
  Filler    db (256-26) dup (?)
ends

proc GetModeInfo Mode:word,I:dword ; function:Boolean
  mov  ax,4F01h
  mov  cx,[Mode]
  les  di,[I]
  int  10h
  VesaError @@fail
  mov  al,1 ;True
  ret
@@fail:
  mov  al,0 ;False
  ret
endp

proc SetMaxVisibleWindow
  xor  ax,ax
  mov  [VisibleWindow.Left],ax
  mov  [VisibleWindow.Top],ax
  mov  ax,[CanvasWidth]
  dec  ax
  mov  [VisibleWindow.Right],ax
  mov  ax,[CanvasHeight]
  dec  ax
  mov  [VisibleWindow.Bottom],ax
  ret
endp

proc GetSetModeProperties near ; AX ® mode, CF ¯ error
local Buf:TModeInfo
  mov  [VideoMode],ax
  cmp  ax,Mode320x200
  jne  @@svga
  ; VGA mode
  mov  [WWin],al
  mov  [RWin],al
  mov  [LineSize],320
  mov  [ScreenWidth],320
  mov  [ScreenHeight],200
  push 1
  call SetMode
  clc
  ret
@@svga: ; Vesa mode
  ; get mode information
  lea  si,[Buf]
  push ax ss si
  call GetModeInfo
  or   al,al
  jz   @@fail
  test [Buf.Mode],1
  jz   @@fail
  ; screen properties
  movAX ScreenWidth,Buf.Width
  movAX ScreenHeight,Buf.Height
  movAX LineSize,Buf.LineSize
  ; determine RWin
  test [Buf.WinA],3
  jz   @@rwinb
  mov  [RWin],0
  jmp  short @@rwingot
@@fail:
  stc
  ret
@@rwinb:
  test [Buf.WinB],3
  jz   @@fail
  mov  [RWin],1
@@rwingot: ; determine WWin
  test [Buf.WinA],5
  jz   @@wwinb
  mov  [WWin],0
  jmp  short @@wwingot
@@wwinb:
  test [Buf.WinB],5
  jz   @@fail
  mov  [WWin],1
@@wwingot: ; colour depth
  cmp  [Buf.PixelSize],8
  je   @@mode8
  cmp  [Buf.PixelSize],16
  jne  @@fail
  push 16
  jmp  short @@setmode
@@mode8:
  push 8
@@setmode:
  call SetMode
  clc
  ret
endp

proc InitGraph Mode ; function:Boolean
  xor  si,si ;False
  mov  [XP],si
  mov  [YP],si
  mov  ax,[Mode]
  call GetSetModeProperties
  jc   @@fail
  movAX CanvasWidth,ScreenWidth
  movAX CanvasHeight,ScreenHeight
  call SetMaxVisibleWindow
  xor  ax,ax
  mov  [CanvasX],ax
  mov  [CanvasY],ax
  mov  [RVideoPage],ax
  mov  [WVideoPage],ax
  cmp  [Mode],Mode320x200
  jne  @@svga
  ; VGA mode
  mov  ax,13h
  int  10h
  mov  al,1 ;True
  jmp  short @@done
@@fail:
  mov  al,0 ;False
  jmp  short @@done
@@svga: ; Vesa mode
  mov  ax,4F02h
  mov  bx,[Mode]
  int  10h
  VesaError @@fail
  mov  al,1 ;True
@@done:
  mov  cx,[OnModeChange.Count]
  jcxz @@skip
  les  di,[OnModeChange.Items]
@@nexthandler:
  push ax cx es di
  push ax
  call [dword ptr es:di]
  pop  di es cx ax
  add  di,4
  loop @@nexthandler
@@skip:
  ret
endp

proc GetVideoMode ; function:Boolean
  mov  ax,4F03h
  int  10h
  VesaError @@fail
  cmp  bx,100h
  jae  @@cont
  cmp  bx,Mode320x200
  jbe  @@cont
  add  bx,98h
@@cont:
  xchg ax,bx
  call GetSetModeProperties
  jc   @@fail
  ; canvas
  mov  ax,4F06h
  mov  bl,1
  int  10h
  VesaError @@nocanvas
  mov  [LineSize],bx
  mov  [CanvasWidth],cx
  mov  [CanvasHeight],dx
  mov  ax,4F07h
  mov  bx,1
  int  10h
  mov  [CanvasX],cx
  mov  [CanvasY],dx
  jmp  short @@canvasok
@@fail:
  push 0
  call SetMode
  mov  al,0 ;False
  ret
@@nocanvas:
  movAX CanvasWidth,ScreenWidth
  cmp  [GrMode],16
  jne  @@notshl
  shl  ax,1
@@notshl:
  mov  [LineSize],ax
  movAX CanvasHeight,ScreenHeight
  xor  ax,ax
  mov  [CanvasX],ax
  mov  [CanvasY],ax
@@canvasok: ; video pages
  call GetRVideoPage
  mov  [RVideoPage],dx
  call GetWVideoPage
  mov  [WVideoPage],dx
  mov  al,1 ;True
  ret
endp

proc CloseGraph
  mov  ax,3
  int  10h
  mov  ax,1003h
  mov  bl,0
  int  10h
  push 0
  call SetMode
  call ResetSize
  mov  [VideoMode],0
  ret
endp

;***********************************
;*   HORIZONTAL & VERTICAL LINES   *
;***********************************

proc HBorders1 far X1,X2,Y
  cmp  [RangeCheck],0
  je   @@norch
  push [X1] [Y] [Color]
  call far PutPixel1
  push [dword ptr Y] [Color]
  call far PutPixel1
  ret
@@norch:
  InitCoor1 X1,Y
  mov  al,[byte ptr Color]
  jxor
  stosb
  add  di,[X2]
  sub  di,[X1]
  dec  di
  stosb
  ret
@@xor: ; XOR MODE
  xor  [es:di],al
  add  di,[X2]
  sub  di,[X1]
  xor  [es:di],al
  ret
endp

proc HBorders8 far X1,X2,Y
  cmp  [RangeCheck],0
  je   @@norch
  push [X1] [Y] [Color]
  call far PutPixel8
  push [dword ptr Y] [Color]
  call far PutPixel8
  ret
@@norch:
  InitWCoor8 X1,Y
  mov  al,[byte ptr Color]
  jxor
  stosb
  IncWPageOnDI0 @@jump
@@jump:
  mov  cx,[X2]
  sub  cx,[X1]
  dec  cx
  add  di,cx
  IncWPageOnCarry @@pixel2
@@pixel2:
  stosb
  ret
@@xor: ; XOR MODE
  xor  [es:di],al
  mov  cx,[X2]
  sub  cx,[X1]
  add  di,cx
  IncWPageOnCarry @@xpixel2
@@xpixel2:
  xor  [es:di],al
  ret
endp

proc HBorders16 far X1,X2,Y
  cmp  [RangeCheck],0
  je   @@norch
  push [X1] [Y] [Color]
  call far PutPixel16
  push [dword ptr Y] [Color]
  call far PutPixel16
  ret
@@norch:
  InitWCoor16 X1,Y
  mov  ax,[Color]
  jxor
  stosw
  IncWPageOnDI0 @@jump
@@jump:
  mov  cx,[X2]
  sub  cx,[X1]
  dec  cx
  shl  cx,1
  add  di,cx
  IncWPageOnCarry @@pixel2
@@pixel2:
  stosw
  ret
@@xor: ; XOR MODE
  xor  [es:di],ax
  mov  cx,[X2]
  sub  cx,[X1]
  shl  cx,1
  add  di,cx
  IncWPageOnCarry @@xpixel2
@@xpixel2:
  xor  [es:di],ax
  ret
endp

proc HLine1 far X1,X2,Y
  CheckRange HLineRangeCheck
  InitCoor1 X1,Y
  mov  cx,[X2]
  sub  cx,[X1]
  inc  cx
  mov  al,[byte ptr Color]
  jxor
  cmp  cx,32
  jae  @@fast
  ; line too short
  rep  stosb
  ret
@@fast: ; fast method
  mov  ah,al
@@nextpre: ; first 0..3 bytes
  test di,3
  jz   @@predone
  stosb
  dec  cx
  jmp  short @@nextpre
@@predone:
  ; middle
  push cx
  shr  cx,2
  mov  bx,ax
  shl  eax,16
  mov  ax,bx
  rep  stosd
  ; last 0..3 bytes
  pop  cx
  and  cx,3
  rep  stosb
@@exit:
  ret
@@xor: ; XOR MODE
  cmp  cx,32
  jae  @@xfast
  ; line too short
@@nextbyte:
  xor  [es:di],al
  inc  di
  loop @@nextbyte
  ret
@@xfast: ; fast method
  mov  ah,al
@@xnextpre: ; first 0..3 bytes
  test di,3
  jz   @@xpredone
  xor  [es:di],al
  inc  di
  dec  cx
  jmp  short @@xnextpre
@@xpredone:
  ; middle
  push cx
  shr  cx,2
  mov  bx,ax
  shl  eax,16
  mov  ax,bx
@@nextdword:
  xor  [es:di],eax
  add  di,4
  loop @@nextdword
  ; last 0..3 bytes
  pop  cx
  and  cx,3
  jz   @@exit
@@nextsuf:
  xor  [es:di],al
  inc  di
  loop @@nextsuf
  ret
endp

proc HLine8 far X1,X2,Y
  CheckRange HLineRangeCheck
  InitWCoor8 X1,Y
  mov  cx,[X2]
  sub  cx,[X1]
  inc  cx
  mov  al,[byte ptr Color]
  jxor
  cmp  cx,32
  jae  @@fast
@@slow: ; line too short
  stosb
  IncWPageOnDI0 @@loopslow
@@loopslow:
  loop @@slow
  ret
@@fast: ; fast method
  mov  ah,al
@@nextpre: ; first 0..3 pixels
  test di,3
  jz   @@dbound
  stosb
  dec  cx
  IncWPageOnDI0 @@nextpre
  jmp  short @@nextpre
@@dbound: ; middle (before page break)
  mov  bx,ax
  shl  eax,16
  mov  ax,bx
  mov  dx,di
  neg  dx
  jz   @@putend
  cmp  cx,dx
  jbe  @@putend
  xchg cx,dx
  sub  dx,cx
  shr  cx,2
  rep  stosd
  call IncWVideoPage
  mov  cx,dx
@@putend: ; middle (whole/remaining)
  push cx
  shr  cx,2
  rep  stosd
  pop  cx
  and  cx,3
  jz   @@exit
@@nextsuf: ; last 0..3 pixels
  IncWPageOnDI0 @@putsuf
@@putsuf:
  stosb
  loop @@nextsuf
@@exit:
  ret
@@xor: ; XOR MODE
  cmp  cx,32
  jae  @@xfast
  ; line too short
@@nextbyte:
  xor  [es:di],al
  inc  di
  IncWPageOnZero @@loopbyte
@@loopbyte:
  loop @@nextbyte
  ret
@@xfast: ; fast method
  mov  ah,al
@@xnextpre: ; first 0..3 pixels
  test di,3
  jz   @@xdbound
  xor  [es:di],al
  inc  di
  IncWPageOnZero @@looppre
@@looppre:
  dec  cx
  jmp  short @@xnextpre
@@xdbound: ; middle
  mov  bx,ax
  shl  eax,16
  mov  ax,bx
  push cx
  shr  cx,2
@@nextdword:
  xor  [es:di],eax
  add  di,4
  IncWPageOnCarry @@loopdword
@@loopdword:
  loop @@nextdword
  pop  cx
  and  cx,3
  jz   @@exit
@@xnextsuf: ; last 0..3 pixels
  xor  [es:di],al
  inc  di
  IncWPageOnZero @@loopsuf
@@loopsuf:
  loop @@xnextsuf
  ret
endp

proc HLine16 far X1,X2,Y
  CheckRange HLineRangeCheck
  InitWCoor16 X1,Y
  mov  cx,[X2]
  sub  cx,[X1]
  inc  cx
  mov  ax,[Color]
  jxor
  cmp  cx,32
  jae  @@fast
@@slow: ; line too short
  stosw
  IncWPageOnDI0 @@loopslow
@@loopslow:
  loop @@slow
  ret
@@fast: ; fast method
  ; first 0/1 pixel
  test di,2
  jz   @@dbound
  stosw
  dec  cx
  IncWPageOnDI0 @@dbound
@@dbound: ; middle (before page break)
  mov  bx,ax
  shl  eax,16
  mov  ax,bx
  mov  dx,di
  neg  dx
  jz   @@putend
  shr  dx,1
  cmp  cx,dx
  jbe  @@putend
  xchg cx,dx
  sub  dx,cx
  shr  cx,1
  rep  stosd
  call IncWVideoPage
  mov  cx,dx
@@putend: ; middle (whole/remaining)
  shr  cx,1
  rep  stosd
  jnc  @@exit
  ; last 0/1 pixel
  IncWPageOnDI0 @@putlast
@@putlast:
  stosw
@@exit:
  ret
@@xor: ; XOR MODE
  cmp  cx,32
  jae  @@xfast
@@nextbyte: ; line too short
  xor  [es:di],ax
  inc2 di
  IncWPageOnZero @@loopslow
@@loopbyte:
  loop @@nextbyte
  ret
@@xfast: ; fast method
  ; first 0/1 pixel
  test di,2
  jz   @@xdbound
  xor  [es:di],ax
  dec  cx
  inc2 di
  IncWPageOnZero @@xdbound
@@xdbound: ; middle
  mov  bx,ax
  shl  eax,16
  mov  ax,bx
  shr  cx,1
  pushf
@@nextmiddle:
  xor  [es:di],eax
  add  di,4
  IncWPageOnCarry @@loopmiddle
@@loopmiddle:
  loop @@nextmiddle
  popf
  jnc  @@exit
  ; last 0/1 pixel
  xor  [es:di],ax
  ret
endp

proc HLineRangeCheck near ; parameters: HLine
  ; vertically
  mov  ax,[Y]
  cmp  ax,[VisibleWindow.Top]
  jl   @@out
  cmp  ax,[VisibleWindow.Bottom]
  jg   @@out
  ; horizontally
  mov  cx,[VisibleWindow.Left]
  mov  dx,[VisibleWindow.Right]
  mov  ax,[X1]
  mov  bx,[X2]
  cmp  ax,bx
  jle  @@x1
  mov  [X2],ax
  xchg ax,bx
  mov  [X1],ax
@@x1:
  cmp  ax,dx
  jg   @@out
  cmp  ax,cx
  jge  @@x2
  mov  [X1],cx
@@x2:
  cmp  bx,cx
  jl   @@out
  cmp  bx,dx
  jle  @@ok
  mov  [X2],dx
@@ok:
  clc
  ret
@@out:
  stc
  ret
endp

proc VLine1 far X,Y1,Y2
  CheckRange VLineRangeCheck
  InitCoor1 X,Y1
  mov  al,[byte ptr Color]
  mov  cx,[Y2]
  sub  cx,[Y1]
  jc   @@exit
  inc  cx
  jxor
@@nextpixel:
  mov  [es:di],al
  add  di,[LineSize]
  loop @@nextpixel
@@exit:
  ret
@@xor: ; XOR MODE
  xor  [es:di],al
  add  di,[LineSize]
  loop @@xor
  ret
endp

proc VLine8 far X,Y1,Y2
  CheckRange VLineRangeCheck
  InitWCoor8 X,Y1
  mov  al,[byte ptr Color]
  mov  bx,[LineSize]
  mov  cx,[Y2]
  sub  cx,[Y1]
  jc   @@exit
  inc  cx
  jxor
@@nextpixel:
  mov  [es:di],al
  add  di,bx
  IncWPageOnCarry @@loop
@@loop:
  loop @@nextpixel
@@exit:
  ret
@@xor: ; XOR MODE
  xor  [es:di],al
  add  di,bx
  IncWPageOnCarry @@xloop
@@xloop:
  loop @@xor
  ret
endp

proc VLine16 far X,Y1,Y2
  CheckRange VLineRangeCheck
  InitWCoor16 X,Y1
  mov  ax,[Color]
  mov  bx,[LineSize]
  mov  cx,[Y2]
  sub  cx,[Y1]
  jc   @@exit
  inc  cx
  jxor
@@nextpixel:
  mov  [es:di],ax
  add  di,bx
  IncWPageOnCarry @@loop
@@loop:
  loop @@nextpixel
@@exit:
  ret
@@xor: ; XOR MODE
  xor  [es:di],ax
  add  di,bx
  IncWPageOnCarry @@xloop
@@xloop:
  loop @@xor
  ret
endp

proc VLineRangeCheck near ; parameters: VLine
  ; horizontally
  mov  ax,[X]
  cmp  ax,[VisibleWindow.Left]
  jl   @@out
  cmp  ax,[VisibleWindow.Right]
  jg   @@out
  ; vertically
  mov  cx,[VisibleWindow.Top]
  mov  dx,[VisibleWindow.Bottom]
  mov  ax,[Y1]
  mov  bx,[Y2]
  cmp  ax,bx
  jle  @@y1
  mov  [Y2],ax
  xchg ax,bx
  mov  [Y1],ax
@@y1:
  cmp  ax,dx
  jg   @@out
  cmp  ax,cx
  jge  @@y2
  mov  [Y1],cx
@@y2:
  cmp  bx,cx
  jl   @@out
  cmp  bx,dx
  jle  @@ok
  mov  [Y2],dx
@@ok:
  clc
  ret
@@out:
  stc
  ret
endp

;***************************
;*   GETPIXEL / PUTPIXEL   *
;***************************

proc GetPixel1 far X,Y ; function:Word
  InitCoor1 X,Y
  movzx ax,[es:di]
  ret
endp

proc GetPixel8 far X,Y ; function:Word
  InitRCoor8 X,Y
  movzx ax,[es:di]
  ret
endp

proc GetPixel16 far X,Y ; function:Word
  InitRCoor16 X,Y
  mov  ax,[es:di]
  ret
endp

proc GetRed16 far X,Y ; function:Word
  InitRCoor16 X,Y
  mov  ax,[es:di]
  cmp  [RGB255],0
  jne  @@255
  shr  ax,10
  and  ax,3Eh
  ret
@@255:
  shr  ax,8
  and  ax,0F8h
  or   ax,3
  ret
endp

proc GetGreen16 far X,Y ; function:Word
  InitRCoor16 X,Y
  mov  ax,[es:di]
  cmp  [RGB255],0
  jne  @@255
  shr  ax,5
  and  ax,3Fh
  ret
@@255:
  shr  ax,2
  and  ax,0FCh
  or   ax,3
  ret
endp

proc GetBlue16 far X,Y ; function:Word
  InitRCoor16 X,Y
  mov  ax,[es:di]
  cmp  [RGB255],0
  jne  @@255
  shl  ax,1
  and  ax,3Eh
  ret
@@255:
  shl  ax,3
  and  ax,0F8h
  or   ax,3
  ret
endp

proc PutPixel1 far X,Y,C
  CheckRange PixelRangeCheck,@exit
  InitCoor1 X,Y
  jmp  short @do
proc PutPixel8 far X,Y,C
  CheckRange PixelRangeCheck,@exit
  InitWCoor8 X,Y
@do:
  mov  al,[byte ptr C]
  jxor
  stosb
@exit:
  ret
@@xor: ; XOR MODE
  xor  [es:di],al
  ret
endp
endp

proc PutPixel16 far X,Y,C
  CheckRange PixelRangeCheck
  InitWCoor16 X,Y
  mov  ax,[C]
  jxor
  stosw
@@exit:
  ret
@@xor: ; XOR MODE
  xor  [es:di],ax
  ret
endp

proc PutRed16 far X,Y,C
  CheckRange PixelRangeCheck
  InitWCoor16 X,Y
  mov  ax,[C]
  cmp  [RGB255],0
  jne  @@255
  and  ax,3Eh
  shl  ax,10
  jxor
  jmp  short @@go
@@255:
  and  ax,0F8h
  shl  ax,8
  jxor
@@go:
  and  [word ptr es:di],07FFh
  or   [es:di],ax
@@exit:
  ret
@@xor:
  xor  [es:di],ax
  ret
endp

proc PutGreen16 far X,Y,C
  CheckRange PixelRangeCheck
  InitWCoor16 X,Y
  mov  ax,[C]
  cmp  [RGB255],0
  jne  @@255
  and  ax,3Fh
  shl  ax,5
  jxor
  jmp  short @@go
@@255:
  and  ax,0FCh
  shl  ax,3
  jxor
@@go:
  and  [word ptr es:di],0F81Fh
  or   [es:di],ax
@@exit:
  ret
@@xor:
  xor  [es:di],ax
  ret
endp

proc PutBlue16 far X,Y,C
  CheckRange PixelRangeCheck
  InitWCoor16 X,Y
  mov  ax,[C]
  cmp  [RGB255],0
  jne  @@255
  and  ax,3Eh
  shr  ax,1
  jxor
  jmp  short @@go
@@255:
  and  ax,0F8h
  shr  ax,3
  jxor
@@go:
  and  [word ptr es:di],0FFE0h
  or   [es:di],ax
@@exit:
  ret
@@xor:
  xor  [es:di],ax
  ret
endp

proc PixelRangeCheck near ; parameters: PutPixel
  mov  ax,[X]
  cmp  ax,[VisibleWindow.Left]
  jl   @@out
  cmp  ax,[VisibleWindow.Right]
  jg   @@out
  mov  ax,[Y]
  cmp  ax,[VisibleWindow.Top]
  jl   @@out
  cmp  ax,[VisibleWindow.Bottom]
  jg   @@out
  clc
  ret
@@out:
  stc
  ret
endp

;***********************
;*   RECTANGLE / BAR   *
;***********************
public Rectangle,BarRangeCheck

proc Rectangle X1,Y1,X2,Y2
  mov  ax,[X1]
  cmp  ax,[X2]
  jne  @@notvline
  push [dword ptr Y1] [Y2]
  call [VLine]
  ret
@@notvline:
  mov  ax,[Y1]
  cmp  ax,[Y2]
  jne  @@nothline
  push [X1] [X2] [Y1]
  call [HLine]
  ret
@@nothline:
  cmp  [RangeCheck],0
  je   @@norch
  ; range-checking enabled
  mov  ax,[X1]
  cmp  ax,[X2]
  jng  @@notexx
  xchg ax,[X2]
  mov  [X1],ax
@@notexx:
  push ax
  mov  ax,[Y1]
  cmp  ax,[Y2]
  jng  @@notexy
  xchg ax,[Y2]
  mov  [Y1],ax
@@notexy: ; top
  push [X2] ax
  call [HLine]
  ; middle
  mov  ax,[CanvasWidth]
  dec  ax
  mov  ax,[X1]
  mov  bx,[X2]
  cmp  ax,[VisibleWindow.Left]
  jnl  @@x1vis
  cmp  bx,[VisibleWindow.Right]
  jg   @@bottom
  push bx [Y1] [Y2]
  call [VLine]
  jmp  short @@bottom
@@x1vis:
  cmp  bx,[VisibleWindow.Right]
  jng  @@x12vis
  push ax [Y1] [Y2]
  call [VLine]
  jmp  short @@bottom
@@x12vis: ; both sides visible
  mov  [RangeCheck],0 ;False
  mov  ax,[Y1]
  cmp  ax,[VisibleWindow.Top]
  jnl  @@nexty
  mov  ax,[VisibleWindow.Top]
@@nexty:
  inc  [Y1]
  mov  ax,[Y1]
  cmp  ax,[Y2]
  je   @@abottom
  cmp  ax,[VisibleWindow.Bottom]
  jg   @@abottom
  push [X1] [X2] [Y1]
  call [HBorders]
  jmp  short @@nexty
@@abottom:
  mov  [RangeCheck],1 ;True
@@bottom: ; bottom
  push [X1] [dword ptr Y2]
  call [HLine]
  ret
@@norch: ; NO RANGE-CHECKING
  push [X1] [X2] ax
  call [HLine]
  ; middle
  mov  cx,[Y2]
  sub  cx,[Y1]
  dec  cx
  jz   @@bottomline
  mov  bx,[X2]
  sub  bx,[X1]
  mov  dx,[CanvasWidth]
  sub  dx,bx
  jxor
  dec  bx
  dec  dx
  cmp  [GrMode],16
  je   @@mode16
  cmp  [GrMode],8
  je   @@mode8
  ; middle (VGA)
  mov  al,[byte ptr Color]
@@nexty1:
  add  di,dx
  stosb
  add  di,bx
  stosb
  loop @@nexty1
  jmp  short @@bottomline
@@mode8: ; middle (8-bit)
  mov  al,[byte ptr Color]
@@nexty8:
  add  di,dx
  IncWPageOnCarry @@nc8a1
@@nc8a1:
  stosb
  IncWPageOnDI0 @@nc8p1
@@nc8p1:
  add  di,bx
  IncWPageOnCarry @@nc8a2
@@nc8a2:
  stosb
  IncWPageOnDI0 @@nc8p2
@@nc8p2:
  loop @@nexty8
  jmp  short @@bottomline
@@mode16: ; middle (16-bit)
  shl  bx,1
  shl  dx,1
  mov  ax,[Color]
@@nexty16:
  add  di,dx
  IncWPageOnCarry @@nc16a1
@@nc16a1:
  stosw
  IncWPageOnDI0 @@nc16p1
@@nc16p1:
  add  di,bx
  IncWPageOnCarry @@nc16a2
@@nc16a2:
  stosw
  IncWPageOnDI0 @@nc16p2
@@nc16p2:
  loop @@nexty16
@@bottomline: ; bottom
  push [X1] [dword ptr Y2]
  call [HLine]
  ret
@@xor: ; XOR MODE
  cmp  [GrMode],16
  je   @@xmode16
  cmp  [GrMode],8
  je   @@xmode8
  ; middle (VGA)
  mov  al,[byte ptr Color]
  dec  di
@@xnexty1:
  add  di,dx
  xor  [es:di],al
  add  di,bx
  xor  [es:di],al
  loop @@xnexty1
  jmp  short @@bottomline
@@xmode8: ; middle (8-bit)
  mov  al,[byte ptr Color]
  mov  si,dx
  dec  si
  add  di,si
  jmp  short @@firsty8
@@xnexty8:
  add  di,dx
@@firsty8:
  IncWPageOnCarry @@xnc8a1
@@xnc8a1:
  xor  [es:di],al
  add  di,bx
  IncWPageOnCarry @@xnc8a2
@@xnc8a2:
  xor  [es:di],al
  loop @@xnexty8
  jmp  short @@bottomline
@@xmode16: ; middle (16-bit)
  shl  bx,1
  shl  dx,1
  mov  ax,[C]
  mov  si,dx
  dec  si
  add  di,si
  jmp  short @@firsty16
@@xnexty16:
  add  di,dx
@@firsty16:
  IncWPageOnCarry @@xnc16a1
@@xnc16a1:
  xor  [es:di],ax
  add  di,bx
  IncWPageOnCarry @@xnc16a2
@@xnc16a2:
  xor  [es:di],ax
  loop @@xnexty16
  jmp  @@bottomline
endp

proc Bar1 far X1,Y1,X2,Y2
  CheckRange BarRangeCheck
  InitCoor1 X1,Y1
  mov  bx,[X2]
  sub  bx,[X1]
  inc  bx
  mov  cx,[Y2]
  sub  cx,[Y1]
  inc  cx
  mov  al,[byte ptr Color]
  mov  ah,al
  jxor @@xor
@@nextrow:
  push cx
  mov  cx,bx
  test di,1
  jz   @@middle
  dec  cx
  stosb
@@middle:
  shr  cx,1
  rep  stosw
  jnc  @@notlast
  stosb
@@notlast:
  add  di,[LineSize]
  sub  di,bx
  pop  cx
  loop @@nextrow
@@exit:
  ret
@@xor: ; XOR MODE
  push cx
  mov  cx,bx
  shr  cx,1
  pushf
@@nextbyte:
  xor  [es:di],ax
  inc2 di
  loop @@nextbyte
  popf
  jnc  @@xnotlast
  xor  [es:di],al
  inc  di
@@xnotlast:
  add  di,[LineSize]
  sub  di,bx
  pop  cx
  loop @@xor
  ret
endp

proc Bar8 far X1,Y1,X2,Y2
  CheckRange BarRangeCheck
  InitWCoor8 X1,Y1
  mov  bx,[X2]
  sub  bx,[X1]
  inc  bx
  mov  dx,[LineSize]
  sub  dx,bx
  mov  cx,[Y2]
  sub  cx,[Y1]
  inc  cx
  mov  al,[byte ptr Color]
  mov  ah,al
  jxor
@@nextrow:
  push cx
  mov  cx,bx
  ; first 0/1 pixel
  test di,1
  jz   @@middle
  stosb
  dec  cx
  jz   @@exit
  IncWPageOnDI0 @@middle
@@middle: ; middle
  shr  cx,1
  jz   @@lastpixel
  pushf
@@nextpixel:
  stosw
  IncWPageOnDI0 @@looppixel
@@looppixel:
  loop @@nextpixel
  popf
@@lastpixel:
  jnc  @@endrow
  ; last 0/1 pixel
  stosb
  IncWPageOnDI0 @@endrow
@@endrow:
  add  di,dx
  IncWPageOnCarry @@rowloop
@@rowloop:
  pop  cx
  loop @@nextrow
@@exit:
  ret
@@xor: ; XOR MODE
  push cx
  mov  cx,bx
  ; first 0/1 pixel
  test di,1
  jz   @@xmiddle
  xor  [es:di],al
  dec  cx
  jz   @@exit
  inc  di
  IncWPageOnZero @@xmiddle
@@xmiddle: ; middle
  shr  cx,1
  jz   @@xlastpixel
  pushf
@@xnextpixel:
  xor  [es:di],ax
  inc2 di
  IncWPageOnZero @@xlooppixel
@@xlooppixel:
  loop @@xnextpixel
  popf
@@xlastpixel:
  jnc  @@xendrow
  ; last 0/1 pixel
  xor  [es:di],al
  inc  di
  IncWPageOnZero @@xendrow
@@xendrow:
  add  di,dx
  IncWPageOnCarry @@xrowloop
@@xrowloop:
  pop  cx
  loop @@xor
  ret
endp

proc Bar16 far X1,Y1,X2,Y2
  CheckRange BarRangeCheck
  InitWCoor16 X1,Y1
  mov  bx,[X2]
  sub  bx,[X1]
  inc  bx
  mov  dx,[LineSize]
  sub  dx,bx
  sub  dx,bx
  mov  cx,[Y2]
  sub  cx,[Y1]
  inc  cx
  mov  ax,[Color]
  shl  eax,16
  mov  ax,[Color]
  jxor
@@nextrow:
  push cx
  mov  cx,bx
  ; first 0/1 pixel
  test di,2
  jz   @@middle
  stosw
  dec  cx
  jz   @@exit
  IncWPageOnDI0 @@middle
@@middle: ; middle
  shr  cx,1
  jz   @@lastpixel
  pushf
@@nextpixel:
  stosd
  IncWPageOnDI0 @@looppixel
@@looppixel:
  loop @@nextpixel
  popf
@@lastpixel:
  jnc  @@endrow
  ; last 0/1 pixel
  stosw
  IncWPageOnDI0 @@endrow
@@endrow:
  add  di,dx
  IncWPageOnCarry @@rowloop
@@rowloop:
  pop  cx
  loop @@nextrow
@@exit:
  ret
@@xor: ; XOR MODE
  push cx
  mov  cx,bx
  ; first 0/1 pixel
  test di,2
  jz   @@xmiddle
  xor  [es:di],ax
  dec  cx
  jz   @@exit
  inc2 di
  IncWPageOnZero @@xmiddle
@@xmiddle: ; middle
  shr  cx,1
  jz   @@xlastpixel
  pushf
@@xnextpixel:
  xor  [es:di],eax
  add  di,4
  IncWPageOnCarry @@xlooppixel
@@xlooppixel:
  loop @@xnextpixel
  popf
@@xlastpixel:
  jnc  @@xendrow
  ; last 0/1 pixel
  xor  [es:di],ax
  inc2 di
  IncWPageOnZero @@xendrow
@@xendrow:
  add  di,dx
  IncWPageOnCarry @@xrowloop
@@xrowloop:
  pop  cx
  loop @@xor
  ret
endp

proc BarRangeCheck near ; parameters: Bar
  ; horizontally
  mov  cx,[VisibleWindow.Left]
  mov  dx,[VisibleWindow.Right]
  mov  ax,[X1]
  mov  bx,[X2]
  cmp  ax,bx
  jle  @@x1
  mov  [X2],ax
  xchg ax,bx
  mov  [X1],ax
@@x1:
  cmp  ax,dx
  jg   @@out
  cmp  ax,cx
  jnl  @@x2
  mov  [X1],cx
@@x2:
  cmp  bx,cx
  jl   @@out
  cmp  bx,dx
  jng  @@vert
  mov  [X2],dx
@@vert: ; vertically
  mov  cx,[VisibleWindow.Top]
  mov  dx,[VisibleWindow.Bottom]
  mov  ax,[Y1]
  mov  bx,[Y2]
  cmp  ax,bx
  jle  @@y1
  mov  [Y2],ax
  xchg ax,bx
  mov  [Y1],ax
@@y1:
  cmp  ax,dx
  jg   @@out
  cmp  ax,cx
  jnl  @@y2
  mov  [Y1],cx
@@y2:
  cmp  bx,cx
  jl   @@out
  cmp  bx,dx
  jng  @@ok
  mov  [Y2],dx
@@ok:
  clc
  ret
@@out:
  stc
  ret
endp

;************
;*   LINE   *
;************
public Line

proc Line X1,Y1,X2,Y2
local X,Y ; X = ³X2-X1³, Y = ³Y2-Y1³
  mov  ax,[X2]
  sub  ax,[X1]
  jz   @@vertical
  jns  @@xpos
  neg  ax
  jmp  short @@xpos
@@vertical:
  push [dword ptr Y1] [Y2]
  call [VLine]
  ret
@@xpos:
  mov  [X],ax
  mov  ax,[Y2]
  sub  ax,[Y1]
  jz   @@horizontal
  jns  @@ypos
  neg  ax
  jmp  short @@ypos
@@horizontal:
  push [X1] [X2] [Y1]
  call [HLine]
  ret
@@ypos:
  mov  [Y],ax
  cmp  [X],ax
  jb   @@vert
  ; X >= Y
  call LineCoordsH
  jc   @@done
  push bx cx dx si
  cmp  [GrMode],16
  jne  @@hlo
  shl  ax,1
@@hlo:
  add  ax,[X1]
  mov  bx,ax
  mov  ax,si
  call GetWCoor
  pop  si dx cx bx
  jmp  short @@hnextpixel
@@hxor8:
  xor  [es:di],al
  jmp  short @@hcount
@@hhi:
  jxor @@hxor16
  mov  [es:di],ax
  jmp  short @@hcount
@@hxor16:
  xor  [es:di],ax
  jmp  short @@hcount
@@hnextpixel:
  mov  ax,[C]
  cmp  [GrMode],16
  sete dh
  je   @@hhi
  jxor @@hxor8
  mov  [es:di],al
@@hcount:
  movsx ax,dh
  inc  ax
  add  bx,[Y]
  cmp  bx,[X]
  jb   @@hincdi
  sub  bx,[X]
  or   dl,dl
  jns  @@hdownwards
  sub  ax,[LineSize]
  dec  si
  cmp  si,[VisibleWindow.Top]
  jl   @@done
  neg  ax
  sub  di,ax
  jnc  @@hloop
  call DecWVideoPage
  jmp  short @@hloop
@@hdownwards:
  add  ax,[LineSize]
  inc  si
  cmp  si,[VisibleWindow.Bottom]
  jg   @@done
@@hincdi:
  add  di,ax
  jc   @@hincwpage
@@hloop:
  loop @@hnextpixel
@@done:
  ret
@@hincwpage:
  call IncWVideoPage
  jmp  short @@hloop
@@vert: ; X < Y
  call LineCoordsV
  jc   @@done
  push bx cx dx si
  cmp  [GrMode],16
  jne  @@vlo
  shl  si,1
@@vlo:
  add  ax,[Y1]
  mov  bx,si
  call GetWCoor
  pop  si dx cx bx
  jmp  short @@vnextpixel
@@vnextpixel:
  mov  ax,[C]
  cmp  [GrMode],16
  sete dh
  je   @@vhi
  jxor @@vxor8
  mov  [es:di],al
@@vcount:
  mov  ax,[LineSize]
  add  bx,[X]
  cmp  bx,[Y]
  jb   @@vincdi
  sub  bx,[Y]
  or   dl,dl
  js   @@vleftwards
  inc  ax
  add  al,dh
  adc  ah,0
  inc  si
  cmp  si,[VisibleWindow.Right]
  jng  @@vincdi
  jmp  short @@done
@@vxor8:
  xor  [es:di],al
  jmp  short @@vcount
@@vhi:
  jxor @@vxor16
  mov  [es:di],ax
  jmp  short @@vcount
@@vxor16:
  xor  [es:di],ax
  jmp  short @@vcount
@@vleftwards:
  dec  ax
  sub  al,dh
  sbb  ah,0
  dec  si
  cmp  si,[VisibleWindow.Left]
  jl   @@done
@@vincdi:
  add  di,ax
  jc   @@vwpage
@@vloop:
  loop @@vnextpixel
  ret
@@vwpage:
  or   ax,ax
  js   @@vwleftwards
  call IncWVideoPage
  jmp  short @@vloop
@@vwleftwards:
  call DecWVideoPage
  jmp  short @@vloop
endp

proc LineCoordsH near ; parameters & locals inherited
; AX ¯ initial relative x, BX ¯ progress, CX ¯ number of pixels
; DX ¯ dir (ñ1), SI ¯ initial y
  mov  ax,[X2]
  cmp  ax,[X1]
  jnl  @@notxchg
  xchg ax,[X1]
  mov  [X2],ax
  mov  ax,[Y1]
  xchg ax,[Y2]
  mov  [Y1],ax
@@notxchg:
  xor  ax,ax
  mov  dx,[X1]
  cmp  dx,[VisibleWindow.Right]
  jg   @@noline
  cmp  dx,[VisibleWindow.Left]
  jnl  @@normleft
  neg  dx
  mov  ax,[VisibleWindow.Left]
  xadd ax,dx
@@normleft:
  mov  cx,[X2]
  cmp  cx,[VisibleWindow.Left]
  jl   @@noline
  cmp  cx,[VisibleWindow.Right]
  jng  @@normright
  mov  cx,[VisibleWindow.Right]
@@normright:
  sub  cx,dx
  inc  cx
  mov  bx,[X]
  shr  bx,1
  inc  bx
  sub  bx,[X]
  neg  bx
  mov  si,[Y1]
  cmp  si,[Y2]
  setl dl
  mov  dh,0
  dec  dx
  or   dl,1
  cmp  si,[VisibleWindow.Top]
  jl   @@nextstart
  cmp  si,[VisibleWindow.Bottom]
  jle  @@startline
@@nextstart:
  add  bx,[Y]
  cmp  bx,[X]
  jb   @@loopstart
  sub  bx,[X]
  add  si,dx
  cmp  si,[VisibleWindow.Top]
  jl   @@loopstart
  cmp  si,[VisibleWindow.Bottom]
  jle  @@startline
@@loopstart:
  inc  ax
  loop @@nextstart
@@noline:
  stc
  ret
@@startline:
  clc
  ret
endp

proc LineCoordsV near ; parameters & locals inherited
; AX ¯ initial relative y, BX ¯ progress, CX ¯ number of pixels
; DX ¯ dir (ñ1), SI ¯ initial x
  mov  ax,[Y2]
  cmp  ax,[Y1]
  jnl  @@notxchg
  xchg ax,[Y1]
  mov  [Y2],ax
  mov  ax,[X1]
  xchg ax,[X2]
  mov  [X1],ax
@@notxchg:
  xor  ax,ax
  mov  dx,[Y1]
  cmp  dx,[VisibleWindow.Bottom]
  jg   @@noline
  cmp  dx,[VisibleWindow.Top]
  jnl  @@normtop
  neg  dx
  mov  ax,[VisibleWindow.Top]
  xadd ax,dx
@@normtop:
  mov  cx,[Y2]
  cmp  cx,[VisibleWindow.Top]
  jl   @@noline
  cmp  cx,[VisibleWindow.Bottom]
  jng  @@normbottom
  mov  cx,[VisibleWindow.Bottom]
@@normbottom:
  sub  cx,dx
  inc  cx
  mov  bx,[Y]
  shr  bx,1
  inc  bx
  sub  bx,[Y]
  neg  bx
  mov  si,[X1]
  cmp  si,[X2]
  setl dl
  mov  dh,0
  dec  dx
  or   dl,1
  cmp  si,[VisibleWindow.Left]
  jl   @@nextstart
  cmp  si,[VisibleWindow.Right]
  jle  @@startline
@@nextstart:
  add  bx,[X]
  cmp  bx,[Y]
  jb   @@loopstart
  sub  bx,[Y]
  add  si,dx
  cmp  si,[VisibleWindow.Left]
  jl   @@loopstart
  cmp  si,[VisibleWindow.Right]
  jle  @@startline
@@loopstart:
  inc  ax
  loop @@nextstart
@@noline:
  stc
  ret
@@startline:
  clc
  ret
endp

;*************
;*   PRINT   *
;*************
public Print,PrintShd

proc Print X,Y,S:dword
local AddDI,PrintLetter:dword
  cmp  [Font.Width],0
  jle  @@exit
  cmp  [Font.Height],0
  jle  @@exit
  lgs  si,[S]
  lodsbGS
  movzx cx,al
  jcxz @@exit
  mov  [word ptr PrintLetter+2],seg Print
  cmp  [RangeCheck],0
  jne  @@rch
  cmp  [GrMode],8
  je   @@mode8
  cmp  [GrMode],16
  je   @@mode16
  mov  [word ptr PrintLetter],offset PrintLetter1
@@nextchar:
  push cx
  mov  bx,[Font.Width]
  mov  cx,[Font.Height]
  lodsbGS
  cmp  al,[Font.FirstChar]
  jb   @@default
  cmp  al,[Font.LastChar]
  ja   @@default
@@printchar:
  push si
  sub  al,[Font.FirstChar]
  movzx dx,al
  push dx ; char index
  mov  ax,[Font.Width]
  add  ax,7
  shr  ax,3
  mul  dx
  mul  cx
  lfs  si,[Font.Data]
  add  si,ax
  call [PrintLetter]
  pop  si ; char index
  shl  si,1
  lfs  bx,[Font.Widths]
  mov  ax,[fs:bx+si]
  pop  si
  add  [X],ax
@@loopchar:
  pop  cx
  loop @@nextchar
@@exit:
  ret
@@rch:
  mov  [word ptr PrintLetter],offset PrintLetterRCh
  jmp  short @@nextchar
@@mode8:
  mov  [word ptr PrintLetter],offset PrintLetter8
  jmp  short @@nextchar
@@mode16:
  mov  [word ptr PrintLetter],offset PrintLetter16
  jmp  short @@nextchar
@@default:
  mov  al,[Font.DefaultChar]
  cmp  al,[Font.FirstChar]
  jb   @@skip
  cmp  al,[Font.LastChar]
  jna  @@printchar
@@skip:
  add  [X],bx
  jmp  short @@loopchar
endp

proc PrintLetterRCh far ; params&locals: Print ; range-checker version
                        ; FS:SI ® @Data[#], CX ® height
  ; AH = bit counter, AL = read data, BX = remaining width,
  ; CX = line counter, DX = y position, DI = x position, FS:SI = @Data[#]
  mov  dx,[Y]
@@nextrow:
  mov  di,[X]
  mov  bx,[Font.Width]
@@nextbyte:
  mov  ah,8
  lodsbFS
@@nextpixel:
  shr  al,1
  jnc  @@skip
  push ax bx cx si di dx [Color]
  call [PutPixel]
  sub  sp,4
  pop  dx di si cx bx ax
@@skip:
  inc  di
  dec  bx
  jz   @@endrow
  dec  ah
  jnz  @@nextpixel
  jmp  short @@nextbyte
@@endrow:
  inc  dx
  loop @@nextrow
  ret
endp

proc PrintLetter1 far ; params&locals: Print
                      ; FS:SI ® @Data[#], BX ® width, CX ® height
  ; AH = bit counter, AL = read data, BX = "Pos", CX = line counter,
  ; DL = pixel, FS:SI = @Data[#], ES:DI = screen
  mov  ax,[LineSize]
  sub  ax,bx
  mov  [AddDI],ax
  InitCoor1 X,Y
  mov  dl,[byte ptr Color]
@@nextrow:
  mov  bx,[Font.Width]
@@nextbyte:
  mov  ah,8
  lodsbFS
@@nextpixel:
  shr  al,1
  jnc  @@skip
  mov  [es:di],dl
@@skip:
  inc  di
  dec  bx
  jz   @@endrow
  dec  ah
  jnz  @@nextpixel
  jmp  short @@nextbyte
@@endrow:
  add  di,[AddDI]
  loop @@nextrow
  ret
endp

proc PrintLetter8 far ; params&locals: Print
                      ; FS:SI ® @Data[#], BX ® width, CX ® height
  ; AH = bit counter, AL = read data, BX = "Pos", CX = line counter,
  ; DL = pixel, FS:SI = @Data[#], ES:DI = screen
  mov  ax,[LineSize]
  sub  ax,bx
  mov  [AddDI],ax
  InitWCoor8 X,Y
  mov  dl,[byte ptr Color]
@@nextrow:
  mov  bx,[Font.Width]
@@nextbyte:
  mov  ah,8
  lodsbFS
@@nextpixel:
  shr  al,1
  jnc  @@skip
  mov  [es:di],dl
@@skip:
  inc  di
  IncWPageOnZero @@pixelput
@@pixelput:
  dec  bx
  jz   @@endrow
  dec  ah
  jnz  @@nextpixel
  jmp  short @@nextbyte
@@endrow:
  add  di,[AddDI]
  IncWPageOnCarry @@looprow
@@looprow:
  loop @@nextrow
  ret
endp

proc PrintLetter16 far ; params&locals: Print
                       ; FS:SI ® @Data[#], BX ® width, CX ® height
  ; AH = bit counter, AL = read data, BX = "Pos", CX = line counter,
  ; DX = pixel, FS:SI = @Data[#], ES:DI = screen
  mov  ax,[LineSize]
  shl  bx,1
  sub  ax,bx
  mov  [AddDI],ax
  InitWCoor16 X,Y
  mov  dx,[Color]
@@nextrow:
  mov  bx,[Font.Width]
@@nextbyte:
  mov  ah,8
  lodsbFS
@@nextpixel:
  shr  al,1
  jnc  @@skip
  mov  [es:di],dx
@@skip:
  add  di,2
  IncWPageOnZero @@pixelput
@@pixelput:
  dec  bx
  jz   @@endrow
  dec  ah
  jnz  @@nextpixel
  jmp  short @@nextbyte
@@endrow:
  add  di,[AddDI]
  IncWPageOnCarry @@looprow
@@looprow:
  loop @@nextrow
  ret
endp

proc PrintShd X,Y,S:dword,C,Sh
local AddDI,BufOffs,Saved:byte,Pos,PrintLetter:dword
  cmp  [Font.Height],0
  jle  @@exit
  mov  ax,[Font.Width]
  or   ax,ax
  jg   @@goodsize
@@exit:
  ret
@@rch:
  mov  [word ptr PrintLetter],offset PrintLetterShdRCh
  jmp  short @@nextchar
@@mode8:
  mov  [word ptr PrintLetter],offset PrintLetterShd8
  jmp  short @@nextchar
@@mode16:
  mov  [word ptr PrintLetter],offset PrintLetterShd16
  jmp  short @@nextchar
@@goodsize:
  sub  sp,ax
  jc   @@exit ; stack overflow
  and  sp,not 3
  cmp  sp,16
  jb   @@exit ; low on stack!
  mov  [BufOffs],sp
  lgs  si,[S]
  lodsbGS
  movzx cx,al
  jcxz @@exit
  mov  [word ptr PrintLetter+2],seg Print
  cmp  [RangeCheck],0
  jne  @@rch
  cmp  [GrMode],8
  je   @@mode8
  cmp  [GrMode],16
  je   @@mode16
  mov  [word ptr PrintLetter],offset PrintLetterShd1
@@nextchar:
  push cx
  mov  bx,[Font.Width]
  mov  cx,[Font.Height]
  lodsbGS
  cmp  al,[Font.FirstChar]
  jb   @@default
  cmp  al,[Font.LastChar]
  ja   @@default
@@printchar:
  push si
  sub  al,[Font.FirstChar]
  movzx dx,al
  push dx ; char index
  mov  ax,[Font.Width]
  add  ax,7
  shr  ax,3
  mul  dx
  mul  cx
  lfs  si,[Font.Data]
  add  si,ax
  ; clearing buffer
  mov  dx,cx
  mov  cx,bx
  add  cx,3
  shr  cx,2
  mov  di,[BufOffs]
  mov  ax,ss
  mov  es,ax
  xor  eax,eax
  rep  stosd
  mov  cx,dx
  ; printing
  call [PrintLetter]
  pop  si ; char index
  shl  si,1
  lfs  bx,[Font.Widths]
  mov  ax,[fs:bx+si]
  pop  si
  add  [X],ax
@@loopchar:
  pop  cx
  loop @@nextchar
  ret
@@default:
  mov  al,[Font.DefaultChar]
  cmp  al,[Font.FirstChar]
  jb   @@skip
  cmp  al,[Font.LastChar]
  jna  @@printchar
@@skip:
  add  [X],bx
  jmp  short @@loopchar
endp

proc PrintLetterShdRCh far ; params&locals: PrintShd ; range-checker version
                           ; FS:SI ® @Data[#], BX ® width, CX ® height
  ; AH = bit counter, AL = read data, BX = @buffer[pos], CX = line counter,
  ; DX = y position, DI = x position, FS:SI = @Data[#]
  mov  dx,[Y]
@@nextrow:
  mov  di,[X]
  movAX Pos,Font.Width
  mov  bx,[BufOffs]
  mov  [Saved],0
@@nextbyte:
  mov  ah,8
  lodsbFS
@@nextpixel:
  shr  al,1
  jnc  @@checkshd
  push ax bx cx si di dx [C]
  call [PutPixel]
  sub  sp,4
  pop  dx di si cx bx
  mov  al,1
  xchg al,[ss:bx]
  mov  [Saved],al
  pop  ax
  jmp  short @@skip
@@endrow:
  inc  dx
  loop @@nextrow
  ret
@@checkshd:
  cmp  [byte ptr ss:bx],0
  jne  @@shadow
  cmp  [byte ptr ss:bx-1],0
  jne  @@shadow
  cmp  [Saved],0
  je   @@skip
@@shadow:
  push ax bx cx si di dx [Sh]
  call [PutPixel]
  sub  sp,4
  pop  dx di si cx bx
  mov  al,0
  xchg al,[ss:bx]
  mov  [Saved],al
  pop  ax
@@skip:
  inc  di
  inc  bx
  dec  [Pos]
  jz   @@endrow
  dec  ah
  jnz  @@nextpixel
  jmp  short @@nextbyte
endp

proc PrintLetterShd1 far ; params&locals: PrintShd
                         ; FS:SI ® @Data[#], BX ® width, CX ® height
  ; AH = "Saved", AL = pixel/shadow, BX = @buffer[pos], CX = line counter,
  ; DH = bit counter, DL = read data, FS:SI = @Data[#], ES:DI = screen
  mov  ax,[LineSize]
  sub  ax,bx
  mov  [AddDI],ax
  InitCoor1 X,Y
@@nextrow:
  movAX Pos,Font.Width
  mov  bx,[BufOffs]
  mov  ah,0
@@nextbyte:
  mov  dh,8
  mov  dl,[fs:si]
  inc  si
@@nextpixel:
  shr  dl,1
  jnc  @@checkshd
  mov  al,[byte ptr C]
  stosb
  mov  ah,1
  xchg ah,[ss:bx]
  jmp  short @@looppixel
@@checkshd:
  cmp  [byte ptr ss:bx],0
  jne  @@shadow
  cmp  [byte ptr ss:bx-1],0
  jne  @@shadow
  or   ah,ah
  jz   @@skip
@@shadow:
  mov  al,[byte ptr Sh]
  stosb
  mov  ah,0
  xchg ah,[ss:bx]
  jmp  short @@looppixel
@@skip:
  inc  di
@@looppixel:
  inc  bx
  dec  [Pos]
  jz   @@endrow
  dec  dh
  jnz  @@nextpixel
  jmp  short @@nextbyte
@@endrow:
  add  di,[AddDI]
  loop @@nextrow
  ret
endp

proc PrintLetterShd8 far ; params&locals: PrintShd
                         ; FS:SI ® @Data[#], BX ® width, CX ® height
  ; AH = "Saved", AL = pixel/shadow, BX = @buffer[pos], CX = line counter,
  ; DH = bit counter, DL = read data, FS:SI = @Data[#], ES:DI = screen
  mov  ax,[LineSize]
  sub  ax,bx
  mov  [AddDI],ax
  InitWCoor8 X,Y
@@nextrow:
  movAX Pos,Font.Width
  mov  bx,[BufOffs]
  mov  ah,0
@@nextbyte:
  mov  dh,8
  mov  dl,[fs:si]
  inc  si
@@nextpixel:
  shr  dl,1
  jnc  @@checkshd
  mov  al,[byte ptr C]
  mov  [es:di],al
  mov  ah,1
  xchg ah,[ss:bx]
  jmp  short @@skip
@@checkshd:
  cmp  [byte ptr ss:bx],0
  jne  @@shadow
  cmp  [byte ptr ss:bx-1],0
  jne  @@shadow
  or   ah,ah
  jz   @@skip
@@shadow:
  mov  al,[byte ptr Sh]
  mov  [es:di],al
  mov  ah,0
  xchg ah,[ss:bx]
@@skip:
  inc  di
  IncWPageOnZero @@looppixel
@@looppixel:
  inc  bx
  dec  [Pos]
  jz   @@endrow
  dec  dh
  jnz  @@nextpixel
  jmp  short @@nextbyte
@@endrow:
  add  di,[AddDI]
  IncWPageOnCarry @@looprow
@@looprow:
  loop @@nextrow
  ret
endp

proc PrintLetterShd16 far ; params&locals: PrintShd
                          ; FS:SI ® @Data[#], BX ® width, CX ® height
  ; AX = pixel/shadow, BX = @buffer[pos], CX = line counter,
  ; DH = bit counter, DL = read data, FS:SI = @Data[#], ES:DI = screen
  mov  ax,[LineSize]
  shl  bx,1
  sub  ax,bx
  mov  [AddDI],ax
  InitWCoor16 X,Y
@@nextrow:
  movAX Pos,Font.Width
  mov  bx,[BufOffs]
  mov  [Saved],0
@@nextbyte:
  mov  dh,8
  mov  dl,[fs:si]
  inc  si
@@nextpixel:
  shr  dl,1
  jnc  @@checkshd
  mov  ax,[C]
  mov  [es:di],ax
  mov  al,1
  xchg al,[ss:bx]
  mov  [Saved],al
  jmp  short @@skip
@@checkshd:
  cmp  [byte ptr ss:bx],0
  jne  @@shadow
  cmp  [byte ptr ss:bx-1],0
  jne  @@shadow
  cmp  [Saved],0
  je   @@skip
@@shadow:
  mov  ax,[Sh]
  mov  [es:di],ax
  mov  al,0
  xchg al,[ss:bx]
  mov  [Saved],al
@@skip:
  add  di,2
  IncWPageOnZero @@looppixel
@@looppixel:
  inc  bx
  dec  [Pos]
  jz   @@endrow
  dec  dh
  jnz  @@nextpixel
  jmp  short @@nextbyte
@@endrow:
  add  di,[AddDI]
  IncWPageOnCarry @@looprow
@@looprow:
  loop @@nextrow
  ret
endp

;***************************
;*   GETIMAGE / PUTIMAGE   *
;***************************

macro IncDSegRPageOnSI0 lab
  or   si,si
  jnz  lab
  push ds
  mov  ds,[DSeg]
  call IncRVideoPage
  pop  ds
endm

macro IncDSegWPageOnDI0 lab
  or   di,di
  jnz  lab
  push ds
  mov  ds,[DSeg]
  call IncWVideoPage
  pop  ds
endm

proc GetLine1 far X,Y,W,P:dword
uses ds
  InitCoor1 X,Y,si
  les  di,[P]
  mov  cx,[W]
  mov  ds,[SegA000]
  test si,1
  jz   @@middle
  dec  cx
  movsb
@@middle:
  shr  cx,1
  rep  movsw
  jnc  @@end
  movsb
@@end:
  ret
endp

proc GetLine8 far X,Y,W,P:dword
local DSeg
  InitRCoor8 X,Y,si
  les  di,[P]
  mov  cx,[W]
  mov  [DSeg],ds
  mov  ds,[SegA000]
  ; first 0/1 pixel
  test si,1
  jz   @@middle
  dec  cx
  movsb
  IncDSegRPageOnSI0 @@middle
@@middle: ; middle
  shr  cx,1
  jz   @@last
  pushf
@@nextpixel:
  movsw
  IncDSegRPageOnSI0 @@looppixel
@@looppixel:
  loop @@nextpixel
  ; last 0/1 pixel
  popf
@@last:
  jnc  @@end
  movsb
@@end: ; end of line
  mov  ds,[DSeg]
  ret
endp

proc GetLine16 far X,Y,W,P:dword
local DSeg
  InitRCoor16 X,Y,si
  les  di,[P]
  mov  cx,[W]
  mov  [DSeg],ds
  mov  ds,[SegA000]
  ; first 0/1 pixel
  test si,2
  jz   @@middle
  dec  cx
  movsw
  IncDSegRPageOnSI0 @@middle
@@middle: ; middle
  shr  cx,1
  jz   @@last
  pushf
@@nextpixel:
  movsd
  IncDSegRPageOnSI0 @@looppixel
@@looppixel:
  loop @@nextpixel
  ; last 0/1 pixel
  popf
@@last:
  jnc  @@end
  movsw
@@end: ; end of line
  mov  ds,[DSeg]
  ret
endp

proc PutLine1 far X,Y,W,P:dword
uses ds
  InitCoor1 X,Y
  lds  si,[P]
  mov  cx,[W]
  test di,1
  jz   @@middle
  dec  cx
  movsb
@@middle:
  shr  cx,1
  rep  movsw
  jnc  @@end
  movsb
@@end:
  ret
endp

proc PutLine8 far X,Y,W,P:dword
local DSeg
  InitWCoor8 X,Y
  mov  [DSeg],ds
  lds  si,[P]
  mov  cx,[W]
  ; first 0/1 pixel
  test di,1
  jz   @@middle
  dec  cx
  movsb
  IncDSegWPageOnDI0 @@middle
@@middle: ; middle
  shr  cx,1
  jz   @@last
  pushf
@@nextpixel:
  movsw
  IncDSegWPageOnDI0 @@looppixel
@@looppixel:
  loop @@nextpixel
  ; last 0/1 pixel
  popf
@@last:
  jnc  @@end
  movsb
@@end: ; end of line
  mov  ds,[DSeg]
  ret
endp

proc PutLine16 far X,Y,W,P:dword
local DSeg
  InitWCoor16 X,Y
  mov  [DSeg],ds
  lds  si,[P]
  mov  cx,[W]
  ; first 0/1 pixel
  test di,2
  jz   @@middle
  dec  cx
  movsw
  IncDSegWPageOnDI0 @@middle
@@middle: ; middle
  shr  cx,1
  jz   @@last
  pushf
@@nextpixel:
  movsd
  IncDSegWPageOnDI0 @@looppixel
@@looppixel:
  loop @@nextpixel
  ; last 0/1 pixel
  popf
@@last:
  jnc  @@end
  movsw
@@end: ; end of line
  mov  ds,[DSeg]
  ret
endp

proc PutTransparentLine1 far X,Y,W,P:dword,T
uses ds
  InitCoor1 X,Y
  lds  si,[P]
  mov  dl,[byte ptr T]
  mov  cx,[W]
@@nextpixel:
  lodsb
  cmp  al,dl
  je   @@skip
  stosb
  jmp  short @@looppixel
@@skip:
  inc  di
@@looppixel:
  loop @@nextpixel
  ret
endp

proc PutTransparentLine8 far X,Y,W,P:dword,T
local DSeg
  InitWCoor8 X,Y
  mov  [DSeg],ds
  lds  si,[P]
  mov  dl,[byte ptr T]
  mov  cx,[W]
@@nextpixel:
  lodsb
  cmp  al,dl
  je   @@skip
  stosb
  jmp  short @@test
@@skip:
  inc  di
@@test:
  IncDSegWPageOnDI0 @@looppixel
@@looppixel:
  loop @@nextpixel
  mov  ds,[DSeg]
  ret
endp

proc PutTransparentLine16 far X,Y,W,P:dword,T
local DSeg
  InitWCoor16 X,Y
  mov  [DSeg],ds
  lds  si,[P]
  mov  dx,[T]
  mov  cx,[W]
@@nextpixel:
  lodsw
  cmp  ax,dx
  je   @@skip
  stosw
  jmp  short @@test
@@skip:
  inc2 di
@@test:
  IncDSegWPageOnDI0 @@looppixel
@@looppixel:
  loop @@nextpixel
  mov  ds,[DSeg]
  ret
endp

;*********************
;*   IMAGE DRAWING   *
;*********************
public SetImageMode, PutNextRed,PutNextGreen,PutNextBlue
public RepeatNextPixel,PutNextBlock,SkipNextPixel,SkipNextBlock

proc SetImageMode near Mode ; >0: drawing, =0: skipping, <0: finished
  mov  ax,cs
  shl  eax,16
  cmp  [Mode],0
  jg   @@drawing
  jl   @@finished
  and  [ImageMode],not iDrawing
  mov  ax,offset SkipNextPixel_
  jmp  short @@setproc
@@drawing:
  or   [ImageMode],iDrawing
  cmp  [GrMode],16
  je   @@drawing16
  mov  ax,offset PutNextPixel8
  jmp  short @@setproc
@@drawing16:
  mov  ax,offset PutNextPixel16
  jmp  short @@setproc
@@finished:
  and  [ImageMode],not iDrawing
  or   [ImageMode],iShowed
  mov  ax,offset Empty2
@@setproc:
  mov  [PutNextPixel],eax
  ret
endp

proc PutNextPixel8 ; Clr:word
  mov  bx,sp
  les  di,[ImageAddr]
  mov  al,[ss:bx+4] ;Clr
  stosb
  inc  [word ptr ImageAddr]
  dec  [Remains]
  jnz  @@exit
  call GetReady
@@exit:
  ret  2
endp

proc PutNextPixel16 ; Clr:word
  mov  bx,sp
  les  di,[ImageAddr]
  mov  ax,[ss:bx+4] ;Clr
  stosw
  add  [word ptr ImageAddr],2
  dec  [Remains]
  jnz  @@exit
  call GetReady
@@exit:
  ret  2
endp

proc SkipNextPixel_ ; Clr:word
  dec  [Remains]
  jnz  @@exit
  call GetReady
@@exit:
  ret  2
endp

proc PutNextMasked far ; Clr:word ; jump point from another procedure
                       ; AX ® argument for "or", DX ® argument for "and"
  les  di,[ImageAddr]
  and  [es:di],dx
  or   [es:di],ax
  add  [word ptr ImageAddr],2
  dec  [Remains]
  jnz  @exit
  call GetReady
@masked_exit:
  ret  2
endp

proc PutNextRed ; Clr:word
  test [ImageMode],iDrawing
  jz   @masked_exit
  mov  dx,07FFh
  mov  bx,sp
  mov  ax,[ss:bx+4] ;Clr
  cmp  [RGB255],0
  jne  @@255
  and  ax,3Eh
  shl  ax,10
  jmp  PutNextMasked
@@255:
  and  ax,0F8h
  shl  ax,8
  jmp  PutNextMasked
endp

proc PutNextGreen ; Clr:word
  test [ImageMode],iDrawing
  jz   @masked_exit
  mov  dx,0F81Fh
  mov  bx,sp
  mov  ax,[ss:bx+4] ;Clr
  cmp  [RGB255],0
  jne  @@255
  and  ax,3Fh
  shl  ax,5
  jmp  PutNextMasked
@@255:
  and  ax,0FCh
  shl  ax,3
  jmp  PutNextMasked
endp

proc PutNextBlue ; Clr:word
  test [ImageMode],iDrawing
  jz   @masked_exit
  mov  dx,0FFE0h
  mov  bx,sp
  mov  ax,[ss:bx+4] ;Clr
  cmp  [RGB255],0
  jne  @@255
  and  ax,3Eh
  shr  ax,1
  jmp  PutNextMasked
@@255:
  and  ax,0F8h
  shr  ax,3
  jmp  PutNextMasked
endp

proc RepeatNextPixel Clr:word,Count:dword
@@next:
  mov  eax,[Count]
  or   eax,eax
  jz   @@exit
  movzx edx,[Remains]
  cmp  eax,edx
  jb   @@last
  sub  eax,edx
  mov  [Count],eax
  xchg ax,dx
  call near RepeatNextPixel_Loop
  call GetReady
  jmp  @@next
@@last:
  sub  [Remains],ax
  call near RepeatNextPixel_Loop
@@exit:
  ret
endp

proc RepeatNextPixel_Loop near ; parameters: RepeatNextPixel ; AX ® count
  test [ImageMode],iDrawing
  jz   @@exit
  cmp  [GrMode],16
  sete cl
  mov  dx,ax
  shl  dx,cl
  les  di,[ImageAddr]
  add  [word ptr ImageAddr],dx
  or   cl,cl
  xchg cx,ax
  mov  ax,[Clr]
  jnz  @@16bit ; CL!=0
  rep  stosb
@@exit:
  ret
@@16bit:
  rep  stosw
  ret
endp

proc PutNextBlock Buf:dword,Count:word
@@next:
  mov  ax,[Count]
  or   ax,ax
  jz   @@exit
  mov  dx,[Remains]
  cmp  ax,dx
  jb   @@last
  sub  ax,dx
  mov  [Count],ax
  xchg ax,dx
  call near PutNextBlock_Loop
  call GetReady
  jmp  @@next
@@last:
  call near PutNextBlock_Loop
@@exit:
  ret
endp

proc PutNextBlock_Loop near ; parameters: PutNextBlock ; AX ® count
  sub  [Remains],ax
  cmp  [GrMode],16
  sete cl
  mov  si,ax
  shl  si,cl
  les  di,[ImageAddr]
  add  [word ptr ImageAddr],si
  xadd [word ptr Buf],si
  test [ImageMode],iDrawing
  jz   @@exit
  push ds
  mov  ds,[word ptr Buf+2]
  or   cl,cl
  xchg cx,ax
  jnz  @@16bit ; CL!=0
  rep  movsb
  pop  ds
@@exit:
  ret
@@16bit:
  rep  movsw
  pop  ds
  ret
endp

proc SkipNextPixel
  cmp  [GrMode],16
  sete al
  cbw
  inc  ax
  add  [word ptr ImageAddr],ax
  dec  [Remains]
  jnz  @@exit
  call GetReady
@@exit:
  ret
endp

proc SkipNextBlock Count:dword
  mov  eax,[Count]
@@next:
  movzx edx,[Remains]
  sub  eax,edx
  jc   @@last
  push eax
  call GetReady
  pop  eax
  jmp  @@next
@@last:
  add  dx,ax
  sub  [Remains],dx
  cmp  [GrMode],16
  sete cl
  shl  dx,cl
  add  [word ptr ImageAddr],dx
  ret
endp

END