Pascal Vgautil

Vgautil

Unit VgaUtil;

Interface

{$G+,R-}

Uses Crt;

{-$DEFINE CLIPADDPUT}

Const
  Long = $66;
  display1 : word = $0000;
  display2 : word = $4000;

  { Vga card 64k bank select }
  BankOfs : Array[0..3] of Word = (0, $4000, $8000, $A000);
  BankNum : Array[0..3] of Byte = (0, 1, 2, 3);

  Width = 80;
  Numsins = 255;
  HiNumsins = Numsins shl 6;
  Pi = 3.1415;
  MovPut = 0;
  AddPut = 1;
  SubPut = 2;
  AndPut = 3;
  OrPut  = 4;
  XorPut = 5;
  TPut = 6;

Type AnyString = String[127];
     RGB = Record
       r, g, b : Byte;
     End;
     PaletteType = Array[0..255] of RGB;
     P2dType = Record
                 x, y : Integer;
               End;
     P3dType = Record
                 x, y, z : Integer;
               End;
     P2dArray = Array[0..255] of P2dType;
     P3dArray = Array[0..255] of P3dType;

Var
  SinTable,CosTable: Array[0..Numsins] of integer;
  Sin2Table,Cos2Table: Array[0..Numsins] of integer;
  PageOffset : Word;
  OldScreenMode, CurPage : Byte;
  VLU : array[0..199] of word;
  OldExitProc : pointer;
  Pal : PaletteType;

{ For procedure comments you will have to hunt around, sorry... }

Procedure CalcSine;
Procedure CalcVLU;
Procedure SetGraphicsMode(Mode : Byte);
Procedure RefreshWait;
Procedure SetSingleColor(Var TPal : PaletteType; Col, R, G, B : Byte);
Procedure SetRGB(ColNum, R, G, B : Byte);
Procedure SetSPalette(Palette : PaletteType);
Procedure Fadepals(Startpal, Endpal : Palettetype; Steps : Integer);
Procedure Fadepalsstep(Startpal, Endpal : Palettetype; TotalSteps, CurStep : Integer);
Procedure GraphCLS;
Procedure VgaGetPic(x1, y1, x2, y2 : Integer; DestPtr : Pointer);
Procedure OldVgaPutPic(Mode : Byte; x1, y1: Integer; SrcPtr, DestPtr
 : Pointer);

Procedure VGAClipPic(Mode : Byte; X1, Y1, XClip, YClip : Integer;
 SrcPtr, DestPtr : Pointer);
Procedure VGAPutPic(Mode : Byte; X1, Y1 : Integer; SrcPtr, DestPtr :
 Pointer);
Procedure RestoreBackground(X1, Y1, XSize, YSize : Integer; SrcPtr,
 DestPtr : Pointer);
Procedure RestoreBackgroundVertical(Y1, Y2 : Integer; SrcPtr,
 DestPtr : Pointer);
Procedure LoadPcx(FileName : AnyString; Var TPal : PaletteType; Orig
 : Pointer);
Procedure LoadPcxPalette(FileName : AnyString; Var TPal :
 PaletteType);
Procedure ClearPage(P : Pointer);
Procedure CopyPage(P : Pointer);
Procedure CopyPageOffset(P : Pointer; POffset : Word);
Procedure Copy2Pages(SrcP, DestP : Pointer);
Procedure SetStart(p:word);
Procedure SetBank(bank:byte);
Procedure Vgaline(const x1,y1,x2,y2,where:word;const c:byte);

function LongDiv(x : longint; y : integer) : integer;
inline($59/$58/$5A/$F7/$F9);
function LongMul(x, y : integer) : longint;
inline($5A/$58/$F7/$EA);
procedure SetBitplanes(planes : byte);
inline(
       $BA/$C4/$03/    {mov    dx,$3C4}
       $58/                            {pop    ax}
       $88/$C4/                        {mov    ah,al}
       $B0/$02/                        {mov    al,$02}
       $EF);                           {out    dx,ax}

Implementation

procedure CLI; inline($FA);
procedure STI; inline($FB);

Procedure CalcSine;                   {Creates sin/cos tables}
Var direction:integer;
    angle:real;
begin
     For Direction:=0 to Numsins do begin   {use 256 degrees in
 circle}
         angle:=Direction;
         angle:=angle*3.14159265/128;
         SinTable[Direction]:=round(Sin(angle)*256);
         CosTable[Direction]:=round(Cos(angle)*256);

 Sin2Table[Direction]:=round(Sin(angle+3.14159265/2)*256*1.2);

 Cos2Table[Direction]:=round(Cos(angle+3.14159265/2)*256*1.2);
     end;                 { the 1.2 accounts for pixel aspect ratio }
end;

{ Makes an array that speeds up pixel offset calculations }
{ Use like this...
  Mov bx, (Y value here)
  Shl bx, 1
  Mov di, Word Ptr Vlu[bx]
  Add di, (X value here)

  DI now holds proper offset.


>> CONTINUED IN NEXT MESSAGE <<
================================================================================
 Area:    PASCAL
 Date:    24 Jul 96  21:11:56  Public
 From:    Ryan Stowers
 To:      All
 Subject: HERE IT IS FINALLY!!!!!!!!!!                             [2]
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
>> CONTINUED FROM PREVIOUS MESSAGE <<


  VERY fast!!!
}

Procedure CalcVlu;

  Var
    A : Integer;

  Begin
    For a := 0 to 199 do
      Vlu[A] := A * 320;
  End;

{ Works for any graphics mode }
Procedure SetGraphicsMode(Mode : Byte); Assembler;

  asm
    Mov al, Mode
    Xor ah, ah
    Int 10H
  end;

