{
Here is a "Perfect" texture mapper. It uses real number to map a square
bitmap into a 4 point polygon. I haven't had any time to optimize it
so I would love to see somebody speed it up for realtime uses. :)
}

Program TextMap;
{$N+,E+}   { Sorry all you out there :) }

Uses Crt;

Type
  PointType = Record
    X, Y : Integer;
  End;

Const
  Top = 1;    Bottom = 2; Left = 3; Right = 4; PWidth : Integer = 15;
  PHeight : Integer = 15;

  Points : Array[0..3] of PointType = ((x : 100; y : 100),
  (x : 150; y : 150),(x : 100; y : 200),(x : 50; y : 150));
  BitMap : Array[0..15, 0..15] of Byte = ((1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1),
      (1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1),(1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1),
      (1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1),(1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1),
      (1,5,5,5,5,1,1,1,1,1,1,5,5,5,5,1),(1,5,5,5,5,1,0,0,0,0,1,5,5,5,5,1),
      (1,5,5,5,5,1,0,0,0,0,1,5,5,5,5,1),(1,5,5,5,5,1,0,0,0,0,1,5,5,5,5,1),
      (1,5,5,5,5,1,0,0,0,0,1,5,5,5,5,1),(1,5,5,5,5,1,1,1,1,1,1,5,5,5,5,1),
      (1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1),(1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1),
      (1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1),(1,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1),
      (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1));

Var
  LeftTable, RightTable : Array[0..400, 0..2] of Integer;
  Max_Y, Min_Y : Integer;
  LineHeight : Integer;

Procedure PutPixel(X, Y : Integer; C : Byte);

Begin
  Mem[$A000:(Y*320)+x] := c;
End;

Procedure Swap(Var a, b : Integer);

Var
  t : Integer;

Begin
  t := a;
  a := b;
  b := t;
End;

Procedure FindMaxMin;

Var
  c : Integer;

Begin
  For c := 0 to 3 do
    Begin
      If Points[c].Y < Min_y
        Then Min_Y := Points[c].Y;
      If Points[c].Y > Max_y
        Then Max_Y := Points[c].Y;
    End;
End;


Procedure ScanLeft(X1, X2, Y1, LH, Side : Integer);

Var
  y : Integer;
  XAdd, Px, Py, PxAdd, PyAdd, x : Single;

Begin
  LH := LH + 1;
  XAdd := (X2-X1)/LH;
  If Side = Top
    Then Begin
      Px := PWidth;
      Py := 0;
      PxAdd := -PWidth/LH;
      PyAdd := 0;
    End;
  If Side = Right
    Then Begin
      Px := PWidth;
      Py := PHeight;
      PxAdd := 0;
      PyAdd := -PHeight/LH;
    End;
  If Side = Bottom
    Then Begin
      Px := 0;
      Py := PHeight;
      PxAdd := PWidth/LH;
      PyAdd := 0;
    End;
  If Side = Left
    Then Begin
      Px := 0;
      Py := 0;
      PxAdd := 0;
      PyAdd := PHeight/LH;
    End;
  x := X1;
  For y := 0 to LH do
    Begin
      LeftTable[Y1 + y, 0] := Round(x);
      LeftTable[Y1 + y, 1] := Round(Px);
      LeftTable[Y1 + y, 2] := Round(Py);
      X := X + XAdd;   Px := Px + PxAdd; Py := Py + PyAdd;
    End;
End;

Procedure ScanRight(X1, X2, Y1, LH, Side : Integer);

Var
  y : Integer;
  XAdd, Px, Py, PxAdd, PyAdd, x : Single;

Begin
  LH := LH + 1;
  XAdd := (X2-X1)/LH;
  If Side = Top
    Then Begin
      Px := 0;
      Py := 0;
      PxAdd := PWidth/LH;
      PyAdd := 0;
    End;
  If Side = Right
    Then Begin
      Px := PWidth;
      Py := 0;
      PxAdd := 0;
      PyAdd := PHeight/LH;
    End;
  If Side = Bottom
    Then Begin
      Px := PWidth;
      Py := PHeight;
      PxAdd := 0;
      PyAdd := -PHeight/LH;
    End;
  If Side = Left
    Then Begin
      Px := 0;
      Py := PHeight;
      PxAdd := 0;
      PyAdd := -PHeight/LH;
    End;
  x := X1;
  For y := 0 to LH do
    Begin
      RightTable[Y1 + y, 0] := Round(x);
      RightTable[Y1 + y, 1] := Round(Px);
      RightTable[Y1 + y, 2] := Round(Py);
      X := X + XAdd;   Px := Px + PxAdd; Py := Py + PyAdd;
    End;
End;


Procedure ScanConvert(X1, Y1, X2, Y2, PLoc : Integer);

Begin
  If Y2 < Y1
    Then Begin
      Swap(X1, X2);
      Swap(Y1, Y2);
      LineHeight := Y2 - Y1;
      ScanLeft(X1, X2, Y1, LineHeight, PLoc);
    End
    Else Begin
      LineHeight := Y2 - Y1;
      ScanRight(X1, X2, Y1, LineHeight, PLoc);
    End;
End;

Procedure TextureMap;

Var
  LW, x, y : Integer;
  PolyX1, PolyX2, Px1, Px2, Py1, Py2, PxA, PyA : Single;
  Color : Byte;

Begin
  For y := Min_Y to Max_Y do
    Begin
      PolyX1 := LeftTable[y,0];
      Px1 := LeftTable[y,1];
      Py1 := LeftTable[y,2];
      PolyX2 := RightTable[y,0];
      Px2 := RightTable[y,1];
      Py2 := RightTable[y,2];
      LW := Round(PolyX2-PolyX1);
      Lw := Lw + 1;
      PxA := (Px2-Px1)/LW;
      PyA := (Py2-Py1)/LW;
      For x := Round(PolyX1) to Round(PolyX2) do
        Begin
          Color := Bitmap[Round(Py1), Round(Px1)];
          PutPixel(X, Y, Color);
          Px1 := Px1 + PxA;
          Py1 := Py1 + PyA;
        End;
    End;
End;

Begin
  Asm
    Mov AX,$13
    Int 10h
  End;
  Max_Y := 0;
  Min_Y := 32000;
  FindMaxMin;
  ScanConvert(Points[0].X, Points[0].Y, Points[1].x, Points[1].y, Top);
  ScanConvert(Points[1].X, Points[1].Y, Points[2].x, Points[2].y, Right);
  ScanConvert(Points[2].X, Points[2].Y, Points[3].x, Points[3].y, Bottom);
  ScanConvert(Points[3].X, Points[3].Y, Points[0].x, Points[0].y, Left);
  TextureMap;
  Readln;
  TextMode(co80);
End.

