model model1;

procedure SimpleWall(const x1, z1, x2, z2, h1, h2: float; const u, v: float);
begin
  glTexCoord2f(u, v); 
  glbegin(GL_QUADS);
    glVertex3f(x1, h1, z1);
    glVertex3f(x1, h2, z1);
    glVertex3f(x2, h2, z2);
    glVertex3f(x2, h1, z2);
  glEnd;
end;

procedure SimpleFlat(const x1, z1, x2, z2, h: float; const u, v: float);
begin
  glTexCoord2f(u, v); 
  glbegin(GL_QUADS);
    glVertex3f(x1, h, z1);
    glVertex3f(x1, h, z2);
    glVertex3f(x2, h, z2);
    glVertex3f(x2, h, z1);
  glEnd;
end;

procedure Cube(const x1, y1, z1, x2, y2, z2: float; const u, v: float);
begin
  SimpleFlat(x1, z1, x2, z2, y1, u, v);  
  SimpleFlat(x1, z1, x2, z2, y2, u, v);  
  SimpleWall(x1, z1, x1, z2, y1, y2, u, v);
  SimpleWall(x1, z2, x2, z2, y1, y2, u, v);
  SimpleWall(x2, z2, x2, z1, y1, y2, u, v);
  SimpleWall(x2, z1, x1, z1, y1, y2, u, v);
end;

function UV(const id: integer): float;
begin
  Result := (id + 0.5) / 8;
end;

procedure Cube4(const x1, y1, z1, x2, y2, z2: float; const iu, iv: integer);
var
  xm, ym, zm: float;
  XX: array[0..2] of float;
  YY: array[0..2] of float;
  ZZ: array[0..2] of float;
  u, v: integer;
  i, j, k: integer;
begin
  xm := (x1 + x2) / 2;
  ym := (y1 + y2) / 2;
  zm := (z1 + z2) / 2;
  
  u := iu;
  v := iv;
  
  XX[0] := x1;
  XX[1] := xm;
  XX[2] := x2;

  YY[0] := y1;
  YY[1] := ym;
  YY[2] := y2;

  ZZ[0] := z1;
  ZZ[1] := zm;
  ZZ[2] := z2;
  
  for i := 0 to 1 do
    for j := 0 to 1 do
      for k := 0 to 1 do
      begin
        Cube(XX[i], YY[j], ZZ[k], XX[i + 1], YY[j + 1], ZZ[k + 1], UV(u), UV(v));
        inc(u);
        if u = 8 then
        begin
          u := 0;
          inc(v);
        end;
      end;
end;

procedure CraneLevel(const level: integer);
var
  yelev: float;
begin
  yelev := level * 0.31;
  
  Cube(-0.21, yelev + 0.00, -0.21, -0.19, yelev + 0.01, -0.19, UV(2), UV(0)); 
  Cube(-0.21, yelev + 0.00,  0.21, -0.19, yelev + 0.01,  0.19, UV(2), UV(0)); 
  Cube( 0.01, yelev + 0.00,  0.21, -0.01, yelev + 0.01,  0.19, UV(2), UV(0)); 
  Cube( 0.01, yelev + 0.00, -0.21, -0.01, yelev + 0.01, -0.19, UV(2), UV(0));
  Cube( 0.21, yelev + 0.00,  0.21,  0.19, yelev + 0.01,  0.19, UV(2), UV(0)); 
  Cube( 0.21, yelev + 0.00, -0.21,  0.19, yelev + 0.01, -0.19, UV(2), UV(0));
   
  Cube(-0.21, yelev + 0.01, -0.21, -0.19, yelev + 0.02,  0.21, UV(1), UV(0));
  Cube( 0.01, yelev + 0.01, -0.21, -0.01, yelev + 0.02,  0.21, UV(1), UV(0));
  Cube( 0.21, yelev + 0.01, -0.21,  0.19, yelev + 0.02,  0.21, UV(1), UV(0));

  Cube(-0.21, yelev + 0.02, -0.21, -0.19, yelev + 0.30, -0.19, UV(1), UV(0)); 
  Cube(-0.21, yelev + 0.02,  0.21, -0.19, yelev + 0.30,  0.19, UV(1), UV(0)); 
  Cube( 0.01, yelev + 0.02, -0.21, -0.01, yelev + 0.30, -0.19, UV(1), UV(0)); 
  Cube( 0.01, yelev + 0.02,  0.21, -0.01, yelev + 0.30,  0.19, UV(1), UV(0)); 
  Cube( 0.21, yelev + 0.02,  0.21,  0.19, yelev + 0.30,  0.19, UV(1), UV(0)); 
  Cube( 0.21, yelev + 0.02, -0.21,  0.19, yelev + 0.30, -0.19, UV(1), UV(0));
   
  Cube(-0.25, yelev + 0.02, -0.19,  0.25, yelev + 0.03,  0.19, UV(4), UV(0)); 
  
  Cube(-0.21, yelev + 0.30, -0.21, -0.19, yelev + 0.31, -0.19, UV(2), UV(0)); 
  Cube(-0.21, yelev + 0.30,  0.21, -0.19, yelev + 0.31,  0.19, UV(2), UV(0)); 
  Cube( 0.01, yelev + 0.30,  0.21, -0.01, yelev + 0.31,  0.19, UV(2), UV(0)); 
  Cube( 0.01, yelev + 0.30, -0.21, -0.01, yelev + 0.31, -0.19, UV(2), UV(0));
  Cube( 0.21, yelev + 0.30,  0.21,  0.19, yelev + 0.31,  0.19, UV(2), UV(0)); 
  Cube( 0.21, yelev + 0.30, -0.21,  0.19, yelev + 0.31, -0.19, UV(2), UV(0));   
end;

var 
  cargo_offs: integer;

procedure CargoLevel(const level: integer);
var
  yelev: float;
begin
  yelev := level * 0.31 + 0.03;

  inc(cargo_offs);
  if cargo_offs = 8 then
    cargo_offs := 1;
  Cube4(-0.24, yelev, -0.19,  0.24, yelev + 0.20,  0.00, 0, cargo_offs);
end;

var
  frm: integer;
  i, j, k: integer;
begin
  cargo_offs := 0;
  frm := 0;
  
  for i := 0 to 3 do
  begin
    if i > 1 then
    begin
      SetFrame(frm);
      inc(frm);
      for j := 0 to i do
      begin
        CraneLevel(j);
        for k := 0 to j - 2 do
          CargoLevel(k);
      end;
    end;
    SetFrame(frm);
    inc(frm);
    for j := 0 to i do
    begin
      CraneLevel(j);
      for k := 0 to j - 1 do
        CargoLevel(k);
    end;
    SetFrame(frm);
    inc(frm);
    for j := 0 to i do
    begin
      CraneLevel(j);
      for k := 0 to j do
        CargoLevel(k);
    end;
  end;
end.