{ One of Bjarke's routines }

{$F+}
procedure ScreenExitProc;
{$F-}
begin
  ExitProc := OldExitProc;
  If (ExitCode <> 0) then
    Begin
      SetGraphicsMode($03); {if runtime error, restore screen}
      Writeln('Mega screw up error #',ExitCode);
    End;
end;

{ Wait for vertical retrace }
Procedure RefreshWait; Assembler;

  Asm
    Mov  dx,$3da
   @Looper:
    In   al,dx
    And  al,8
    Jz  @Looper
  End;

Procedure SetSingleColor(Var TPal : PaletteType; Col, R, G, B :
 Byte);

  Begin
    Pal[Col].r := R;
    Pal[Col].g := G;
    Pal[Col].b := B;
  End;

{ One of Bjarke's routines.  Very useful. }
Procedure SetRGB(ColNum, R, G, B : Byte); assembler;

  Asm
    Mov  dx, $3c8
    Mov  al, ColNum
    Out  dx, al
    Inc  dx

    Mov  al, R
    Out  dx, al
    Mov  al, G
    Out  dx, al
    Mov  al, B
    Out  dx, al
  End;

{ One of Bjarke's routines, but i modified it to use a static array
 insted
  of a pointer.  }
Procedure SetSPalette(Palette : PaletteType);

Var
  Count : Integer;

Begin
  Asm
    Mov  dx,$3c8
    Xor  al,al
    Out  dx,al
    Inc  dx
    Mov  si,0
    Mov  cx,768

    @Looper:
      Mov  al,Byte Ptr [Palette+si]
      Out  dx,al
      Inc  si
      Dec  cx
      Jnz @Looper
  End;

End;
Procedure Fadepals(Startpal, Endpal : Palettetype; Steps : Integer);

  Var
    Temppal : PaletteType;
    MCount, PCount : Integer;

  Begin
    For MCount := Steps downto 0 do
      Begin
        For PCount := 0 to 255 do
          Begin
            Temppal[PCount].r := ((startpal[PCount].r * MCount) div
 Steps)+
                                 ((endpal[PCount].r *
 (Steps-MCount)) div Steps);
            Temppal[PCount].g := ((startpal[PCount].g * MCount) div
 Steps)+
                                 ((endpal[PCount].g *
 (Steps-MCount)) div Steps);
            Temppal[PCount].b := ((startpal[PCount].b * MCount) div
 Steps)+
                                 ((endpal[PCount].b *
 (Steps-MCount)) div Steps);
          End;
        SetSpalette(Temppal);
        RefreshWait;
      end;
    SetSPalette(Endpal);
  End;

Procedure Fadepalsstep(Startpal, Endpal : Palettetype; TotalSteps,
 CurStep : Integer);

  Var
    Temppal : PaletteType;
    PCount : Integer;

  Begin
    For PCount := 0 to 255 do
      Begin
        SetRGB(PCount,
               ((startpal[PCount].r * CurStep) div TotalSteps)+
               ((endpal[PCount].r * (TotalSteps-CurStep)) div
 TotalSteps),
               ((startpal[PCount].g * CurStep) div TotalSteps)+
               ((endpal[PCount].g * (TotalSteps-CurStep)) div
 TotalSteps),
               ((startpal[PCount].b * CurStep) div TotalSteps)+
               ((endpal[PCount].b * (TotalSteps-CurStep)) div
 TotalSteps));
      End;
  End;

{ Ummm..... What does this procedure do... }
Procedure GraphCLS;

  Begin
    Fillchar(Mem[Sega000:0], 64000, 0);
  End;

{ Just like GET in BASIC for grabbing screen images, but you dont
 need a
{ static array like in BASIC. Just use a pointer }
{ NOT optimized, but works. Just make sure you used GETMEM with
 DestPtr.}
{ x1,y1,x2,y2 = Coordinates of the screen you want to get }

Procedure VgaGetPic(x1, y1, x2, y2 : Integer; DestPtr : Pointer);

Var
  VCount, HCount, DestSeg, DestOfs, CurOfs, W, H :Integer;

Begin
  DestSeg := Seg(DestPtr^);
  DestOfs := Ofs(DestPtr^);
  W := (x2 - x1);
  H := (y2 - y1);

  CurOfs := 0;
  MemW[DestSeg:DestOfs + CurOfs] := W;
  Inc(CurOfs,2);
  MemW[DestSeg:DestOfs + CurOfs] := H;
  Inc(CurOfs,2);

  For VCount := y1 to y2 do
    Begin
      For HCount := x1 to x2 do
        Begin
          Mem[DestSeg:DestOfs + CurOfs] := Mem[$a000:HCount + VCount
 * 320];
          Inc(CurOfs);
        End;
    End;
End;

{ Just like PUT in BASIC for putting images on the screen.  Im
 pretty sure
  this one does all the clipping you need, but its older and slower
 than
  the newer one (look below)
  Mode = Use one of the constants for MOV, ADD, SUB, etc, etc
  x1,y1 = coordinates
  SrcPtr = source bitmap
  DestPtr = destination bitmap can be either direct video or a
 virtual page
}

Procedure OldVgaPutPic(Mode : Byte; x1, y1: Integer; SrcPtr, DestPtr
 : Pointer);

Var DestSeg, Bytes, WordsLeft, BytesLeft : Word;
    DestStartx, DestStarty, XWriteLen, YWriteLen, SrcOfs : Integer;
    PicW, PicH, DestStartYOfs, StartYOfs, DestXerror, Xerror, Tilt :
 Integer;

Begin
  PicW := MemW[Seg(SrcPtr^):Ofs(SrcPtr^) + 0] + 1;
  PicH := MemW[Seg(SrcPtr^):Ofs(SrcPtr^) + 2] + 1;
  If X1 > 319 then exit;
  If Y1 > 199 then Exit;
  If X1 < -PicW then exit;
  If Y1 < -PicH then exit;
  SrcOfs := Ofs(SrcPtr^);

  Asm
    Mov Tilt, 0

    Mov ax, 16
    Sub ax, PicW
    Mov Xerror, 0        { Xerror := (16 - PicW)}
    Mov ax, X1           { DestStartX := X1 }
    Mov DestStartx, ax

    Mov ax, Y1           { DestStarty := Y1 }
    Mov DestStartY, ax

    Mov ax, PicW         { XWriteLen := PicW }
    Mov XWriteLen, ax

    Mov ax, PicH         { YWriteLen := PicH }
    Mov YWriteLen, ax

    Mov StartYOfs, 4

    Cmp Y1, 0            { If Y1 < 0 then }
    Jg @SkipY11
      Mov ax, PicH
      Add ax, Y1
      Mov YWriteLen, ax

      Mov DestStartY, 0  { DestStartY := 0 }

      Mov ax, Y1         { StartYOfs := StartYOfs + Abs(y1) * PicW }
      Not ax
      Add ax, 1
      Mul PicW
      Add StartYOfs, ax
    @SkipY11:
  Mov ax, Y1             { If (Y1 + YWriteLen) > 199 then }
  Add ax, YWriteLen
  Cmp ax, 199
  Jl @SkipY12
    Mov ax, 200          { YWriteLen := 200 - Y1 }
    Sub ax, Y1
    Mov YWriteLen, ax
  @SkipY12:

  Cmp X1, 0              { If X < 0 then }
  Jg @SkipX11
    Mov ax, X1           { Xerror := Abs(X1) }
    Not ax
    add ax, 1
    Mov Xerror, ax

    Mov ax, X1           { XWriteLen := XWriteLen + X1 }
    Add XWriteLen, ax

    Mov ax, Xerror       { StartYofs := StartYOfs + Xerror }
    Add StartYOfs, ax

    Mov DestStartX, 0    { DestStartX := 0 }
  @SkipX11:

  Mov ax, X1             { If (X1 + XWriteLen) > 319 then }
  Add ax, XWriteLen
  Cmp ax, 319
  Jl @SkipX12
    Mov ax, 320          { XWriteLen := 320 - X1 }
    Sub ax, X1
    Mov XWriteLen, ax

    Mov ax, 320          { Xerror := X1 - (320 - PicW) }
    Sub ax, PicW
    Mov bx, X1
    Sub bx, ax
    Mov Xerror, bx
  @SkipX12:

  Cmp XWriteLen, 0
  Jg @Oops1
    Mov Tilt, 1
  @Oops1:
  Cmp YWriteLen, 0
  Jg @Oops2
    Mov Tilt, 1
  @Oops2:

  { Dest start coordinates computer }
  Mov  ax, DestStartY      { Y coordinate }
  Mov  bx, ax
  Shl  ax, 6
  Add  ah, bl
  Add  ax, DestStartX      { X coordinate }
  Mov  DestStartYOfs, ax

  Mov  ax, 320             { DestXError := 320 - XwriteLen }
  Sub  ax, XwriteLen
  Mov  DestXError, ax
  End;
  If Tilt <> 0 Then Exit;

  Case Mode of
   { MOV }
   0:Begin
       Bytes := Word(XWriteLen div 4);
       WordsLeft := (Xwritelen mod 4) and 2;
       BytesLeft := (Xwritelen mod 4) and 1;
       If DestPtr = Nil then
         DestSeg := $a000
        else
         DestSeg := Seg(DestPtr^);
       Asm
        Mov ax, 0 {Y Loop Count}

         Mov es, DestSeg {Dest segment }
         Mov si, StartYOfs {Src offset}
         Mov di, DestStartYOfs {Dest offset}

         Push ds {Save ds}
         Lds cx, SrcPtr {Load SrcPtr into ds}

         @YLooper:

           db 66h; Mov   cx, Bytes; { Move double words at one to
 increase speed }
           db 66h; Rep Movsw

           Mov cx, WordsLeft
           Jcxz @SkipZero1
             Movsw
           @SkipZero1:
           Mov cx, BytesLeft
           Jcxz @SkipZero2
             Movsb
           @SkipZero2:

           Add si, XError {Fix offscreen clipping errors}
           Add di, DestXError

         Inc Ax {Increment Ax}
         Cmp ax, YWriteLen {If ax < YWritelen then.. }
         Jl @YLooper {Goto @YLooper}

         Pop Ds {All done, restore ds to prevent stack errors}
      End;
    End;
   { Addition PUT }
   1:Begin
       If DestPtr = Nil then
         DestSeg := $a000
        else
         DestSeg := Seg(DestPtr^);
       Asm
         Mov ax, 0 {Init Y Count }

         Mov es, DestSeg { Init dest segment }
         Mov si, StartYOfs { Init source offset }
         Mov di, DestStartYOfs

         {Get source segment and figure source start coordinates}
         Push Ds
         Lds cx, SrcPtr {Load SrcPtr into ds}

         @YLooper:

           { Loop length computer }
           Mov  cx, XWriteLen

           Shr  cx,1
           Jnc @SkipSingle
             Mov dl, es:[di]
             Add dl, ds:[si]
             Mov es:[di], dl
             Inc di; Inc si
           @SkipSingle:
             Jcxz @Exit
           @XLooper:
             Mov dl, es:[di]
             Add dl, ds:[si]
             Mov dh, es:[di+1]
             Add dh, ds:[si+1]

             Mov es:[di], dx
             Add si, 2; Add di, 2
           Loop @XLooper

        @Exit:
        Add si, XError {Fix offscreen clipping errors}
        Add di, DestXError

        Inc Ax  {Increment ax counter}
        Cmp ax, YWriteLen {If y < YWriteLen then... }
        Jl @YLooper {Goto YLooper}

        Pop Ds { All done, restore Ds to prevent stack errors }
      End;
    End;
   { Subtraction PUT }
   2:Begin
       If DestPtr = Nil then
         DestSeg := $a000
        else
         DestSeg := Seg(DestPtr^);
       Asm
         Mov ax, 0 {Init Y Count }

         Mov es, DestSeg { Init dest segment }
         Mov si, StartYOfs { Init source offset }
         Mov di, DestStartYofs

         {Get source segment and figure source start coordinates}
         Push Ds
         Lds cx, SrcPtr {Load SrcPtr into ds}

         @YLooper:

           { Loop length computer }
           Mov  cx, XWriteLen
           Shr  cx,1
           Jnc @SkipSingle
             Mov dl, es:[di]
             Sub dl, ds:[si]
             Mov es:[di], dl
             Inc di; Inc si
           @SkipSingle:
             Jcxz @Exit
           @XLooper:
             Mov dl, es:[di]
             Sub dl, ds:[si]
             Mov dh, es:[di+1]
             Sub dh, ds:[si+1]

             Mov es:[di], dx
             Add si, 2; Add di, 2
           Loop @XLooper

        @Exit:
        Add si, XError {Fix offscreen clipping errors}
        Add di, DestXerror

        Inc Ax  {Increment ax counter}
        Cmp ax, YWriteLen {If y < YWriteLen then... }
        Jl @YLooper {Goto YLooper}

        Pop Ds { All done, restore Ds to prevent stack errors }
      End;
    End;
   { XOR PUT }
   3:Begin
       If DestPtr = Nil then
         DestSeg := $a000
        else
         DestSeg := Seg(DestPtr^);
       Asm
         Mov ax, 0 {Init Y Count }

         Mov es, DestSeg { Init dest segment }
         Mov si, StartYOfs { Init source offset }
         Mov di, DestStartYofs

         {Get source segment and figure source start coordinates}
         Push Ds
         Lds cx, SrcPtr {Load SrcPtr into ds}

         @YLooper:

           { Loop length computer }
           Mov  cx, XWriteLen
           Shr  cx,1
           Jnc @SkipSingle
             Mov dl, es:[di]
             Xor dl, ds:[si]
             Mov es:[di], dl
             Inc di; Inc si
           @SkipSingle:
             Jcxz @Exit
           @XLooper:
             Mov dl, es:[di]
             Xor dl, ds:[si]
             Mov dh, es:[di+1]
             Xor dh, ds:[si+1]

             Mov es:[di], dx
             Add si, 2; Add di, 2
           Loop @XLooper

        @Exit:
        Add si, XError {Fix offscreen clipping errors}
        Add di, DestXError

        Inc Ax  {Increment ax counter}
        Cmp ax, YWriteLen {If y < YWriteLen then... }
        Jl @YLooper {Goto YLooper}

        Pop Ds { All done, restore Ds to prevent stack errors }
      End;
    End;
   { AND PUT }
   4:Begin
       If DestPtr = Nil then
         DestSeg := $a000
        else
         DestSeg := Seg(DestPtr^);
       Asm
         Mov ax, 0 {Init Y Count }

         Mov es, DestSeg { Init dest segment }
         Mov si, StartYOfs { Init source offset }
         Mov di, DestStartYofs

         {Get source segment and figure source start coordinates}
         Push Ds
         Lds cx, SrcPtr {Load SrcPtr into ds}

         @YLooper:

           { Loop length computer }
           Mov  cx, XWriteLen
           Shr  cx,1
           Jnc @SkipSingle
             Mov dl, es:[di]
             And dl, ds:[si]
             Mov es:[di], dl
             Inc di; Inc si
           @SkipSingle:
             Jcxz @Exit
           @XLooper:
             Mov dl, es:[di]
             And dl, ds:[si]
             Mov dh, es:[di+1]
             And dh, ds:[si+1]

             Mov es:[di], dx
             Add si, 2; Add di, 2
           Loop @XLooper

        @Exit:
        Add si, XError {Fix offscreen clipping errors}
        Add di, DestXError

        Inc Ax  {Increment ax counter}
        Cmp ax, YWriteLen {If y < YWriteLen then... }
        Jl @YLooper {Goto YLooper}

        Pop Ds { All done, restore Ds to prevent stack errors }
      End;
    End;
   { NOT PUT - This is good for some strange effects if used
 correctly }
   5:Begin
       If DestPtr = Nil then
         DestSeg := $a000
        else
         DestSeg := Seg(DestPtr^);
       Asm
         Mov ax, 0 {Init Y Count }

         Mov es, DestSeg { Init dest segment }
         Mov si, StartYOfs { Init source offset }
         Mov di, DestStartYofs

         {Get source segment and figure source start coordinates}
         Push Ds
         Lds cx, SrcPtr {Load SrcPtr into ds}

         @YLooper:

           { Loop length computer }
           Mov  cx, XWriteLen
           Shr  cx,1
           Jnc @SkipSingle
             Mov dl, es:[di]
             Add dl, ds:[si]; Not dl
             Mov es:[di], dl
             Inc di; Inc si
           @SkipSingle:
             Jcxz @Exit
           @XLooper:
             Mov dl, es:[di]
             Add dl, ds:[si]; Not dl
             Mov dh, es:[di+1]
             Add dh, ds:[si+1]; Not dh

             Mov es:[di], dx
             Add si, 2; Add di, 2
           Loop @XLooper

        @Exit:
        Add si, XError {Fix offscreen clipping errors}
        Add di, DestXerror

        Inc Ax  {Increment ax counter}
        Cmp ax, YWriteLen {If y < YWriteLen then... }
        Jl @YLooper {Goto YLooper}

        Pop Ds { All done, restore Ds to prevent stack errors }
      End;
    End;
   { Transparent MOV }
   6:Begin
       If DestPtr = Nil then
         DestSeg := $a000
        else
         DestSeg := Seg(DestPtr^);
       Asm
         Mov ax, 0 {Init Y Count }

         Mov es, DestSeg { Init dest segment }
         Mov si, StartYOfs { Init source offset }
         Mov di, DestStartYOfs

         {Get source segment and figure source start coordinates}
         Push Ds
         Lds cx, SrcPtr {Load SrcPtr into ds}

         @YLooper:

           { Loop length computer }
           Mov  cx, XWriteLen
           Shr  cx,1
           Jnc @SkipSingle
             Mov dl, ds:[si]
             Or dl, dl
             Jz @SkipZero1
               Mov es:[di], dl
             @SkipZero1:
             Inc di; Inc si
           @SkipSingle:
             Jcxz @Exit
           @XLooper:
             Mov dx, ds:[si]

             Or dl, dl
             Jnz @SkipZero2
               Mov dl, es:[di]
             @SkipZero2:

             Or dh, dh
             Jnz @SkipZero3
               Mov dh, es:[di+1]
             @SkipZero3:
             Mov es:[di], dx
             Add si, 2; Add di, 2
           Loop @XLooper

        @Exit:
        Add si, XError {Fix offscreen clipping errors}
        Add di, DestXerror

        Inc Ax  {Increment ax counter}
        Cmp ax, YWriteLen {If y < YWriteLen then... }
        Jl @YLooper {Goto YLooper}

        Pop Ds { All done, restore Ds to prevent stack errors }
      End;
    End;
  End; {Case}
End;

{ Same thing as OldVGAPutPic, this one (sort of) clips. Clipping not
 quite
  finished yet. Use this PUTPIC only if you know that a bitmap will
 go off
  screen. Routines are quicker (i think?) since I tried to use less
 local
  variables and more registers
  Mode = Use predefined constants from the top of the program
  X1 = X position of picture
  Y1 = Y position of picture

  Next two are user clip functions! I found this useful in
 displaying a fuse
  that is burning it self down (i.e. show less and less of the fuse
 as time
  goes on)

  XClip = Number of pixels to clip from X size
  YClip = Number of pixels to clip from Y size
  SrcPtr, DestPtr = Source and destination virtual pages }

Procedure VGAClipPic(Mode : Byte; X1, Y1, XClip, YClip : Integer;
 SrcPtr, DestPtr : Pointer);

  Label _StopDraw;
  Var OutSeg, YSize, XSize, YOfs, XDiff, XSiDiff : Word;

  Begin
    If DestPtr = Nil then OutSeg := SegA000 else OutSeg :=
 Seg(DestPtr^);
    If XClip < 0 then XClip := 0;
    If YClip < 0 then YClip := 0;
    Asm
      { ----- Determine start adress ----- }

      Mov XSiDiff, 0
      Mov bx, Y1; Shl bx, 1;
      Mov ax, Word Ptr [Vlu+bx]; Mov Yofs, ax

      { ----- Load X and Y sizes ----- }

      Les di, SrcPtr
      Mov ax, es:[di]; Inc ax;
      Mov XSize, ax
      Mov bx, 320; Sub bx, XSize; Mov XDiff, bx

      Mov ax, es:[di+2]; Inc ax
      Mov YSize, ax

      Mov ax, OutSeg
      Mov es, ax

      { ----- Range checking ----- }
      Cmp Y1, 200
      Jae _StopDraw
      Cmp X1, 320
      Jae _StopDraw

      { ----- Clipping routines ----- }
      Mov dx, 200; Sub dx, YSize
      Cmp Y1, dx
      Jbe @SkipMaxY
        Mov ax, Y1
        Sub ax, dx
        Sub YSize, ax
      @SkipMaxY:

      Mov dx, 320; Sub dx, XSize
      Cmp X1, dx
      Jbe @SkipMaxX
        Mov ax, X1
        Sub ax, dx
        Sub XSize, ax
        Add XDiff, ax
        Mov XSiDiff, ax
      @SkipMaxX:

      { ----- User clip. sometimes VERY useful! ----- }
      Mov ax, XClip
      Sub XSize, ax
      Add XDiff, ax
      Add XSiDiff, ax

      Mov ax, YClip
      Sub YSize, ax

      { ----- if we aint even gonna see a sprite, exit for godsake!
 ----- }

      Mov ax, XSize
      And ax, ax
      Js _StopDraw
      And ax, ax
      Jz _StopDraw

      Mov ax, YSize
      And ax, ax
      Js _StopDraw
      And ax, ax
      Jz _StopDraw

      { ----- Misc stuff ----- }

      Mov di, Yofs
      Add di, X1

      @Stop:
    End;
    Case Mode of
      { ----- MOV PUT ----- }
      0: Asm
           Push ds
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           Cld
           @YLooper:

             Push cx
             Mov cx, XSize;

             Shr cx, 1
             Jnc @SkipSingleByte
               Movsb
             @SkipSingleByte:
             Jcxz @Exit

             Shr cx, 1
             Jnc @SkipSingleWord
               Movsw
             @SkipSingleWord:
             Jcxz @Exit

             Db 66h; Rep Movsw

             @Exit:
             Add di, XDiff
             Add si, XSiDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- ADD PUT ----- }
      1: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               Add al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov ax, [ds:si]
               Mov bx, [es:di]

               Add al, bl;
               {$IFDEF CLIPADDPUT}
               Jnc @ResetAL
                 Mov al, 255;
               @ResetAL:
               {$ENDIF}

               Add ah, bh;
               {$IFDEF CLIPADDPUT}
               Jnc @ResetAH
                 Mov ah, 255;
               @ResetAH:
               {$ENDIF}

               Mov [es:di], ax; Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff
             Add si, XSiDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- SUB PUT ----- }
      2: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               Sub al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov bx, [es:di]
               Mov ax, [ds:si]
               Sub al, bl; Sub ah, bh
               Mov [es:di], ax; Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff
             Add si, XSiDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- AND PUT ----- }
      3: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4
           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               And al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov bx, [es:di]
               Mov ax, [ds:si]
               And al, bl; And ah, bh
               Mov [es:di], ax; Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff
             Add si, XSiDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- OR PUT ----- }
      4: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               Or al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov bx, [es:di]
               Mov ax, [ds:si]

               Or al, bl; Or ah, bh

               Mov [es:di], ax
               Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff
             Add si, XSiDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- XOR PUT ----- }
      5: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               Xor al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov bx, [es:di]
               Mov ax, [ds:si]
               Xor al, bl; Xor ah, bh
               Mov [es:di], ax; Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff
             Add si, XSiDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- TRANSPARENT PUT ----- }
      6: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @TSkipSingle
               Mov al, [ds:si]
               Or al, al
               Jz @TSkipZeroB
                 Mov [es:di], al
               @TSkipZeroB:
               Inc di; Inc si
             @TSkipSingle:
               Jcxz @TExit
             @XLooper:
               Mov ax, [ds:si];

               Or al, al
               Je @TSkipZeroWL
                 Mov [es:di], al
               @TSkipZeroWL:
               Or ah, ah
               Je @TSkipZeroWH
                 Mov [es:di+1], ah
               @TSkipZeroWH:

               Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @TExit:
             Add di, XDiff
             Add si, XSiDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
    End;
    _StopDraw:;
  End;

