program PltCube;

  { Demo of Plt and H3 units: draws a cube. }
  { Last edited by J. Stolfi on 93-04-20. }
 
uses Crt, Plt, R3, H3, R4x4;

const
  radius = 3.0 {mm};  { Half-side of cubelets }
  disp = 23.0 {mm};   { Cublet spacing }

type
  Segment  = record a, b: H3.Point end;
  Triangle = record a, b, c: H3.Point end;
  CubeEdges = array [0..11] of Segment;

var
  e: CubeEdges;
  persp: H3.PMap;  { Basic perspective transformation. }
  rt: H3.PMap;     { Cube rotation and translation map. }
  m: H3.PMap;      { Composite map persp * rt. }

  i, j, k: integer;

procedure def_cube_edge(
    var a, b: H3.Point;
    i, j, k: integer;
    jv, kv: integer
  );
  { Defines edge of cube in standard position. }
  { Edge extends from -radius to +radius along coordinate i. }
  { Coords j and k are jv and kv, mapped [0..1] -> [-radius..+radius]. }
  begin
    a.c[0] := 1.0;
    if jv = 0 then a.c[j] := -radius else a.c[j] := +radius;
    if kv = 0 then a.c[k] := -radius else a.c[k] := +radius;
    b.c := a.c;
    a.c[i] := -radius;
    b.c[i] := +radius;
  end;

procedure def_rot_matrix(xr, yr, zr, xs, ys, zs: real; var rm: R4x4.T);
  var r, s, t: R3.T;
      i: integer;
  begin
    r[0] := xr;
    r[1] := yr;
    r[2] := zr;
    R3.reduce(r);
    s[0] := xs;
    s[1] := ys;
    s[2] := zs;
    R3.orthize(s, r, s);
    R3.reduce(s);
    R3.cross(r, s, t);
    rm[0,0] := 1.0;
    rm[0,1] := 0.0;
    rm[0,2] := 0.0;
    rm[0,3] := 0.0;
    for i := 1 to 3 do
      begin
        rm[i,0] := 0.0;
        rm[1,i] := r[i-1];
        rm[2,i] := s[i-1];
        rm[3,i] := t[i-1];
      end;
  end;

procedure def_rot_trans_matrix(xt, yt, zt: real; var m: H3.PMap);
  var r, s, t: R3.T;
      ra, rb: R4x4.T;
  begin
    def_rot_matrix(1.0, 2.0, 3.0,  4.0, 1.0, -2.0, ra);
    def_rot_matrix(1.0, 2.0, 2.5,  2.0, -1.0, 0.0, rb);

    ra[0,1] := xt;
    ra[0,2] := yt;
    ra[0,3] := zt;
    R4x4.mul(ra, rb, m.dir);
    R4x4.adj(m.dir, m.inv);
  end;

procedure def_cube(var e: CubeEdges);
  var r, i, j, k: integer;
  begin
    for r := 0 to 11 do
      begin
        i := r div 4;
        j := (i + 1) mod 3;
        k := (j + 1) mod 3;
        def_cube_edge(
          e[r].a, e[r].b,
          i+1, j+1, k+1,
          r mod 2, (r mod 4) div 2
        );
      end;
  end;

procedure def_persp_map(var m: PMap);
  var obs, foc, upp: H3.Point;
  begin
    H3.mk_point(1.0, 400.0, 0.0, 0.0, obs);
    H3.mk_point(1.0,   0.0, 0.0, 0.0, foc);
    H3.mk_point(0.0,   0.0, 0.0, 1.0, upp);
    H3.persp_map(obs, foc, upp, m);
  end;

procedure draw_persp_cube(
    var e: CubeEdges;
    var m: H3.PMap; { Scene-to-Image and Perspective map. }
    xc, yc: real    { Center of window on Image Z=0 plane. }
  );
  var r: integer;
      p, q: H3.Point;
  begin
    for r := 0 to 11 do
      begin
        { Compute projection: }
        H3.map_point(e[r].a, m, p);
        H3.map_point(e[r].b, m, q);
        plt_draw_segment(
          p.c[1]/p.c[0] - xc, p.c[2]/p.c[0] - yc,
          q.c[1]/q.c[0] - xc, q.c[2]/q.c[0] - yc,
          0.0, 0.0
        );
      end;
  end;

procedure print_persp_cube(var e: CubeEdges; var m: H3.PMap);
  var r: integer;
      p, q: H3.Point;
  begin
    for r := 0 to 11 do
      begin
        H3.map_point(e[r].a, m, p);
        H3.map_point(e[r].b, m, q);
        write('p[', r:2, '] = '); H3.print_point(output, p); writeln;
        write('q[', r:2, '] = '); H3.print_point(output, q); writeln;
        readln;
      end;
  end;

begin
  def_cube(e);
  def_persp_map(persp);
  plt_begin_drawing('PltCube.ps', 'sensei', 1);
  for i := -2 to 2 do
    for j := -2 to 2 do
      for k := -2 to 2 do
        begin
          def_rot_trans_matrix(i*disp, j*disp, k*disp, rt);
          H3.comp_map(rt, persp, m);
          draw_persp_cube(e, m, 0.0, 0.0);
        end;
  plt_add_caption('BEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEP!');
  plt_add_caption('This is a test. Repeat, it''s only a test.');
  plt_add_caption('If this were a real drawing, you would be given');
  plt_add_caption('further instructions as to where to look at');
  plt_add_caption('and what to think of it.');
  plt_end_drawing;
end.