This file is indexed.

/usr/src/castle-game-engine-4.1.1/x3d/x3dnodes_elevationgrid.inc is in castle-game-engine-src 4.1.1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
{
  Copyright 2002-2013 Michalis Kamburelis.

  This file is part of "Castle Game Engine".

  "Castle Game Engine" is free software; see the file COPYING.txt,
  included in this distribution, for details about the copyright.

  "Castle Game Engine" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  ----------------------------------------------------------------------------
}

function TElevationGridNode.Proxy(var State: TX3DGraphTraverseState;
  const OverTriangulate: boolean): TAbstractGeometryNode;

{ I initially rendered ElevationGrid directly, by GL_QUAD_STRIP
  for each row. Fast, but has troubles:

  - When colorPerVertex is different than normalPerVertex,
    neither flat nor smooth shading is good.
  - Normal generation was a pain. A code generating smooth-only normals
    was implemented, and was already a pain to maintain (since with IndexedFaceSet,
    we already had normal generation implemented).
    creaseAngle was not supported, only all smooth or all flat was supported.
  - Rendering by quads was sometimes not fully correct, as elevation grid
    quads were not really planar. So with GPU performing any triangulation
    it wants, results are undefined and not always the best.
    Right now we triangulate ourselves along the shortest diagonal,
    which improves the look much.
    IndexedFaceSet is rendered through GL_TRIANGLES anyway.

  Using proxy to render ElevationGrid solves above troubles.
  Using proxy also makes simpler implementation than rendering,
  and also it's used for triangulating.
}
var
  Coords: TVector3SingleList;
  CoordIndexes: TLongIntList;

  { Add to CoordIndexes a quad from given indexes.
    Actually we add two triangles, looking at Coord to choose the best
    triangulation. }
  procedure Quad(const IndexNum, I1, I2, I3, I4: Integer);
  begin
    if PointsDistanceSqr(Coords.L[I1], Coords.L[I3]) <
       PointsDistanceSqr(Coords.L[I2], Coords.L[I4]) then
    begin
      CoordIndexes.L[IndexNum    ] := I1;
      CoordIndexes.L[IndexNum + 1] := I2;
      CoordIndexes.L[IndexNum + 2] := I3;
      CoordIndexes.L[IndexNum + 3] := -1;
      CoordIndexes.L[IndexNum + 4] := I3;
      CoordIndexes.L[IndexNum + 5] := I4;
      CoordIndexes.L[IndexNum + 6] := I1;
      CoordIndexes.L[IndexNum + 7] := -1;
    end else
    begin
      CoordIndexes.L[IndexNum    ] := I1;
      CoordIndexes.L[IndexNum + 1] := I2;
      CoordIndexes.L[IndexNum + 2] := I4;
      CoordIndexes.L[IndexNum + 3] := -1;
      CoordIndexes.L[IndexNum + 4] := I2;
      CoordIndexes.L[IndexNum + 5] := I3;
      CoordIndexes.L[IndexNum + 6] := I4;
      CoordIndexes.L[IndexNum + 7] := -1;
    end;
  end;

var
  IFS: TIndexedFaceSetNode absolute Result;
  XDimension, ZDimension: Integer; {< shortcuts for appropriate fields values }
  TexCoordProvided: boolean;
  I, J, NextIndex: Integer;
  CoordNode: TCoordinateNode;
  TexCoords: TVector2SingleList;
begin
  IFS := TIndexedFaceSetNode.Create(NodeName, BaseUrl);
  try
    XDimension := FdXDimension.Value;
    ZDimension := FdZDimension.Value;

    if IsNotEmpty then
    begin
      CoordNode := TCoordinateNode.Create('', BaseUrl);
      IFS.FdCoord.Value := CoordNode;
      Coords := CoordNode.FdPoint.Items;

      { calculate TexCoordProvided, set IFS.FdTexCoord, maybe set TexCoords }
      TexCoordProvided :=
        (FdTexCoord.Value <> nil) and
        (FdTexCoord.Value is TTextureCoordinateNode) and
        (TTextureCoordinateNode(FdTexCoord.Value).FdPoint.Count >=
          XDimension * ZDimension);
      if TexCoordProvided then
        IFS.FdTexCoord.Value := FdTexCoord.Value else
      begin
        IFS.FdTexCoord.Value := TTextureCoordinateNode.Create('', BaseUrl);
        TexCoords := TTextureCoordinateNode(IFS.FdTexCoord.Value).FdPoint.Items;
      end;

      { generate coords (and other per-vertex stuff: tex coords) }
      Coords.Count := XDimension * ZDimension;
      if not TexCoordProvided then
        TexCoords.Count := XDimension * ZDimension;
      for J := 0 to ZDimension - 1 do
        for I := 0 to XDimension - 1 do
        begin
          Coords.L[I + J * XDimension] := Vector3Single(
            FdXSpacing.Value * I,
            FdHeight.Items.L[I + J * XDimension],
            FdZSpacing.Value * J);

          if not TexCoordProvided then
            TexCoords.L[I + J * XDimension] := Vector2Single(
              I / (XDimension - 1),
              J / (ZDimension - 1));
        end;

      { generate quads indexes }
      CoordIndexes := IFS.CoordIndex.Items;
      CoordIndexes.Count := (XDimension - 1) * (ZDimension - 1) * 8;
      NextIndex := 0;
      for J := 1 to ZDimension - 1 do
        for I := 1 to XDimension - 1 do
        begin
          { Vertices are ordered such that face is CCW from up
            (i.e. looking from positive Y axis). }
          Quad(NextIndex,
               I     + (J - 1) * XDimension,
               I - 1 + (J - 1) * XDimension,
               I - 1 +  J      * XDimension,
               I     +  J      * XDimension);
          NextIndex += 8;
        end;
      Assert(NextIndex = CoordIndexes.Count);
    end;

    IFS.FdSolid.Value := FdSolid.Value;
    IFS.FdCcw.Value := FdCcw.Value;
    { We order our coords such that we can simply copy normal/color nodes }
    IFS.FdNormalPerVertex.Value := FdNormalPerVertex.Value;
    IFS.FdNormal.Value := FdNormal.Value;
    IFS.FdColorPerVertex.Value := FdColorPerVertex.Value;
    IFS.FdColor.Value := FdColor.Value;
    IFS.FdCreaseAngle.Value := FdCreaseAngle.Value;
    IFS.FdFogCoord.Value := FdFogCoord.Value;
    IFS.FdAttrib.AssignValue(FdAttrib);
  except FreeAndNil(Result); raise end;
end;

function TElevationGridNode.ProxyUsesOverTriangulate: boolean;
begin
  Result := false;
end;