{ DOES NOT CLIP AT ALL! Just does renage checking.  Use this for
 faster
  PUTs if your bitmap will stay within the screen boundaries }

Procedure VGAPutPic(Mode : Byte; X1, Y1 : Integer; SrcPtr, DestPtr :
 Pointer);

  Label _StopDraw;
  Var OutSeg, YSize, XSize, YOfs, XDiff : Word;

  Begin
    If DestPtr = Nil then OutSeg := SegA000 else OutSeg :=
 Seg(DestPtr^);
    Asm
      { ----- Determine start adress ----- }

      Mov bx, Y1; Shl bx, 1;
      Mov ax, Word Ptr [Vlu+bx]; Mov Yofs, ax

      { ----- Load X and Y sizes ----- }

      Les di, SrcPtr
      Mov ax, es:[di]; Inc ax;
      Mov XSize, ax
      Mov bx, 320; Sub bx, XSize; Mov XDiff, bx

      Mov ax, es:[di+2]; Inc ax
      Mov YSize, ax

      Mov ax, OutSeg
      Mov es, ax

      { ----- Range checking ----- }

      { Upper limit check (down and right) }
      Mov ax, Y1
      Add ax, YSize
      Cmp ax, 200
      Jae _StopDraw

      Mov ax, X1
      Add ax, XSize
      Cmp ax, 320
      Jae _StopDraw

      { Lower limit (up and left) }
      Mov ax, Y1
      Cmp ax, 200
      Jae _StopDraw

      Mov ax, X1
      Cmp ax, 320
      Jae _StopDraw

      { No clipping routines here!!! }

      { ----- Misc stuff ----- }

      Mov di, Yofs
      Add di, X1

      @Stop:
    End;
    Case Mode of
      { ----- MOV PUT ----- }
      0: Asm
           Push ds
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           Cld
           @YLooper:

             Push cx
             Mov cx, XSize;

             Shr cx, 1
             Jnc @SkipSingleByte
               Movsb
             @SkipSingleByte:
             Jcxz @Exit

             Shr cx, 1
             Jnc @SkipSingleWord
               Movsw
             @SkipSingleWord:
             Jcxz @Exit

             Db 66h; Rep Movsw

             @Exit:
             Add di, XDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- ADD PUT ----- }
      1: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               Add al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov ax, [ds:si]
               Mov bx, [es:di]

               Add al, bl;
               {$IFDEF CLIPADDPUT}
               Jnc @ResetAL
                 Mov al, 255;
               @ResetAL:
               {$ENDIF}

               Add ah, bh;
               {$IFDEF CLIPADDPUT}
               Jnc @ResetAH
                 Mov ah, 255;
               @ResetAH:


