{$A+,B-,D-,E+,F+,G+,I-,L-,N+,P-,Q-,R-,S-,T-,V-,X+,Y-}
{*-----------------------------------------------*}
{|                                               |}
{|  <<< VGA 13h-mode unit for fast graphics >>>  |}
{|         Written on Borland Pascal 7.0         |}
{|     and supports real and protected modes.    |}
{|    Version 1.11 p, last update : 20-Dec-97    |}
{|       Coded by HardBreaker [FleXoft Co.]      |}
{|    alexic@ropnet.ru; 9135@multi-page.cea.ru   |}
{|      Alexic@hotmail.com, #pascal-IRC-EFNet    |}
{|  Special thanks to : Zyklon, [bios], my wife  |}
{|                                               |}
{*-----------------------------------------------*}

Unit Graphics;
Interface
Type
  { VGA color record }
  TColor    = record
    R, G, B : byte;
  end;

  { VGA palette structures }
  PVGAPalette  = ^TVGAPalette;
  TVGAPalette  = array[0..255] of TColor;

  { Sprite structures }
  PSprite = ^TSprite;
  TSprite = record
    a, b : word;
    data : pointer;
  end;

Const
  { Unit version label }
  Version        = '1.11 p';

  { Error codes }
  VGA_Ok          =   0;
  VGA_NoMemory    =  -1;
  VGA_IOError     =  -2;
  VGA_NoFile      =  -3;
  VGA_BadVersion  =  -4;
  VGA_BadFormat   =  -5;

  { Workplace area }
  MinX           =   0;
  MaxX           = 319;
  MinY           =   0;
  MaxY           = 199;

Var
  { Pointer to double buffer     }
  { aka virtual or shadow screen }
  DBuffer   : pointer;

  { Pointer to VGA videobuffer   }
  VBuffer   : pointer;

  {$L vb30.obj}                          { include 32-bit grapics procedures }
                                         { see asm source at the end of file }
{ -------------------------------------------------------------------------- }
Function  GetVideoMode:byte;                    { get current video mode     }
Procedure SetVideoMode(n:byte);                 { set video mode             }
Procedure InitGraphMode;                        { init 13h graph mode        }
Procedure DoneGraphMode;                        { restore old mode           }
Function  InitDoubleBuffer:integer;             { allocate double buffer     }
Procedure DoneDoubleBuffer;                     { deallocate double buffer   }
Procedure ShowBuffer32;                         { copy d-buffer to screen    }
Procedure ClearDBuffer32;                       { clear d-buffer fast        }
Procedure ClearVBuffer32;                       { clear screen buffer fast   }
Procedure Retrace;                              { wait for back trace        }
{ -------------------------------------------------------------------------- }
Procedure SetPoint(x,y:integer;c:byte);         { fast point to d-buffer     }
Function  GetPoint(x,y:integer):byte;           { get point from d-buffer    }
Procedure SetScreenPoint(x,y:integer;c:byte);   { fast point direct to screen}
Function  GetScreenPoint(x,y:integer):byte;     { get point from screen      }
Procedure SetVLine(x,y1,y2:integer;c:byte);     { fast vertical line (db)    }
Procedure SetHLine(x1,x2,y:integer;c:byte);     { fast horizontal line (db)  }
Procedure SetLine(x1,y1,x2,y2:integer;c:byte);  { set line (not so fast)     }
Procedure SetBox(x1,y1,x2,y2:integer;c:byte);   { draw box                   }
Procedure SetRect(x1,y1,x2,y2:integer;c:byte);  { draw rectangle             }
{ -------------------------------------------------------------------------- }
Procedure SetPaletteColor(c,r,g,b:byte);        { set palette color          }
Procedure GetPaletteColor(c:byte;var r,g,b:byte); { get palette color        }
Function  ColorInPal(var c:byte;r,g,b:byte;p:pointer):boolean; { check color }
Function  FindColor(var c:byte;r,g,b:byte;p:pointer):integer;  { find color  }
Procedure SetAllPalette(p: pointer);            { set all vga palette        }
Procedure GetAllPalette(p: pointer);            { get all vga palette        }
Procedure FadeIn(n:word;p:pointer);             { fading palette in          }
Procedure FadeOut(n:word);                      { fading palette out         }
{ -------------------------------------------------------------------------- }
Procedure BitBLT_Opaque(x,y:integer; sprite:TSprite);       { bit blitting   }
Procedure BitBLT_Transparent(x,y:integer; sprite:TSprite);  { bit blitting   }
Procedure BitBLT_OpaqueT(x,y:integer; sprite:TSprite);      { bit blitting   }
Procedure BitBLT_TransparentT(x,y:integer; sprite:TSprite); { bit blitting   }
Procedure Zoom_OpaqueT(zx,zy,za,zb:integer; sprite:TSprite); { zoom opaque   }
Procedure Zoom_TransparentT(zx,zy,za,zb:integer; sprite:TSprite); { zoom tr. }
Procedure GetImage(zx,zy:integer; sprite:TSprite); {                         }
{ -------------------------------------------------------------------------- }
Function  InitSysFont(cb,cf:byte):integer;      { load BIOS 1st 128 chars    }
Procedure DoneSysFont;                          { unload system font         }
Procedure TextOut(x,y:integer; st:string);      { write to screen/d-buffer   }
{ -------------------------------------------------------------------------- }
Function  GetVGAErrorMsg(n:integer):string;     { get error msg by errnum    }
{ -------------------------------------------------------------------------- }

Implementation
Uses
  CRT;

Type
  PFontBuffer = ^TFontBuffer;
  TFontBuffer = array[0..8191] of byte;

Var
  sysfont  : PFontBuffer;

{ --------------------------------------------------------------------- }

Function GetVideoMode;
{    Job : return current videomode via bios call                       }
{  Input : none                                                         }
{ Output : videomode ( byte )                                           }
begin;
  asm
    mov ah, $0F
    int $10
    mov @result, al
  end;
end;

Procedure SetVideoMode; assembler;
{    Job : set video mode via bios call                                 }
{  Input : videomode number ( byte )                                    }
{ Output : none                                                         }
asm
  xor ah, ah
  mov al, n
  int $10
end;

Procedure InitGraphMode; assembler;
{    Job : initiate 13h mode ( 320x200x256 )                            }
{  Input : none                                                         }
{ Output : none                                                         }
asm
  mov ax,$0013
  int $10
end;

Procedure DoneGraphMode; assembler;
{    Job : reset to 03h text mode ( 80x25 )                             }
{  Input : none                                                         }
{ Output : none                                                         }
asm
  mov ax, $0003
  int $10
end;

Function InitDoubleBuffer;
{    Job : allocate double buffer 64000 bytes in heap                   }
{  Input : none                                                         }
{ Output : operation error code (integer), 0 if no errors               }
begin
  if dbuffer = vbuffer then begin
    if MaxAvail < 64000 then begin
      InitDoubleBuffer:=VGA_NoMemory; exit;
    end;
    getmem(dbuffer,64000);
  end;
  InitDoubleBuffer:=VGA_Ok;
end;

Procedure DoneDoubleBuffer;
{    Job : deallocate double buffer                                     }
{  Input : none                                                         }
{ Output : none                                                         }
begin
  if dbuffer <> vbuffer then begin
    freemem(dbuffer,64000);
    dbuffer:=vbuffer;
  end;
end;

Procedure ShowBuffer32;   external;
{    Job : fast copy double buffer to VGA screen memory                 }
{  Input : none                                                         }
{ Output : none                                                         }

Procedure ClearDBuffer32; external;
{    Job : fast cleaning double buffer                                  }
{  Input : none                                                         }
{ Output : none                                                         }

Procedure ClearVBuffer32; external;
{    Job : fast cleaning VGA screen memory                              }
{  Input : none                                                         }
{ Output : none                                                         }

Procedure Retrace; assembler;
{    Job : wait for begin retracing CRT                                 }
{  Input : none                                                         }
{ Output : none                                                         }
asm
  mov dx,$3da
 @wait1:
  in al,dx
  and al,8
  jnz @wait1
 @wait2:
  in al,dx
  and al,8
  jz @wait2
end;

{ --------------------------------------------------------------------- }

Procedure SetPoint; assembler;
{    Job : set fast point on screen/double buffer ( with clipping )     }
{  Input : x, y - coordinates; c - color index                          }
{ Output : none                                                         }
asm
  mov ax, y              { load y to ax }
  cmp ax, MinY
  jl @fin
  cmp ax, MaxY
  jg @fin
  mov cx, x              { load x to cx }
  cmp cx, MinX
  jl @fin
  cmp cx, MaxX
  jg @fin
  les di, dbuffer        { loading d-buffer starting address }
  mov bx, ax             { copy y to bx }
  sal ax, 6              { shift equal mult on 32 }
  sal bx, 8              { shift equal mult on 256 }
  add ax, bx             { equal mult on 320 (with shifts) }
  add ax, cx             { starting point solved }
  add di, ax             { starting point in es:di now }
  mov bh, c              { load color into bh }
  mov es:[di], bh        { moving color into d-buffer }
 @fin:
end;

Function  GetPoint;
{    Job : get point from screen/double buffer ( with clipping )        }
{  Input : x, y - coordinates                                           }
{ Output : color index                                                  }
begin;
  asm
    mov ax, y              { load y to ax }
    cmp ax, MinY
    jl @fin
    cmp ax, MaxY
    jg @fin
    mov cx, x              { load x to cx }
    cmp cx, MinX
    jl @fin
    cmp cx, MaxX
    jg @fin
    les di, dbuffer        { loading d-buffer starting address }
    mov bx, ax             { copy y to bx }
    sal ax, 6              { shift equal mult on 32 }
    sal bx, 8              { shift equal mult on 256 }
    add ax, bx             { equal mult on 320 (with shifts) }
    add ax, cx             { starting point solved }
    add di, ax             { starting point in es:di now }
    mov bh, es:[di]
    mov @result, bh
    jmp @ok
   @fin:
    mov @result, 0
   @ok:
  end;
end;

Procedure SetScreenPoint; assembler;
{    Job : set point direct to screen ( with clipping )                 }
{  Input : x, y - coordinates; c - color index                          }
{ Output : none                                                         }
asm
  mov ax, y              { load y to ax }
  cmp ax, MinY
  jl @fin
  cmp ax, MaxY
  jg @fin
  mov cx, x              { load x to cx }
  cmp cx, MinX
  jl @fin
  cmp cx, MaxX
  jg @fin
  les di, vbuffer        { loading screen buffer starting address }
  mov bx, ax             { copy y to bx }
  sal ax, 6              { shift equal mult on 32 }
  sal bx, 8              { shift equal mult on 256 }
  add ax, bx             { equal mult on 320 (with shifts) }
  add ax, cx             { starting point solved }
  add di, ax             { starting point in es:di now }
  mov bh, c              { load color into bh }
  mov es:[di], bh        { moving color into d-buffer }
 @fin:
end;

Function  GetScreenPoint;
{    Job : get point from VGA screen memory                             }
{  Input : x, y - coordinates                                           }
{ Output : color index                                                  }
begin;
  asm
    mov ax, y              { load y to ax }
    cmp ax, MinY
    jl @fin
    cmp ax, MaxX
    jg @fin
    mov cx, x              { load x to cx }
    cmp cx, MinX
    jl @fin
    cmp cx, MaxX
    jg @fin
    les di, vbuffer        { loading d-buffer starting address }
    mov bx, ax             { copy y to bx }
    sal ax, 6              { shift equal mult on 32 }
    sal bx, 8              { shift equal mult on 256 }
    add ax, bx             { equal mult on 320 (with shifts) }
    add ax, cx             { starting point solved }
    add di, ax             { starting point in es:di now }
    mov bh, es:[di]        { load point from buffer to bh }
    mov @result, bh        { return color into func. result }
    jmp @ok
   @fin:
    mov @result, 0
   @ok:
  end;
end;

Procedure SetVLine; assembler;
{    Job : draw vertical line to screen/double buffer ( with clipping ) }
{  Input : x, y1, y2 - coordinates; c - color index                     }
{ Output : none                                                         }
asm
  mov cx, x
  cmp cx, MinX
  jl @fin
  cmp cx, MaxX
  jg @fin
  mov ax, y1
  cmp y2, ax
  jg @nochange
    xchg y2, ax
    mov y1, ax
 @nochange:
  mov ax, y1
  cmp ax, MaxY
  jg @fin
  cmp ax, MinY
  jge @notopcut
  mov ax, MinY
  mov y1, ax
 @notopcut:
  mov ax, y2
  cmp ax, MinY
  jl @fin
  cmp ax, MaxY
  jle @nobottomcut
  mov ax, MaxY
  mov y2, ax
 @nobottomcut:
  les di, dbuffer       { loading d-buffer starting address }
  mov ax, y1            { solving starting point }
  mov bx, ax            { copy y1 to bx }
  sal ax, 6             { shift equal mult on 32 }
  sal bx, 8             { shift equal mult on 256 }
  add ax, bx            { equal mult on 320 (with shifts) }
  mov bx, x             { load x to bx }
  add ax, bx            { starting point solved }
  add di, ax            { starting point in es:di now }
  mov cx, y2            { load y2 coordinate to ax }
  mov bx, y1            { load y1 coordinate to bx }
  inc cx                { correct size of line }
  sub cx, bx            { size of line -1 in ax }
  mov bh, c             { load color into bh }
  mov ax, 320           { load size of line into cx }
 @cont:                 { label for repeat points }
    mov es:[di], bh     { moving color into d-buffer }
    add di, ax          { increment pointer }
  loop @cont            { return if not ready }
 @fin:
end;

Procedure SetHLine; assembler;
{    Job : draw horizontal line to screen/dble buffer ( with clipping ) }
{  Input : x1, x2, y - coordinates, c - color index                     }
{ Output : none                                                         }
asm
  mov ax, y
  cmp ax, MinY
  jl @fin
  cmp ax, MaxY
  jg @fin
  mov ax, x1
  cmp x2, ax
  jg @nochange
    xchg x2, ax
    mov x1, ax
 @nochange:
  mov ax, x1
  cmp ax, MaxX
  jg @fin
  cmp ax, MinX
  jge @noleftcut
  mov ax, MinX
  mov x1, ax
 @noleftcut:
  mov ax, x2
  cmp ax, MinX
  jl @fin
  cmp ax, MaxX
  jle @norightcut
  mov ax, MaxX
  mov x2, ax
 @norightcut:
  les di, dbuffer       { loading d-buffer starting address }
  mov ax, y             { solving starting point }
  mov bx, ax            { copy y to bx }
  sal ax, 6             { shift equal mult on 32 }
  sal bx, 8             { shift equal mult on 256 }
  add ax, bx            { equal mult on 320 (with shifts) }
  mov bx, x1            { load first x to bx }
  add ax, bx            { starting point solved }
  add di, ax            { starting point in es:di now }
  mov cx, x2            { load y2 coordinate to ax }
  inc cx                { correct size of line }
  mov bx, x1            { load y1 coordinate bx }
  sub cx, bx            { size of line -1 in ax }
  mov bh, c             { load color into bh }
 @cont:                 { label for repeat point }
    mov es:[di], bh     { moving color into d-buffer }
    inc di              { increment pointer }
  loop @cont            { return if not ready }
 @fin:
end;

procedure SetLine;  { * needs optimizing * }
{    Job : draw any line on screen/double buffer                        }
{  Input : x1, y1, x2, y2 - coordinates; c - color index                }
{ Output : none                                                         }
var dx, dy, s, e, i : integer; j, delta : single;
begin
  dx:=x2 - x1;
  dy:=y2 - y1;
  if dx = 0 then begin
    if dy = 0 then begin SetPoint(x1,y1,c); exit; end;
    if dy > 0 then begin SetVLine(x1,y1,y2,c); exit; end;
  end;
  if dy = 0 then begin
    if dx = 0 then begin SetPoint(x1,y1,c); exit; end;
    if dx > 0 then begin SetHLine(x1,x2,y1,c); exit; end;
  end;
  if abs(dx) > abs(dy) then begin
    delta:=dy / dx;
    if dx > 0 then begin
      j:=y1; s:=x1; e:=x2;
    end else begin
      j:=y2; s:=x2; e:=x1;
    end;
    for i:=s to e do begin
      SetPoint(i,round(j),c); j:=j+delta;
    end;
  end else begin
    delta:=dx / dy;
    if dy > 0 then begin
      j:=x1; s:=y1; e:=y2;
    end else begin
      j:=x2; s:=y2; e:=y1;
    end;
    for i:=s to e do begin
      SetPoint(round(j),i,c); j:=j+delta;
    end;
  end;
end;

Procedure SetBox;  { * needs optimizing a bit * }
{    Job : draw filled box on screen/double buffer                      }
{  Input : x1, y1, x2, y2 - coordinates; c - color index                }
{ Output : none                                                         }
var i, s, e : integer;
begin
  if y1 < y2 then begin s:=y1; e:=y2 end else begin s:=y2; e:=y1; end;
  for i:=s to e do SetHLine(x1,x2,i,c);
end;

Procedure SetRect;  { * needs optimizing a bit * }
{    Job : draw rectangle on screen/double buffer                       }
{  Input : x1, y1, x2, y2 - coordinates; c - color index                }
{ Output : none                                                         }
begin
  SetHLine(x1,x2,y1,c);
  SetHLine(x1,x2,y2,c);
  SetVLine(x1,y1,y2,c);
  SetVLine(x2,y1,y2,c);
end;

{ --------------------------------------------------------------------- }

Procedure SetPaletteColor;
{    Job : set selected color in VGA palette                            }
{  Input : c - color index; r, g, b - color components (0..63)          }
{ Output : none                                                         }
begin
  port[$3C6]:=$FF;
  port[$3C8]:=c;
  port[$3C9]:=r;
  port[$3C9]:=g;
  port[$3C9]:=b;
end;

Procedure GetPaletteColor;
{    Job : get selected color from VGA palette                          }
{  Input : c - color index                                              }
{ Output : r, g, b - color components (0..63)                           }
begin
  port[$3C6]:=$FF;
  port[$3C7]:=c;
  r:=port[$3C9];
  g:=port[$3C9];
  b:=port[$3C9];
end;

Function ColorInPal;
{    Job : check color in palette                                       }
{  Input : r,g,b - color components; p - palette, if NIL - VGA palette  }
{ Output : true if color in palette, in that case c - index in palette  }
var
  pal        : PVGAPalette;
  tr, tg, tb : byte;
  ok, en     : boolean;
begin
  c:=0; pal:=p; ok:=false; en:=false;
  repeat
    if pal = NIL then begin
      GetPaletteColor(c,tr,tg,tb);
    end else begin
      tr:=pal^[c].r;
      tg:=pal^[c].g;
      tb:=pal^[c].b;
    end;
    if (r = tr) and (g = tg) and (b = tb) then ok:=true;
    if (not ok) and (c < 255) then inc(c) else en:=true;
  until ok or en;
  ColorInPal:=ok;
end;

Function FindColor;
{    Job : find nearest color in palette                                }
{  Input : r, g, b - color components; p - palette,if NIL - VGA palette }
{ Output : deviation                                                    }
var
  i, save, tr, tg, tb : byte;
  dist, d : integer; pal : PVGAPalette;
begin
  dist:=1000; save:=0; pal:=p;
  for i:=0 to 255 do begin
    if pal = NIL then begin
      GetPaletteColor(i,tr,tg,tb);
    end else begin
      tr:=pal^[i].r;
      tg:=pal^[i].g;
      tb:=pal^[i].b;
    end;
    d:=round(sqrt(sqr(tr-r)+sqr(tg-g)+sqr(tb-b)));
    if d < dist then begin dist:=d; save:=i; end;
  end;
  c:=save;
end;

Procedure SetAllPalette;
{    Job : set all palette colors from memory buffer                    }
{  Input : p - pointer to mem buffer ( 768 bytes of color components )  }
{ Output : none                                                         }
var i:byte; pp : PVGAPalette;
begin
  pp:=p;
  for i:=0 to 255 do begin
    port[$3C6]:=$FF;
    port[$3C8]:=i;
    port[$3C9]:=pp^[i].r;
    port[$3C9]:=pp^[i].g;
    port[$3C9]:=pp^[i].b;
  end;
end;

Procedure GetAllPalette;
{    Job : read all VGA palette colors from DAC to memory buffer        }
{  Input : p - pointer to mem buffer ( 768 bytes of color components )  }
{ Output : none                                                         }
var i:byte; pp : PVGAPalette;
begin
  pp:=p;
  for i:=0 to 255 do begin
    port[$3C6]:=$FF;
    port[$3C7]:=i;
    pp^[i].r:=port[$3C9];
    pp^[i].g:=port[$3C9];
    pp^[i].b:=port[$3C9];
  end;
end;

Procedure FadeIn; { * needs optimizing * }
{    Job : fading screen palette into new palette                       }
{  Input : n - fading speed; p : new palette                            }
{ Output : none                                                         }
var tmp : TVGAPalette; pp : PVGAPalette; i, j : byte;
begin
  pp:=p;
  for j:=0 to 63 do begin
    Delay(n);
    for i:=0 to 255 do begin
      tmp[i].R:=round((pp^[i].r / 63) * j);
      tmp[i].G:=round((pp^[i].g / 63) * j);
      tmp[i].B:=round((pp^[i].b / 63) * j);
    end;
    Retrace;
    SetAllPalette(@tmp);
  end;
end;

Procedure FadeOut; { * needs optimizing * }
{    Job : fading screen out                                            }
{  Input : n - fading speed                                             }
{ Output : none                                                         }
var tmp, base : TVGAPalette; i, j : byte;
begin
  GetAllPalette(@base);
  for j:=63 downto 0 do begin
    Delay(n);
    for i:=0 to 255 do begin
      tmp[i].R:=round(j * (base[i].R / 63));
      tmp[i].G:=round(j * (base[i].G / 63));
      tmp[i].B:=round(j * (base[i].B / 63));
    end;
    Retrace;
    SetAllPalette(@tmp);
  end;
end;

{ --------------------------------------------------------------------- }

Procedure BitBLT_Opaque;
{    Job : draw sprite to screen/double buffer ( with clipping )        }
{  Input : x, y - coordinates; sprite - sprite structure                }
{ Output : none                                                         }
var ra, rb, ox, oy, fx, fy, ch1, ch2 : integer; sz, rz : word;
begin
  asm
    mov ax, x
    mov bx, MaxX
    cmp ax, bx
    jg @fin
    mov dx, MinX
    mov cx, sprite.a
    add ax, cx
    cmp ax, dx
    jle @fin
    mov ra, cx
    mov ax, x
    cmp ax, dx
    jge @m_zx
      mov ox, dx
      sub ox, ax
      mov fx, dx
      mov cx, ox
      sub ra, cx
      jmp @m_zxe
    @m_zx:
      mov ox, 0
      mov fx, ax
    @m_zxe:
    mov ch1, ax
    mov bx, sprite.a
    dec bx
    add ch1, bx
    mov cx, MaxX
    cmp ch1, cx
    jle @noxdec
      mov ax, ch1
      sub ax, cx
      sub ra, ax
    @noxdec:
    mov ax, y
    mov bx, MaxY
    cmp ax, bx
    jg @fin
    mov dx, MinY
    mov cx, sprite.b
    add ax, cx
    cmp ax, dx
    jle @fin
    mov rb, cx
    mov ax, y
    cmp ax, dx
    jge @m_zy
      mov oy, dx
      sub oy, ax
      mov fy, dx
      mov cx, oy
      sub rb, cx
      jmp @m_zye
    @m_zy:
      mov oy, 0
      mov fy, ax
    @m_zye:
    mov ch2, ax
    mov bx, sprite.b
    dec bx
    add ch2, bx
    mov cx, MaxY
    cmp ch2, cx
    jle @noydec
      mov ax, ch2
      sub ax, cx
      sub rb, ax
    @noydec:
    mov ax, oy
    mov bx, sprite.a
    imul bx
    mov sz, ax
    mov ax, ra
    mov bx, rb
    imul bx
    mov rz, ax
    { go draw }
    push ds
    les di, dbuffer
    add di, fx
    mov ax, fy
    mov bx, ax
    sal ax, 6
    sal bx, 8
    add di, bx
    add di, ax
    lds si, sprite.data
    add si, sz
    add si, ox
    mov dx, sprite.a
    mov bx, ra
    mov cx, rz
    @sprite_loop:
      mov al, ds:[si]
      mov es:[di], al
      inc di
      inc si
      dec bx
      cmp bx, 0
      jne @nocorr
        mov bx, ra
        sub di, bx
        add di, 320
        add si, dx
        sub si, bx
      @nocorr:
    loop @sprite_loop
    pop ds
    @fin:
  end;
end;

Procedure BitBLT_Transparent;
{    Job : draw sprite to screen/double buffer with transparency check  }
{          trancparency color = 0  ( with clipping )                    }
{  Input : x, y - coordinates; sprite - sprite structure                }
{ Output : none                                                         }
var ra, rb, ox, oy, fx, fy, ch1, ch2 : integer; sz, rz : word;
begin
  asm
    mov ax, x
    mov bx, MaxX
    cmp ax, bx
    jg @fin
    mov dx, MinX
    mov cx, sprite.a
    add ax, cx
    cmp ax, dx
    jle @fin
    mov ra, cx
    mov ax, x
    cmp ax, dx
    jge @m_zx
      mov ox, dx
      sub ox, ax
      mov fx, dx
      mov cx, ox
      sub ra, cx
      jmp @m_zxe
    @m_zx:
      mov ox, 0
      mov fx, ax
    @m_zxe:
    mov ch1, ax
    mov bx, sprite.a
    dec bx
    add ch1, bx
    mov cx, MaxX
    cmp ch1, cx
    jle @noxdec
      mov ax, ch1
      sub ax, cx
      sub ra, ax
    @noxdec:
    mov ax, y
    mov bx, MaxY
    cmp ax, bx
    jg @fin
    mov dx, MinY
    mov cx, sprite.b
    add ax, cx
    cmp ax, dx
    jle @fin
    mov rb, cx
    mov ax, y
    cmp ax, dx
    jge @m_zy
      mov oy, dx
      sub oy, ax
      mov fy, dx
      mov cx, oy
      sub rb, cx
      jmp @m_zye
    @m_zy:
      mov oy, 0
      mov fy, ax
    @m_zye:
    mov ch2, ax
    mov bx, sprite.b
    dec bx
    add ch2, bx
    mov cx, MaxY
    cmp ch2, cx
    jle @noydec
      mov ax, ch2
      sub ax, cx
      sub rb, ax
    @noydec:
    mov ax, oy
    mov bx, sprite.a
    imul bx
    mov sz, ax
    mov ax, ra
    mov bx, rb
    imul bx
    mov rz, ax
    { go draw }
    push ds
    les di, dbuffer
    add di, fx
    mov ax, fy
    mov bx, ax
    sal ax, 6
    sal bx, 8
    add di, bx
    add di, ax
    lds si, sprite.data
    add si, sz
    add si, ox
    mov dx, sprite.a
    mov bx, ra
    mov cx, rz
    @sprite_loop:
      mov al, ds:[si]
      cmp al, 0
      je @skip_transparent
        mov es:[di], al
      @skip_transparent:
      inc di
      inc si
      dec bx
      cmp bx, 0
      jne @nocorr
        mov bx, ra
        sub di, bx
        add di, 320
        add si, dx
        sub si, bx
      @nocorr:
    loop @sprite_loop
    pop ds
    @fin:
  end;
end;

Procedure BitBLT_OpaqueT;
{    Job : draw sprite to screen/double buffer  ( w/o clipping )        }
{  Input : x, y - coordinates; sprite - sprite structure                }
{ Output : none                                                         }
begin
  asm
    push ds                         { save DS segment }
    les di, dbuffer                 { load d-buffer }
    mov ax, y                       { load starting y }
    mov bx, ax                      { copy starting y }
    sal ax, 6                       { mul to 64 }
    sal bx, 8                       { mul to 256 }
    add ax, bx                      { now mul to 320 }
    mov bx, x                       { load starting x }
    add ax, bx                      { solving starting dest point }
    add di, ax                      { dest first point in es:di }
    lds si, sprite.data             { load source point to ds:si }
    mov bx, sprite.b                { load height to bx }
    mov cx, sprite.a                { load width to cx }
    @cont_next_line:                { label for next line }
      mov cx, sprite.a              { load width again }
      @cont_line:                   { label for next pixel }
        mov al, ds:[si]             { load source to al }
        mov [es:di], al             { load al to dest }
        inc si                      { increment source line }
        inc di                      { increment dest line }
        dec cx                      { decrement pixel counter }
      jnz @cont_line                { return if line not ready }
      add di, 320                   { add const to next line }
      sub di, sprite.a              { correct to start line }
      dec bx                        { decrement lines counter }
    jnz @cont_next_line             { continue if block not ready }
    pop ds                          { return ds segment }
  end;
end;

Procedure BitBLT_TransparentT;
{    Job : draw sprite to screen/double buffer with transparency check  }
{          trancparency color = 0  ( w/o clipping )                     }
{  Input : x, y - coordinates; sprite - sprite structure                }
{ Output : none                                                         }
begin
  asm
    push ds                         { save DS segment }
    les di, dbuffer                 { load d-buffer }
    mov ax, y                       { load starting y }
    mov bx, ax                      { copy starting y }
    sal ax, 6                       { mul to 64 }
    sal bx, 8                       { mul to 256 }
    add ax, bx                      { now mul to 320 }
    mov bx, x                       { load starting x }
    add ax, bx                      { solving starting dest point }
    add di, ax                      { dest first point in es:di }
    lds si, sprite.data             { load source point to ds:si }
    mov bx, sprite.b                { load height to bx }
    mov cx, sprite.a                { load width to cx }
    @cont_next_line:                { label for next line }
      mov cx, sprite.a              { load width again }
      @cont_line:                   { label for next pixel }
        mov al, ds:[si]             { load source to al }
        cmp al, 0                   { compare with transparent }
        je @skip_transparent        { skip if transparent }
          mov [es:di], al           { load al to dest }
        @skip_transparent:          { label for skipping }
        inc si                      { increment source line }
        inc di                      { increment dest line }
        dec cx                      { decrement pixel counter }
      jnz @cont_line                { return if line not ready }
      add di, 320                   { add const to next line }
      sub di, sprite.a              { correct to start line }
      dec bx                        { decrement lines counter }
    jnz @cont_next_line             { continue if block not ready }
    pop ds                          { return ds segment }
  end;
end;

procedure Zoom_OpaqueT;    { * needs addon clipping * }
{    Job : moving sprite into screen with zooming ( w/o clipping )   }
{          max sprite size for correct zooming - 255x255             }
{  Input : zx, zy, za, zb - position and size of sprite on screen,   }
{          sprite - sprite structure                                 }
{ Output : none ( visual result :)                                   }
var vdx, vdy, soff : word;
begin
  asm
    push ds                     { save ds register, will changed }
    mov ax, 320                 { * }
    sub ax, word ptr za
    mov word ptr soff, ax       { make screen offset }
    mov ax, word ptr sprite.a   { * }
    mov bx, word ptr za
    sal ax, 8
    xor dx, dx
    div bx
    mov word ptr vdx, ax        { count increment x factor }
    mov ax, word ptr sprite.b   { * }
    mov bx, word ptr zb
    sal ax, 8
    xor dx, dx
    div bx
    mov word ptr vdy, ax     { count increment y factor }
    les di, dbuffer          { * }
    mov ax, zy
    mov bx, ax
    sal ax, 6
    sal bx, 8
    add ax, bx
    mov bx, zx
    add ax, bx
    add di, ax               { es:di points to first screen pixel }
    lds si, sprite.data      { ds:si points to first pixel of sprite }
    xor dx, dx               { reset current row (fixed) counter }
    mov cx, zb               { init counter by column size }
    @column:
      push cx                { save cx for inner loop }
      push dx                { save dx for inner loop }
      xor bx, bx             { reset bx (row pixel offset) }
      xor dx, dx             { reset row (fixed) counter }
      mov cx, za             { init current pixel in row }
      @row:
        mov al, ds:[si][bx]  { pick up pixel from sprite }
        mov es:[di], al      { draw pixel into video (or double) buffer }
        add dx, word ptr vdx { increment pixel in row counter (fixed) }
        mov bl, dh           { modify bx by integer part of current pixel }
        inc di               { increment video (double) buffer offset }
      loop @row              { loop of row drawing }
      add di, word ptr soff  { increment screen (double) buffer offset }
      pop dx                 { restore dx for outer loop }
      pop cx                 { restore cx for outer loop }
      mov ah, dh             { move dh to ah }
      add dx, word ptr vdy   { increment column counter (fixed) }
      mov al, dh
      sub al, ah
      jz @nonextcol
      @incy:
        add si, word ptr sprite.a
        dec al
        cmp al, 0
      jnz @incy
      @nonextcol:
    loop @column
    pop ds                 { restore ds register }
  end;
end;

procedure Zoom_TransparentT;    { * needs addon clipping * }
{    Job : moving sprite into screen with zooming ( w/o clipping )   }
{          max sprite size for correct zooming - 255x255             }
{  Input : zx, zy, za, zb - position and size of sprite on screen,   }
{          sprite - sprite structure                                 }
{ Output : none ( visual result :)                                   }
var vdx, vdy, soff : word;
begin
  asm
    push ds                       { save ds register, will changed }
    mov ax, 320                   { * }
    sub ax, word ptr za
    mov word ptr soff, ax         { make screen offset }
    mov ax, word ptr sprite.a     { * }
    mov bx, word ptr za
    sal ax, 8
    xor dx, dx
    div bx
    mov word ptr vdx, ax          { count increment x factor }
    mov ax, word ptr sprite.b     { * }
    mov bx, word ptr zb
    sal ax, 8
    xor dx, dx
    div bx
    mov word ptr vdy, ax          { count increment y factor }
    les di, dbuffer               { * }
    mov ax, zy
    mov bx, ax
    sal ax, 6
    sal bx, 8
    add ax, bx
    mov bx, zx
    add ax, bx
    add di, ax                    { es:di points to first screen pixel }
    lds si, sprite.data           { ds:si points to first pixel of sprite }
    xor dx, dx                    { reset current row (fixed) counter }
    mov cx, zb                    { init counter by column size }
    @column:
      push cx                     { save cx for inner loop }
      push dx                     { save dx for inner loop }
      xor bx, bx                  { reset bx (row pixel offset) }
      xor dx, dx                  { reset row (fixed) counter }
      mov cx, za                  { init current pixel in row }
      push bp                     { save bp (will changed) }
      mov bp, word ptr vdx        { store horiz. increment into bp }
      @row:
        mov al, ds:[si][bx]       { pick up pixel from sprite }
        cmp al, 0                 { compare pixel with transparent color }
        je @skip                  { skip if transparent color }
          mov es:[di], al         { draw pixel into video (or double) buffer }
        @skip:
        add dx, bp                { increment pixel in row counter (fixed) }
        mov bl, dh                { modify bx by int. part of current pixel }
        inc di                    { increment video (double) buffer offset }
      loop @row                   { loop of row drawing }
      pop bp                      { restore bp register }
      add di, word ptr soff       { increment screen (double) buffer offset }
      pop dx                      { restore dx for outer loop }
      pop cx                      { restore cx for outer loop }
      mov ah, dh                  { move dh to ah }
      add dx, word ptr vdy        { increment column counter (fixed) }
      mov al, dh
      sub al, ah
      jz @nonextcol
        mov bx, word ptr sprite.a
        @incy:
          add si, bx
          dec al
          cmp al, 0
        jnz @incy
      @nonextcol:
    loop @column
    pop ds                        { restore ds register }
  end;
end;

procedure GetImage;  { * needs optimizing * }
{    Job : moving screen/dbl buffer image to sprite structure           }
{  Input : zx, zy - position image on screen                            }
{          sprite - sprite structure, filled with a, b sprite size      }
{          and allocated memory for sprite ( getmem(data, a * b) )      }
{ Output : none                                                         }
type tm = array[0..64000] of byte;
var i, j : integer; m : ^tm;
begin
  m:=sprite.data;
  for i:=zx to zx+sprite.a-1 do begin
    for j:=zy to zy+sprite.b-1 do begin
      m^[(i-zx)+(j-zy)*sprite.a]:=GetPoint(i,j);
    end;
  end;
end;

{ ------------------------------------------------------------------------ }

Function InitSysFont;
{    Job : allocate buffer and fill it with char bitmaps                  }
{          here using copy of BIOS standart first 128 ASCII chars         }
{  Input : cb, cf - colors of background and foreground of chars          }
{ Output : error code, 0 if Ok                                            }
const
  fs : array[0..1023] of byte =
          (  0,  0,  0,  0,  0,  0,  0,  0,126,129,165,129,189,153,129,126,
           126,255,219,255,195,231,255,126,108,254,254,254,124, 56, 16,  0,
            16, 56,124,254,124, 56, 16,  0, 56,124, 56,254,254,124, 56,124,
            16, 16, 56,124,254,124, 56,124,  0,  0, 24, 60, 60, 24,  0,  0,
           255,255,231,195,195,231,255,255,  0, 60,102, 66, 66,102, 60,  0,
           255,195,153,189,189,153,195,255, 15,  7, 15,125,204,204,204,120,
            60,102,102,102, 60, 24,126, 24, 63, 51, 63, 48, 48,112,240,224,
           127, 99,127, 99, 99,103,230,192,153, 90, 60,231,231, 60, 90,153,
           128,224,248,254,248,224,128,  0,  2, 14, 62,254, 62, 14,  2,  0,
            24, 60,126, 24, 24,126, 60, 24,102,102,102,102,102,  0,102,  0,
           127,219,219,123, 27, 27, 27,  0, 62, 99, 56,108,108, 56,204,120,
             0,  0,  0,  0,126,126,126,  0, 24, 60,126, 24,126, 60, 24,255,
            24, 60,126, 24, 24, 24, 24,  0, 24, 24, 24, 24,126, 60, 24,  0,
             0, 24, 12,254, 12, 24,  0,  0,  0, 48, 96,254, 96, 48,  0,  0,
             0,  0,192,192,192,254,  0,  0,  0, 36,102,255,102, 36,  0,  0,
             0, 24, 60,126,255,255,  0,  0,  0,255,255,126, 60, 24,  0,  0,
             0,  0,  0,  0,  0,  0,  0,  0, 48,120,120,120, 48,  0, 48,  0,
           108,108,108,  0,  0,  0,  0,  0,108,108,254,108,254,108,108,  0,
            48,124,192,120, 12,248, 48,  0,  0,198,204, 24, 48,102,198,  0,
            56,108, 56,118,220,204,118,  0, 96, 96,192,  0,  0,  0,  0,  0,
            24, 48, 96, 96, 96, 48, 24,  0, 96, 48, 24, 24, 24, 48, 96,  0,
             0,102, 60,255, 60,102,  0,  0,  0, 48, 48,252, 48, 48,  0,  0,
             0,  0,  0,  0,  0, 48, 48, 96,  0,  0,  0,252,  0,  0,  0,  0,
             0,  0,  0,  0,  0, 48, 48,  0,  6, 12, 24, 48, 96,192,128,  0,
           124,198,206,222,246,230,124,  0, 48,112, 48, 48, 48, 48,252,  0,
           120,204, 12, 56, 96,204,252,  0,120,204, 12, 56, 12,204,120,  0,
            28, 60,108,204,254, 12, 30,  0,252,192,248, 12, 12,204,120,  0,
            56, 96,192,248,204,204,120,  0,252,204, 12, 24, 48, 48, 48,  0,
           120,204,204,120,204,204,120,  0,120,204,204,124, 12, 24,112,  0,
             0, 48, 48,  0,  0, 48, 48,  0,  0, 48, 48,  0,  0, 48, 48, 96,
            24, 48, 96,192, 96, 48, 24,  0,  0,  0,252,  0,  0,252,  0,  0,
            96, 48, 24, 12, 24, 48, 96,  0,120,204, 12, 24, 48,  0, 48,  0,
           124,198,222,222,222,192,120,  0, 48,120,204,204,252,204,204,  0,
           252,102,102,124,102,102,252,  0, 60,102,192,192,192,102, 60,  0,
           248,108,102,102,102,108,248,  0,126, 96, 96,120, 96, 96,126,  0,
           126, 96, 96,120, 96, 96, 96,  0, 60,102,192,192,206,102, 62,  0,
           204,204,204,252,204,204,204,  0,120, 48, 48, 48, 48, 48,120,  0,
            30, 12, 12, 12,204,204,120,  0,230,102,108,120,108,102,230,  0,
            96, 96, 96, 96, 96, 96,126,  0,198,238,254,254,214,198,198,  0,
           198,230,246,222,206,198,198,  0, 56,108,198,198,198,108, 56,  0,
           252,102,102,124, 96, 96,240,  0,120,204,204,204,220,120, 28,  0,
           252,102,102,124,108,102,230,  0,120,204,224,112, 28,204,120,  0,
           252, 48, 48, 48, 48, 48, 48,  0,204,204,204,204,204,204,252,  0,
           204,204,204,204,204,120, 48,  0,198,198,198,214,254,238,198,  0,
           198,198,108, 56, 56,108,198,  0,204,204,204,120, 48, 48,120,  0,
           254,  6, 12, 24, 48, 96,254,  0,120, 96, 96, 96, 96, 96,120,  0,
           192, 96, 48, 24, 12,  6,  2,  0,120, 24, 24, 24, 24, 24,120,  0,
            16, 56,108,198,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,255,
            48, 48, 24,  0,  0,  0,  0,  0,  0,  0,120, 12,124,204,118,  0,
           224, 96, 96,124,102,102,220,  0,  0,  0,120,204,192,204,120,  0,
            28, 12, 12,124,204,204,118,  0,  0,  0,120,204,252,192,120,  0,
            56,108, 96,240, 96, 96,240,  0,  0,  0,118,204,204,124, 12,248,
           224, 96,108,118,102,102,230,  0, 48,  0,112, 48, 48, 48,120,  0,
            12,  0, 12, 12, 12,204,204,120,224, 96,102,108,120,108,230,  0,
           112, 48, 48, 48, 48, 48,120,  0,  0,  0,204,254,254,214,198,  0,
             0,  0,248,204,204,204,204,  0,  0,  0,120,204,204,204,120,  0,
             0,  0,220,102,102,124, 96,240,  0,  0,118,204,204,124, 12, 30,
             0,  0,220,118,102, 96,240,  0,  0,  0,124,192,120, 12,248,  0,
            16, 48,124, 48, 48, 52, 24,  0,  0,  0,204,204,204,204,118,  0,
             0,  0,204,204,204,120, 48,  0,  0,  0,198,214,254,254,108,  0,
             0,  0,198,108, 56,108,198,  0,  0,  0,204,204,204,124, 12,248,
             0,  0,252,152, 48,100,252,  0, 28, 48, 48,224, 48, 48, 28,  0,
            24, 24, 24,  0, 24, 24, 24,  0,224, 48, 48, 28, 48, 48,224,  0,
           118,220,  0,  0,  0,  0,  0,  0,  0, 16, 56,108,198,198,254,  0);
var i,j,k,v : byte;
begin
  if sysfont <> NIL then exit;
  if maxavail < sizeof(TFontBuffer) then begin
    InitSysFont:=VGA_NoMemory; exit;
  end;
  new(sysfont);
  for i:=0 to 127 do begin                          { symbol count }
    for j:=0 to 7 do begin                          { byte   count(line) }
      for k:=0 to 7 do begin                        { bit    count(column) }
        {v:=($80 shr k) and (mem[$F000:$FA6E+i*8+j]);}
        v:=($80 shr k) and fs[i*8+j];
        if v > 0 then sysfont^[i*64+j*8+k]:=cf
                 else sysfont^[i*64+j*8+k]:=cb;
      end;
    end;
  end;
  InitSysFont:=VGA_Ok;
end;

Procedure DoneSysFont;
{    Job : deallocate system bitmap font buffer                           }
{  Input : none                                                           }
{ Output : none                                                           }
begin
  if sysfont = NIL then exit;
  dispose(sysfont); sysfont:=NIL;
end;

Procedure TextOut;   { * needs addon clipping * }
{    Job : writing string out to screen/dble-buffer ( without cliping ) }
{  Input : x, y - position of left top corner of string; st - string    }
{ Output : none                                                         }
var size : word; lineptr : pointer;
begin
  if sysfont = NIL then begin exit; end;
  size:=length(st);
  if size = 0 then exit;
  lineptr:=addr(st);
  asm
    push ds
    les di, dbuffer
    mov ax, y
    mov bx, ax             { copy y to bx }
    sal ax, 6              { shift equal mult on 32 }
    sal bx, 8              { shift equal mult on 256 }
    add ax, bx             { equal mult on 320 (with shifts) }
    mov bx, x
    add ax, bx
    add di, ax             { es:di - screen position }
    lds si, sysfont
    mov dx, 1              { current char }
    mov cx, size
    @char:
      push es
      push di
      les di, lineptr
      add di, dx
      inc dx
      xor ax, ax
      mov al, es:[di]
      and al, $7F
      sal ax, 6
      mov bx, ax
      pop di
      pop es
      push cx
      mov cx, 8
        @col:
        push cx
        mov cx, 8
          @row:
          mov al, ds:[si+bx] { ds:si points to 64 bytes of char in font }
          cmp al, 0
          jz @skip_transparent
          mov es:[di], al
          @skip_transparent:
          inc si
        inc di
      loop @row
      pop cx
      add di, 312
    loop @col
    sub di, 2552
    sub si, 64
    pop cx
    loop @char
    pop ds
  end;
end;

{ --------------------------------------------------------------------- }

Function  GetVGAErrorMsg(n:integer):string;
{    Job : return text message of VGA error                             }
{  Input : n - error code                                               }
{ Output : string with error message                                    }
var msg : string;
begin
  case n of
    VGA_Ok         : msg:='No errors';
    VGA_NoMemory   : msg:='Out of memory';
    VGA_IOError    : msg:='IO error';
    VGA_NoFile     : msg:='File not exists';
    VGA_BadVersion : msg:='Version unsupported';
    VGA_BadFormat  : msg:='Incorrect file format';
  else
    msg:='Undefined error';
  end;
  GetVGAErrorMsg:=msg;
end;

Begin
  sysfont:=NIL;
  {$IFDEF DPMI}
    dbuffer:=ptr(SegA000,$0000);
    vbuffer:=ptr(SegA000,$0000);
  {$ELSE}
    dbuffer:=ptr($A000,$0000);
    vbuffer:=ptr($A000,$0000);
  {$ENDIF}
End.

{ ---x---x---x---x---x---x---x--- Cut here ---x---x---x---x---x---x---x--- }

{ Move that part into VB30.ASM and assemble it with TASM  }

.MODEL MEDIUM

EXTRN vbuffer:DWORD
EXTRN dbuffer:DWORD

PUBLIC ClearDBuffer32
PUBLIC ClearVBuffer32
PUBLIC ShowBuffer32

.CODE
.386

ClearDBuffer32 PROC FAR
  cld
  les di, dbuffer
  mov cx, 16000
  xor eax, eax
  rep stosd
  ret
ClearDBuffer32 ENDP

ClearVBuffer32 PROC FAR
  cld
  les di, vbuffer
  mov cx, 16000
  xor eax, eax
  rep stosd
  ret
ClearVBuffer32 ENDP

ShowBuffer32 PROC FAR
  push ds
  cld
  les di, vbuffer
  lds si, dbuffer
  mov cx, 16000
  rep movsd
  pop ds
  ret
ShowBuffer32 ENDP

END

{ End of VB30.ASM file }

{ ---x---x---x---x---x---x---x--- Cut here ---x---x---x---x---x---x---x--- }

{ there are 8x8 chars, image from BIOS first 128 chars           }
{ every char coded by 8 bytes, every bit in byte is point in row }

{   bits : 7 6 5 4 3 2 1 0                                       }
{ byte 0  [#|#|#|#|#|#| | ]  = 1111 1100 = $FC = 252             }
{ byte 1  [ |#|#| | |#|#| ]  = 0110 0110 = $66 = 102             }
{ byte 2  [ |#|#| | |#|#| ]  = 0110 0110 = $66 = 102             }
{ byte 3  [ |#|#|#|#|#| | ]  = 0111 1100 = $7C = 124             }
{ byte 4  [ |#|#| | |#|#| ]  = 0110 0110 = $66 = 102             }
{ byte 5  [ |#|#| | |#|#| ]  = 0110 0110 = $66 = 102             }
{ byte 6  [#|#|#|#|#|#| | ]  = 1111 1100 = $FC = 252             }
{ byte 7  [ | | | | | | | ]  = 0000 0000 = $00 =   0             }

const
  fs : array[0..1023] of byte =
  (  0,  0,  0,  0,  0,  0,  0,  0,126,129,165,129,189,153,129,126,
   126,255,219,255,195,231,255,126,108,254,254,254,124, 56, 16,  0,
    16, 56,124,254,124, 56, 16,  0, 56,124, 56,254,254,124, 56,124,
    16, 16, 56,124,254,124, 56,124,  0,  0, 24, 60, 60, 24,  0,  0,
   255,255,231,195,195,231,255,255,  0, 60,102, 66, 66,102, 60,  0,
   255,195,153,189,189,153,195,255, 15,  7, 15,125,204,204,204,120,
    60,102,102,102, 60, 24,126, 24, 63, 51, 63, 48, 48,112,240,224,
   127, 99,127, 99, 99,103,230,192,153, 90, 60,231,231, 60, 90,153,
   128,224,248,254,248,224,128,  0,  2, 14, 62,254, 62, 14,  2,  0,
    24, 60,126, 24, 24,126, 60, 24,102,102,102,102,102,  0,102,  0,
   127,219,219,123, 27, 27, 27,  0, 62, 99, 56,108,108, 56,204,120,
     0,  0,  0,  0,126,126,126,  0, 24, 60,126, 24,126, 60, 24,255,
    24, 60,126, 24, 24, 24, 24,  0, 24, 24, 24, 24,126, 60, 24,  0,
     0, 24, 12,254, 12, 24,  0,  0,  0, 48, 96,254, 96, 48,  0,  0,
     0,  0,192,192,192,254,  0,  0,  0, 36,102,255,102, 36,  0,  0,
     0, 24, 60,126,255,255,  0,  0,  0,255,255,126, 60, 24,  0,  0,
     0,  0,  0,  0,  0,  0,  0,  0, 48,120,120,120, 48,  0, 48,  0,
   108,108,108,  0,  0,  0,  0,  0,108,108,254,108,254,108,108,  0,
    48,124,192,120, 12,248, 48,  0,  0,198,204, 24, 48,102,198,  0,
    56,108, 56,118,220,204,118,  0, 96, 96,192,  0,  0,  0,  0,  0,
    24, 48, 96, 96, 96, 48, 24,  0, 96, 48, 24, 24, 24, 48, 96,  0,
     0,102, 60,255, 60,102,  0,  0,  0, 48, 48,252, 48, 48,  0,  0,
     0,  0,  0,  0,  0, 48, 48, 96,  0,  0,  0,252,  0,  0,  0,  0,
     0,  0,  0,  0,  0, 48, 48,  0,  6, 12, 24, 48, 96,192,128,  0,
   124,198,206,222,246,230,124,  0, 48,112, 48, 48, 48, 48,252,  0,
   120,204, 12, 56, 96,204,252,  0,120,204, 12, 56, 12,204,120,  0,
    28, 60,108,204,254, 12, 30,  0,252,192,248, 12, 12,204,120,  0,
    56, 96,192,248,204,204,120,  0,252,204, 12, 24, 48, 48, 48,  0,
   120,204,204,120,204,204,120,  0,120,204,204,124, 12, 24,112,  0,
     0, 48, 48,  0,  0, 48, 48,  0,  0, 48, 48,  0,  0, 48, 48, 96,
    24, 48, 96,192, 96, 48, 24,  0,  0,  0,252,  0,  0,252,  0,  0,
    96, 48, 24, 12, 24, 48, 96,  0,120,204, 12, 24, 48,  0, 48,  0,
   124,198,222,222,222,192,120,  0, 48,120,204,204,252,204,204,  0,
   252,102,102,124,102,102,252,  0, 60,102,192,192,192,102, 60,  0,
   248,108,102,102,102,108,248,  0,126, 96, 96,120, 96, 96,126,  0,
   126, 96, 96,120, 96, 96, 96,  0, 60,102,192,192,206,102, 62,  0,
   204,204,204,252,204,204,204,  0,120, 48, 48, 48, 48, 48,120,  0,
    30, 12, 12, 12,204,204,120,  0,230,102,108,120,108,102,230,  0,
    96, 96, 96, 96, 96, 96,126,  0,198,238,254,254,214,198,198,  0,
   198,230,246,222,206,198,198,  0, 56,108,198,198,198,108, 56,  0,
   252,102,102,124, 96, 96,240,  0,120,204,204,204,220,120, 28,  0,
   252,102,102,124,108,102,230,  0,120,204,224,112, 28,204,120,  0,
   252, 48, 48, 48, 48, 48, 48,  0,204,204,204,204,204,204,252,  0,
   204,204,204,204,204,120, 48,  0,198,198,198,214,254,238,198,  0,
   198,198,108, 56, 56,108,198,  0,204,204,204,120, 48, 48,120,  0,
   254,  6, 12, 24, 48, 96,254,  0,120, 96, 96, 96, 96, 96,120,  0,
   192, 96, 48, 24, 12,  6,  2,  0,120, 24, 24, 24, 24, 24,120,  0,
    16, 56,108,198,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,255,
    48, 48, 24,  0,  0,  0,  0,  0,  0,  0,120, 12,124,204,118,  0,
   224, 96, 96,124,102,102,220,  0,  0,  0,120,204,192,204,120,  0,
    28, 12, 12,124,204,204,118,  0,  0,  0,120,204,252,192,120,  0,
    56,108, 96,240, 96, 96,240,  0,  0,  0,118,204,204,124, 12,248,
   224, 96,108,118,102,102,230,  0, 48,  0,112, 48, 48, 48,120,  0,
    12,  0, 12, 12, 12,204,204,120,224, 96,102,108,120,108,230,  0,
   112, 48, 48, 48, 48, 48,120,  0,  0,  0,204,254,254,214,198,  0,
     0,  0,248,204,204,204,204,  0,  0,  0,120,204,204,204,120,  0,
     0,  0,220,102,102,124, 96,240,  0,  0,118,204,204,124, 12, 30,
     0,  0,220,118,102, 96,240,  0,  0,  0,124,192,120, 12,248,  0,
    16, 48,124, 48, 48, 52, 24,  0,  0,  0,204,204,204,204,118,  0,
     0,  0,204,204,204,120, 48,  0,  0,  0,198,214,254,254,108,  0,
     0,  0,198,108, 56,108,198,  0,  0,  0,204,204,204,124, 12,248,
     0,  0,252,152, 48,100,252,  0, 28, 48, 48,224, 48, 48, 28,  0,
    24, 24, 24,  0, 24, 24, 24,  0,224, 48, 48, 28, 48, 48,224,  0,
   118,220,  0,  0,  0,  0,  0,  0,  0, 16, 56,108,198,198,254,  0);

{ End of char fonts }

{ ---x---x---x---x---x---x---x--- Cut here ---x---x---x---x---x---x---x--- }

{ the following contains additional files that should be included with this
  file.  To extract, you need XX3402 available with the SWAG distribution.

  1.     Cut the text below out, and save to a file  ..  filename.xx
  2.     Use XX3402  :   xx3402 d filename.xx
  3.     The decoded file should be created in the same directory.
  4.     If the file is a archive file, use the proper archive program to
         extract the members.

{ ------------------            CUT              ----------------------}

{ ----------------------------  OBJ NEEDED FOR THIS UNIT --------------------- }


*XX3402-000335-170197--72--85-61511--------VB30.OBJ--1-OF--1
U+c+05NWAn+iMLBhl6UU++++53FpQa7j623nQqJhMalZQW+UJaJmQqZjPW+n9X8NW-++ECZ1
crcX05NWAn+iMLBh0cU1+21dH7M0++-cW+A+E84IZV++0JN0An-TJ2JMJ+F1HoF3YtU5+2Uk
++61+SCK1++3LoF-J222F23IEQ8M-k-6+++2-E2DZUU+-YF5IYxJI6iO-++4zk7PX-A+-pN0
JIN4FJ6+-oF0JIN4FJ6+FN+J+++-1YBAFI3GF27JFYN3IXAm++++Ud+J+++-1YBAFI3GJY7J
FYN3IXAm1k++MN+H+++-13B6HpR0JIN4FJ6nAVs++B86-+-+cU4Fc1E++E++zAEy++0tU1ta
Aw1nNej9zAEy++0tU1taAw1nNej95jn2DU++lHM++9a+DjBadFz9StkF+AE1JU922ZM-l07K
+QEaJU86WU6++5E+
***** END OF BLOCK 1 *****


{ ----------------------------  ASM MODULE --------------------- }
.MODEL MEDIUM

EXTRN vbuffer:DWORD
EXTRN dbuffer:DWORD

PUBLIC ClearDBuffer32
PUBLIC ClearVBuffer32
PUBLIC ShowBuffer32

.CODE
.386

ClearDBuffer32 PROC FAR
  cld
  les di, dbuffer
  mov cx, 16000
  xor eax, eax
  rep stosd
  ret
ClearDBuffer32 ENDP

ClearVBuffer32 PROC FAR
  cld
  les di, vbuffer
  mov cx, 16000
  xor eax, eax
  rep stosd
  ret
ClearVBuffer32 ENDP

ShowBuffer32 PROC FAR
  push ds
  cld
  les di, vbuffer
  lds si, dbuffer
  mov cx, 16000
  rep movsd
  pop ds
  ret
ShowBuffer32 ENDP

END