(*
    DEMO02 - Texture mapping and palette rotation
    (c) 1994 by Alessandro Scotti
*)
uses Crt, Modex, Plasma, Threed;

const
  LSIZE = 85;
  Trans : TPoint = ( X:0; Y:0; Z:0 );
type
  T2DPoint = record
    X, Y: integer;
  end;
  TTexture = record
    Desc   : array[ 0..3 ] of T2DPoint;
    Width  : word;
    Data   : array[ 1..64*64 ] of byte;
  end;
  TQuad = record
    VtxCnt : word;
    Vtx    : array[ 0..3 ] of word;
    Texture: word;
  end;
var
  Vtx   : array[ 0..7 ] of TPoint;
  XVtx  : array[ 0..7 ] of TPoint;
  VVtx  : array[ 0..7 ] of T2DPoint;
  Face  : array[ 0..5 ] of TQuad;
  Txts  : array[ 0..5 ] of TTexture;
  Nrm   : array[ 0..5 ] of TPoint;
  XNrm  : array[ 0..5 ] of TPoint;
  Page  : word;
  Palette: array[ byte ] of record R, G, B: byte; end;

(* Make a 64x64 plasma to be used as texture *)
procedure MakeTexture( Idx: word );
var
  I: word;
begin
  mxFillBox( 0, 0, 64, 64, 0, OP_SET );
  MakePlasma( 0, 0, 64, 64, 96, Random(192)+1, Random(192)+1, Random(192)+1 );
  mxGetImage( @Txts[Idx].Data, 0, 0, 64, 64 );
  (* Texture vertexes are 8:8 fixed, add $80 (0.5) for best results *)
  with Txts[Idx] do begin
    Desc[0].X := $80; Desc[0].Y := $80;
    Desc[1].X := $80; Desc[1].Y := $3F80;
    Desc[2].X := $3F80; Desc[2].Y := $3F80;
    Desc[3].X := $3F80; Desc[3].Y := $80;
    Width := 64;
  end;
end;

procedure Init;
var
  I: integer;
begin
  (* Build vertexes for a cube *)
  with Vtx[0] do begin X:=-LSIZE; Y:=-LSIZE; Z:=-LSIZE; end;
  with Vtx[1] do begin X:=+LSIZE; Y:=-LSIZE; Z:=-LSIZE; end;
  with Vtx[2] do begin X:=-LSIZE; Y:=+LSIZE; Z:=-LSIZE; end;
  with Vtx[3] do begin X:=+LSIZE; Y:=+LSIZE; Z:=-LSIZE; end;
  with Vtx[4] do begin X:=-LSIZE; Y:=-LSIZE; Z:=+LSIZE; end;
  with Vtx[5] do begin X:=+LSIZE; Y:=-LSIZE; Z:=+LSIZE; end;
  with Vtx[6] do begin X:=-LSIZE; Y:=+LSIZE; Z:=+LSIZE; end;
  with Vtx[7] do begin X:=+LSIZE; Y:=+LSIZE; Z:=+LSIZE; end;
  for I:=0 to 7 do begin          (* Make points 16:16 fixed *)
    Vtx[I].X := Vtx[I].X*$10000;
    Vtx[I].Y := Vtx[I].Y*$10000;
    Vtx[I].Z := Vtx[I].Z*$10000;
  end;
  (* Build faces *)
  with Face[0] do begin Vtx[0]:=0; Vtx[1]:=2; Vtx[2]:=3; Vtx[3]:=1; end;
  with Face[1] do begin Vtx[0]:=4; Vtx[1]:=5; Vtx[2]:=7; Vtx[3]:=6; end;
  with Face[2] do begin Vtx[0]:=0; Vtx[1]:=1; Vtx[2]:=5; Vtx[3]:=4; end;
  with Face[3] do begin Vtx[0]:=1; Vtx[1]:=3; Vtx[2]:=7; Vtx[3]:=5; end;
  with Face[4] do begin Vtx[0]:=2; Vtx[1]:=0; Vtx[2]:=4; Vtx[3]:=6; end;
  with Face[5] do begin Vtx[0]:=7; Vtx[1]:=3; Vtx[2]:=2; Vtx[3]:=6; end;
  for I:=0 to 5 do Face[I].Texture := I;
  (* Build textures and palette *)
  Randomize;
  FillChar( Palette, SizeOf(Palette), 0 );
  MakePlasmaPalette( Palette, PAL_RGB );
  mxSetPalette( @Palette, 0, 193 );
  for I:=0 to 5 do MakeTexture( I );
end;

var
  AX, AY, AZ: byte;
  I: word;
begin
  mxInit;
  mxSetMode( MX_320x240 );
  Init;
  Page := 240;          (* Start with hidden page *)

  AX := 0;
  AY := 0;
  AZ := 0;
  (* Init 3D transforms, perspective is intentionally exaggerated *)
  tdSetTranslation( Trans );
  tdSetPerspective( 400*$10000, $10000, $10000 );
  (* Main loop, all magic here! *)
  while( not KeyPressed ) do begin
    tdSetRotation( AX, AY, AZ );                (* Set new angles *)
    tdTransform( Vtx, XVtx, 8 );                (* 3D transform points *)
    tdTransformToImage( XVtx, VVtx, 8, 160, 120+Page );
    Inc( AX, 1 );                               (* Bump angles *)
    Inc( AY, 1 );
    Inc( AZ, 2 );
    mxSetClipRegion( 0, Page, 320, 240 );       (* Set clip to new page *)
    mxSetClip( TRUE );
    mxFillBox( 0, Page, 320, 240, 0, OP_MOVE ); (* Clear screen *)
    mxRotatePalette( @Palette[1], 192, 3 );     (* Rotate palette *)
    (* Draw cube: backface culling is straighforward in this case, so *)
    (* it can be handled by the polygon filling procedure *)
    for I:=0 to 5 do
      mxTexturePoly( 4, Face[I].Vtx, VVtx, Txts[I].Desc, Txts[I].Data, Txts[I].Width );
    mxStartLine( Page );                        (* Flip pages *)
    mxSetPalette( @Palette[1], 1, 192 );        (* Set new palette *)
    Page := 240-Page;
  end;

  mxSetMode( MX_TEXT );
  mxTerm;
end.