>> CONTINUED IN NEXT MESSAGE <<
================================================================================
 Area:    PASCAL
 Date:    24 Jul 96  21:14:55  Public           
 From:    Ryan Stowers                                      
 To:      All                                               
 Subject: VGAUTIL 4/7                                              [2]
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
>> CONTINUED FROM PREVIOUS MESSAGE <<

               {$ENDIF}

               Mov [es:di], ax; Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff

             Pop cx
             Dec cx
             Jnz @YLooper
           Pop ds
         End;
      { ----- SUB PUT ----- }
      2: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               Sub al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov bx, [es:di]
               Mov ax, [ds:si]
               Sub al, bl; Sub ah, bh
               Mov [es:di], ax; Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- AND PUT ----- }
      3: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               And al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov bx, [es:di]
               Mov ax, [ds:si]
               And al, bl; And ah, bh
               Mov [es:di], ax; Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- OR PUT ----- }
      4: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               Or al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov bx, [es:di]
               Mov ax, [ds:si]

               Or al, bl; Or ah, bh

               Mov [es:di], ax
               Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- XOR PUT ----- }
      5: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @SkipSingle
               Mov bl, [es:di]
               Mov al, [ds:si]
               Xor al, bl;
               Mov [es:di], al; Inc di; Inc si
             @SkipSingle:
               Jcxz @Exit
             @XLooper:
               Mov bx, [es:di]
               Mov ax, [ds:si]
               Xor al, bl; Xor ah, bh
               Mov [es:di], ax; Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @Exit:
             Add di, XDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
      { ----- TRANSPARENT PUT ----- }
      6: Asm
           Push ds
           Cld
           Lds si, SrcPtr; Add si, 4

           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1
             Jnc @TSkipSingle
               Mov al, [ds:si]
               Or al, al
               Jz @TSkipZeroB
                 Mov [es:di], al
                 Inc di; Inc si
               @TSkipZeroB:
             @TSkipSingle:
               Jcxz @TExit
             @XLooper:
               Mov ax, [ds:si];

               Or al, al
               Je @TSkipZeroWL
                 Mov [es:di], al
               @TSkipZeroWL:
               Or ah, ah
               Je @TSkipZeroWH
                 Mov [es:di+1], ah
               @TSkipZeroWH:

               Add di, 2; Add si, 2
               Dec cx
             Jnz @XLooper

             @TExit:
             Add di, XDiff

             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
         End;
    End;
    _StopDraw:;
  End;

