{
Here is the GOURAUD shading include file that came with Surface Modeler 3.0:
}
procedure GOURAUD;
{ Make a surface model drawing of the object with Gouraud interpolation
  of surface shading }

var Node:                      word;          { node # }
    Surf:                      word;          { surface # }
    Shade:                     real;          { shade of surface }
    Shade2:                    real;          { shade of 2nd side of surface }
    Vert:                      integer;       { vertex # }
    Interp:                    boolean;       { flag interpolated shading }
    User_abort:                boolean;       { did the user abort? }
    ch:                        char;
{$ifndef BIGMEM}
    Shades: nodearray;
      { shade at each node }
    Surfmin, Surfmax: surfaces;
      { surface minimum & maximum (Ztran) }
    Nshades: array[1..MAXNODES] of integer;
      { # shades to average per node }
    Sshade: surfaces;
      { shade at each surface }
{$endif}
label ABORTTEXT,                              { text-mode abort }
      ABORTGRPH;                              { graphics-mode abort }

begin
{$ifdef BIGMEM}
with ptrh^ do with ptri^ do with ptrj^ do
with ptra^ do with ptrb^ do with ptrc^ do
with ptrd^ do with ptre^ do with ptrf^ do
with ptrh^ do with ptri^ do with ptrj^ do
with ptrk^ do with ptrl^ do with ptrm^ do with ptrn^ do
begin
{$endif}

  perf_start;
  User_abort := TRUE;
  if (checkey) then goto ABORTTEXT;
{$ifndef NOSHADOW}
  if (Shadowing) then begin
    shadows (Shades);
    for Node := 1 to Nnodes do
      Nshades[Node] := 0;
  end else
{$else}
  if (Shadowing) then
    writeln ('Error: Shadows not implemented in this version')
  else
{$endif}
    for Node := 1 to Nnodes do begin
      Shades[Node] := 0.0;
      Nshades[Node] := 0;
    end;

  if (Viewchanged) or (Shadowing) then begin
    if (checkey) then goto ABORTTEXT;
    menumsg ('Transforming to 2-D...');
{ Transform from 3-D to 2-D coordinates }
    setorigin;
    for Node := 1 to Nnodes do
      perspect (Xworld[Node], Yworld[Node], Zworld[Node],
                Xtran[Node],  Ytran[Node],  Ztran[Node]);

{ Set plotting limits and normalize transformed coords to screen coords }
    perspect (Xfocal, Yfocal, Zfocal, Xfotran, Yfotran, Zfotran);
    if (not setnormal (Xfotran, Yfotran, XYmax)) then begin
      menumsg ('Warning: Focal point outside data limits.');
      writeln;
      write   ('  Press any key ...');
      ch := readkey;
    { Erase the previous message }
      menumsg ('');
      writeln;
      write ('                          ');
    end;

    if (checkey) then goto ABORTTEXT;
{ Normalize all the nodes }
    for Node := 1 to Nnodes do
      normalize (Xtran[Node], Ytran[Node], Xfotran, Yfotran, XYmax);
    { Initialize all nodal shades to zero }

    if (checkey) then goto ABORTTEXT;
    menumsg ('Sorting surfaces...');
    minmax (Surfmin, Surfmax, Nsurf);
    shelsurf (Surfmin, Surfmax, Nsurf);
    Viewchanged := FALSE;
  end; { if Viewchanged }

  setshade;                            { Setup for shading calculations }

{ Compute the cumulative shading at every node (sum the shades due to
  all surrounding surfaces) }
  if (checkey) then goto ABORTTEXT;
  menumsg ('Computing shades...');
  for Surf := 1 to Nsurf do begin
    if (Nsides = 2) then begin
      { Use only the side of the surface with the brightest shade }
      Shade := Shading (Surf, 1);
      Shade2 := Shading (Surf, 2);
      if (Shade2 > Shade) then
        Shade := Shade2;
    end else
      Shade := Shading (Surf, 1);
    { Surface shade }
    Sshade[Surf] := Shade;
    { Nodal shade }
    for Vert := 1 to Nvert[Surf] do begin
      Node := konnec (Surf, Vert);
      if (Shade >= 0.0) and (Shades[Node] >= 0.0) then begin
        Shades[Node] := Shades[Node] + Shade;
        Nshades[Node] := Nshades[Node] + 1;
      end;
    end; { for Vert }
  end; { for Surf }

  if (checkey) then goto ABORTTEXT;
{ Now average out the nodal shading }
  for Node := 1 to Nnodes do
    if (Nshades[Node] > 0) then
      Shades[Node] := Shades[Node] / Nshades[Node];

{$ifdef USE_IFF}
  menumsg ('Plotting...');
{$endif}

{ Now plot all the surfaces, with Gouraud shading }
  setgmode (Nmatl);
  for Surf := 1 to Nsurf do begin
    if (Sshade[Surf] >= 0.0) then begin
      Interp := TRUE;
      { If any nodal shade varies from the average (surface) shade by more
        than Epsilon, then don't use interpolated shading (unless the node
        is in a shadow, in which case you should interpolate anyway) }
      for Vert := 1 to Nvert[Surf] do begin
        Node := konnec (Surf, Vert);
        if (abs(Shades[Node] - Sshade[Surf]) > Epsilon) and
           (Shades[Node] >= 0.0) then
          Interp := FALSE;
      end;
      if (Interp) then
        intrfill (Surf, Matl[Surf], Shades)
      else
        fillsurf (Surf, Matl[Surf], Sshade[Surf]);
      { Show border of surface, if requested }
      if (ShowAllBorders > 0) then
        border (Surf, Matl[Surf]);
    end; { if Sshade }
    if (grafstat) then goto ABORTGRPH;
  end; { for Surf }
  drawaxes (Xfotran, Yfotran, XYmax);

  perf_stop (5);

{$ifdef USE_IFF}
  menumsg ('Saving IFF...');
  saveiff (Filemask + '.IFF', VGApal);
{$else}
  { Wait for user keypress to continue }
  continue;
{$endif}
  User_abort := FALSE;

  ABORTGRPH:
  exgraphic;
  ABORTTEXT:
  if (User_abort) then
    perf_stop (0);
{$ifdef BIGMEM}
end; {with}
{$endif}
end; {procedure GOURAUD }