{ The next two procedures are used for restoring backgrounds in my
 sprite
  and vector routines.  Ask me and ill give them to you }
{ RestoreBackgoround aint really that fast. It would be more useful
 in mode-x
  sprite programming }

Procedure RestoreBackground(X1, Y1, XSize, YSize : Integer; SrcPtr,
 DestPtr : Pointer);

  Label _TotalExit;
  Var OutSeg, YOfs, XDiff : Word;

  Begin
    If DestPtr = Nil then OutSeg := $A000 else OutSeg :=
 Seg(DestPtr^);
    Asm
      { ----- Determine starting offset ----- }

      Mov bx, Y1; Shl bx, 1;
      Mov ax, Word Ptr [Vlu+bx]; Mov Yofs, ax

      Mov ax, OutSeg
      Mov es, ax

      Mov bx, 320; Sub bx, XSize; Mov XDiff, bx
      Mov dx, 320; Sub dx, XSize

      { ----- Range checking ----- }
      Mov ax, Y1;  Add ax, Xsize
      Cmp ax, 199
      Jae @Stop
      Mov ax, X1;  Add ax, Ysize
      Cmp ax, 319
      Jae @Stop

      { ----- Clipping Routines ----- }

      Mov dx, 200; Sub dx, YSize
      Cmp Y1, dx
      Jbe @SkipMaxY
        Mov ax, Y1
        Sub ax, dx
        Sub YSize, ax
      @SkipMaxY:

      Mov dx, 320; Sub dx, XSize
      Cmp X1, dx
      Jbe @SkipMaxX
        Mov ax, X1
        Sub ax, dx
        Sub XSize, ax
        Add XDiff, ax
      @SkipMaxX:

      Mov di, Yofs
      Add di, X1

           { ----- draw the sucker ----- }
           Push ds
           Lds si, SrcPtr;
           Mov si, Yofs; Add si, X1

           Cld
           Mov cx, YSize
           @YLooper:

             Push cx
             Mov cx, XSize;
             Shr cx, 1

             Jnc @SkipSingle
               Movsb
             @SkipSingle:
               Jcxz @Exit
             Rep Movsw

             @Exit:
             Add di, XDiff
             Add si, XDiff
             Pop cx
             Dec cx
             Jnz @YLooper

           Pop ds
      @Stop:
    End;
  End;

{ This one is really fast (386 instr). Y1 is the top line of SrcPtr
 and Y2
  is the bottom line of ScrPtr to copy to DestPtr }

Procedure RestoreBackgroundVertical(Y1, Y2 : Integer; SrcPtr,
 DestPtr : Pointer);

  Var Bytes, StartOfs : Word;
      Tmp : Integer;

  Begin
    If Y1 > Y2 then
      Begin
        Tmp := Y1;
        Y1 := Y2;
        Y2 := Tmp;
      End;
    If Y1 < 0 then Y1 := 0;
    If Y2 > 199 then Y2 := 199;
    Bytes := (Y2-Y1) * 80;
    If Bytes = 0 then Exit;
    StartOfs := Vlu[Y1];
    Asm
      Mov cx, StartOfs
      Mov dx, Bytes
      Push  ds
      Push  es
      Cld
      Les   di, DestPtr
      Lds   si, SrcPtr
      Mov   di, cx; Mov  si, cx
      db  66h; Mov  cx, dx;
      db  66h; Rep  Movsw
      Pop  es
      Pop  ds
    End;
  End;

{ 'down and dirty' pcx loader.  ONLY works with 256 color pictures
 and is
  limited to files <= 64k :(. If you try to load something over 64k
 the
  machine WILL NOT LOCK but pcx will be all screwed up and so will
 the
  palette.
  If you can, please modify it so it can take >64k pcx files and/or
 16 color
  pictures
  FileName = String that holds the filename
  TPal = Palette of the picture. It's AUTOMATICALLY set when you use
 this
         procedure
  Orig = Pointer (remember to use GETMEM) that you want the
 extracted image
         to go
}

Procedure LoadPcx(FileName : AnyString; Var TPal : PaletteType; Orig
 : Pointer);

Var
  Size : Word;
  TextureOffset : Word;
  Count, PcxW, PcxH, TmpCount : Word;
  RunLen : Byte;
  Value : Byte;
  RVal, GVal, BVal : Byte;
  PCXOffset, OutOfs : Word;
  PCXSeg, OutSeg : Word;
  PCXFile : File;
  PCXBuffer : Pointer;
  TmpLong : LongInt;

Begin
  Assign(PcxFile, FileName);
  Reset(PcxFile, 1);
  TmpLong := FileSize(PcxFile);
  If TmpLong > $ffff then TmpLong := $ffff;
  GetMem(PcxBuffer, TmpLong);
  BlockRead(PcxFile, PcxBuffer^, TmpLong);

  OutSeg := Seg(Orig^);
  OutOfs := Ofs(Orig^);
  PcxSeg := Seg(PcxBuffer^);
  PcxOffset := Ofs(PcxBuffer^);

  { Get picture width and height }
  PcxW := MemW[PcxSeg:PcxOffset + 10];
  PcxH := MemW[PcxSeg:PcxOffset + 12];

  PcxOffset := Ofs(PcxBuffer^) + 128;

  TextureOffset := 0;
  Size := 65535;
  While TextureOffset < Size do
    Begin
      RunLen := Mem[PcxSeg:PcxOffset];
      Inc(PcxOffset);
      If (RunLen and $C0) = $C0
        Then Begin
          RunLen := RunLen And $3f;
          Value := Mem[PCXSeg:PcxOffset];
          Inc(PcxOffset);
        End
        Else Begin
          Value := RunLen;
          RunLen := 1;
        End;
      While (RunLen >= 1) and (TextureOffset < Size) do
        Begin
          {If Value < MinCol then Value := MinCol;
          If Value > MaxCol then Value := MaxCol;}
          Mem[OutSeg:OutOfs+TextureOffset] := Value;
          TextureOffset := TextureOffset + 1;
          RunLen := RunLen - 1;
        End;
    End;
  { Get palette }
  PcxOffset := Ofs(PcxBuffer^);
  Count := TmpLong - 768;
  For TmpCount := 0 to 255 do
    Begin
      Port[$3c8] := TmpCount;
      RVal := Mem[PcxSeg : PcxOffset + Count];
      If TmpCount = 0 then RVal := 0;
      Port[$3c9] := RVal div 4;
      Tpal[TmpCount].r := Rval div 4;
      Inc(Count);

      GVal := Mem[PcxSeg : PcxOffset + Count];
      If TmpCount = 0 then gVal := 0;
      Port[$3c9] := GVal div 4;
      Tpal[TmpCount].g := Gval div 4;
      Inc(Count);

      BVal := Mem[PcxSeg : PcxOffset + Count];
      If TmpCount = 0 then bVal := 0;
      Port[$3c9] := BVal div 4;
      Tpal[TmpCount].b := Bval div 4;
      Inc(Count);
    End;
  FreeMem(PcxBuffer, TmpLong);
  Close(PcxFile);
End;

{ Just loads the pcx file's palette into TPal }

Procedure LoadPcxPalette(FileName : AnyString; Var TPal :
 PaletteType);

Var
  Size : Word;
  Count, TmpCount : Word;
  RVal, GVal, BVal : Byte;
  PCXSeg, PCXOffset : Word;
  PCXFile : File;
  PCXBuffer : Pointer;
  TmpLong : LongInt;

Begin
  Assign(PcxFile, FileName);
  Reset(PcxFile, 1);
  TmpLong := FileSize(PcxFile);
  If TmpLong > $ffff then TmpLong := $ffff;
  GetMem(PcxBuffer, TmpLong);
  BlockRead(PcxFile, PcxBuffer^, TmpLong);

  PcxSeg := Seg(PcxBuffer^);
  PcxOffset := Ofs(PcxBuffer^);
  Count := TmpLong - 768;
  For TmpCount := 0 to 255 do
    Begin
      Port[$3c8] := TmpCount;
      RVal := Mem[PcxSeg : PcxOffset + Count];
      If TmpCount = 0 then RVal := 0;
      Port[$3c9] := RVal div 4;
      Tpal[TmpCount].r := Rval div 4;
      Inc(Count);

      GVal := Mem[PcxSeg : PcxOffset + Count];
      If TmpCount = 0 then gVal := 0;
      Port[$3c9] := GVal div 4;
      Tpal[TmpCount].g := Gval div 4;
      Inc(Count);

      BVal := Mem[PcxSeg : PcxOffset + Count];
      If TmpCount = 0 then bVal := 0;
      Port[$3c9] := BVal div 4;
      Tpal[TmpCount].b := Bval div 4;
      Inc(Count);
    End;
  FreeMem(PcxBuffer, TmpLong);
  Close(PcxFile);
End;

{ Clears a virtual page }
Procedure ClearPage(P : Pointer); Assembler;

Asm
  Les  di,P
  Mov  cx, 16000
  db 66h; Xor  ax, ax
  db 66h; Rep Stosw
End;

{Copies a virtual page to video memory}
Procedure CopyPage(P : Pointer); Assembler;

Asm
  Push  ds
  Push  es
  Cld
  Mov   ax,$A000
  Mov   es,ax
  Mov   di, 0
  Lds   si, P
  db 66h; Mov   cx,16000; dw 0;
  db 66h; Rep Movsw
  Pop   es
  Pop   ds
End;

{Copies a virtual page to video memory with 'offset' :P}
{Note: this routine causes a protection fault so dont use it unless
 you can
 debug it}
Procedure CopyPageOffset(P : Pointer; POffset : Word); Assembler;

Asm
  Push  ds
  Push  es
  Cld
  Mov   ax,$A000
  Mov   es,ax
  Mov   di, 0
  Lds   si, P
  db 66h; Mov   cx,16000; dw 0;
  db 66h; Rep Movsw
  Pop   es
  Pop   ds
End;

{ Copies a virtual page to another virtual page }
Procedure Copy2Pages(SrcP, DestP : Pointer); assembler;

  Asm
    Push  ds
    Les   di, DestP
    Lds   si, SrcP
    db 66h; Mov   cx, 16000; dw 0;
    db 66h; Rep Movsw
    Pop   ds
  End;

{ One of Bjarke's routines sets the start position of the video
 cards video
  memory.  Use this for hardware scrolling }
Procedure SetStart(p:word); assembler;
  Asm
    Mov dx,$3d4;Mov bx,p;Mov al,$c; Mov ah,bh;Out dx,ax;Inc al;Mov ah,bl;Out dx,ax;Mov Word Ptr PageOffset, bx;
  End;

{ Only works with my Tseng/ET4000 video card apparently. Selects
 different
  256k sections of my card for SVGA modes. }
Procedure SetBank(bank:byte);

  Begin
    Port[$03cd] := Bank;
  End;
Procedure Vgaline(const x1,y1,x2,y2,where:word;const c:byte);
var
  dex,dey,incf:Integer;
  offset:word;
begin
  {I added the next 2 lines because this routine is not perfect. I
 get
   garbage whenever I use this im my vector program }
  If (y1 <= 0) or (y1 > 319) or (y2 <= 0) or (y2 > 319) then exit;
  {If (x2-x1 = 0) or (x1-x2 = 0) then exit;}
asm
  mov ax,[x2]
  sub ax,[x1]
  jnc @@dont1
  neg ax
@@dont1:
  mov [dex],ax
  mov ax,[y2]
  sub ax,[y1]
  jnc @@dont2
  neg ax
@@dont2:
  mov [dey],ax
  cmp ax,[dex]
  jbe @@otherline
  mov  ax,[y1]
  cmp  ax,[y2]
  jbe  @@DontSwap1
  mov  bx,[y2]
  mov  [y1],bx
  mov  [y2],ax
  mov  ax,[x1]
  mov  bx,[x2]
  mov  [x1],bx
  mov  [x2],ax
@@dontswap1:
  mov [incf],1
  mov ax,[x1]
  cmp ax,[x2]
  jbe @@skipnegate1
  neg [incf]
@@skipnegate1:
  mov di,[y1]
  mov bx,di
  shl di,8
  shl bx,6
  add di,bx
  add di,[x1]
  mov bx,[dey]
  mov cx,bx
  mov ax,where
  mov es,ax
  mov dl,[c]
  mov si,[dex]
@@drawloop1:
  mov es:[di],dl
  add di,320
  sub bx,si
  jnc @@goon1
  add bx,[dey]
  add di,[incf]
@@goon1:
  loop @@drawloop1
  jmp  @@exitline
@@otherline:
  mov ax,[x1]
  cmp ax,[x2]
  jbe @@dontswap2
  mov bx,[x2]
  mov [x1],bx
  mov [x2],ax
  mov ax,[y1]
  mov bx,[y2]
  mov [y1],bx
  mov [y2],ax
@@dontswap2:
  mov [incf],320
  mov ax,[y1]
  cmp ax,[y2]
  jbe @@skipnegate2
  neg [incf]
@@skipnegate2:
  mov di,[y1]
  mov bx,di
  shl di,8
  shl bx,6
  add di,bx
  add di,[x1]
  mov bx,[dex]
  mov cx,bx
  mov ax,where
  mov es,ax
  mov dl,[c]
  mov si,[dey]
@@drawloop2:
  mov es:[di],dl
  inc di
  sub bx,si
  jnc @@goon2
  add bx,[dex]
  add di,[incf]
@@goon2:
  loop @@drawloop2
@@exitline:
end;
end;

Begin
End.