This file is indexed.

/usr/src/castle-game-engine-6.4/x3d/x3dload.pas is in castle-game-engine-src 6.4+dfsg1-2.

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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
{
  Copyright 2003-2017 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.

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

{ @abstract(Loading 3D models as X3D.)

  Every format except VRML/X3D is handled by converting it into X3D nodes graph.
  This allows to use our great X3D renderer, tools, saving to X3D and such,
  on every 3D model.

  Basic guide for adding a new 3D format:

  @unorderedList(
    @item(
      Particular formats are implemented inside various X3DLoadInternalXxx units.
      Implementation of this unit calls them. In the future,
      a mechanism that allows you to "register" an importer, without modifying
      this unit's implementation, may be done --- report if needed.)

    @item(3D formats are also listed in the file filters constants:
      see Load3D_FileFilters and Load3DSequence_FileFilters.
      Each format has a file filter to specifically choose this format,
      and also is added to the "All 3D models" filter.)

    @item(Enable view3dscene to associate with this file format on freedesktops
      (GNOME, and other following freedesktop.org specs). For this,

      1. Update view3dscene MIME database.
      Simply add appopriate element to ../../../view3dscene/desktop/view3dscene.xml.
      Format of that MIME xml file is self-explanatory.
      It's good idea to google first
      to search for standard MIME type for your model format (e.g. wikipedia
      shows mime types for formats).
      If none is found, just use application/x-???, where ??? is some short
      name for your format.

      2. After adding to MIME database, you want to also add format to
      ../../../view3dscene/desktop/view3dscene.desktop, to indicate that
      view3dscene handles this MIME type.

      3. Finally, also add this to ../../../view3dscene/desktop/install_thumbnailer.sh,
      so that GNOME nautilus thumbnailers for this MIME types can be installed.)

    @item(You probably also want to extend documentation.
      At least ../../../cge-www/htdocs/view3dscene.php, it has a "Features" section that lists
      all supported 3D formats.)
  )
}
unit X3DLoad;

{$I castleconf.inc}

interface

uses SysUtils, Classes,
  CastleUtils, CastleVectors, X3DNodes;

{ Load 3D model. Guess model format based on URL extension.
  VRML/X3D formats are loaded directly,
  other model formats are converted under the hood to VRML/X3D.

  URL is downloaded using CastleDownload unit.
  If you all you care about is loading normal files, then just pass
  a normal filename (absolute or relative to the current directory)
  as the URL parameter.

  @param(AllowStdIn If AllowStdIn and URL = '-' then it will load
    a VRML/X3D file from StdInStream (using current working directory
    as BaseUrl).) }
function Load3D(const URL: string;
  AllowStdIn: boolean = false;
  NilOnUnrecognizedFormat: boolean = false): TX3DRootNode;

const
  { File filters for files loaded by Load3D, suitable
    for TFileFilterList.AddFiltersFromString and TCastleWindowCustom.FileDialog. }
  Load3D_FileFilters =
  'All Files|*|' +
  '*All 3D models|*.wrl;*.wrl.gz;*.wrz;*.x3d;*.x3dz;*.x3d.gz;*.x3dv;*.x3dvz;*.x3dv.gz;*.kanim;*.castle-anim-frames;*.dae;*.iv;*.3ds;*.md3;*.obj;*.geo;*.json;*.stl|' +
  'VRML (*.wrl, *.wrl.gz, *.wrz)|*.wrl;*.wrl.gz;*.wrz|' +
  { TODO:
    and X3D binary (*.x3db;*.x3db.gz)
  }
  'X3D XML (*.x3d, *.x3dz, *.x3d.gz)|*.x3d;*.x3dz;*.x3d.gz|' +
  'X3D classic (*.x3dv, *.x3dvz, *.x3dv.gz)|*.x3dv;*.x3dvz;*.x3dv.gz|' +
  'Castle Animation Frames (*.castle-anim-frames, *.kanim)|*.castle-anim-frames;*.kanim|' +
  'Collada (*.dae)|*.dae|' +
  'Inventor (*.iv)|*.iv|' +
  '3D Studio (*.3ds)|*.3ds|' +
  'Quake 3 engine models (*.md3)|*.md3|' +
  'Wavefront (*.obj)|*.obj|' +
  'Videoscape (*.geo)|*.geo|' +
  'Spine animation (*.json)|*.json|' +
  'Standard Triangle Language (*.stl)|*.stl';

  SaveX3D_FileFilters =
  'All files|*|' +
  '*X3D XML (*.x3d)|*.x3d|' +
  'X3D XML (compressed) (*.x3dz, *.x3d.gz)|*.x3dz;*.x3d.gz|' +
  'X3D classic (*.x3dv)|*.x3dv|' +
  'X3D classic (compressed) (*.x3dvz, *.x3dv.gz)|*.x3dvz;*.x3dv.gz';

{ Load various model formats as animation expressed by VRML/X3D sequence.

  For model formats that cannot express animations (like GEO or Wavefront OBJ)
  or that express animations in a single file (like VRML/X3D >= 2.0)
  we load them exactly like Load3D, adding exactly one item
  to KeyNodes.
  So this function handles @italic(at least) the same model formats as Load3D.

  Additionally, we load castle-anim-frames and MD3 formats to a sequence of frames.

  @param(KeyNodes Sequence of root nodes will be stored there.
    Pass here some created and empty instance of TX3DNodeList.)

  @param(KeyTimes Sequence of time values.
    Pass here some created and empty instance of TSingleList.)
}
procedure Load3DSequence(
  const URL: string;
  const AllowStdIn: boolean;
  const KeyNodes: TX3DNodeList;
  const KeyTimes: TSingleList;
  out ScenesPerTime: Cardinal;
  out Epsilon: Single;
  out TimeLoop, TimeBackwards: boolean); deprecated 'use Load3D instead of Load3DSequence';

const
  { File filters for files loaded by Load3DSequence, suitable
    for TFileFilterList.AddFiltersFromString and TCastleWindowCustom.FileDialog. }
  Load3DSequence_FileFilters = Load3D_FileFilters deprecated 'use Load3D_FileFilters, and use Load3D instead of Load3DSequence';

const
  DefaultBakedAnimationSmoothness = 1;

var
  { A smoothness value for "baked" animations loaded from castle-anim-frames
    files. This is multiplied by the scenes_per_time value recorded
    in castle-anim-frames file (30 by default), and determines the number
    of extra frames we add to the baked animation (between key frames). }
  BakedAnimationSmoothness: Single = DefaultBakedAnimationSmoothness;

implementation

uses CastleClassUtils, CastleURIUtils,
  X3DLoadInternalGEO, X3DLoadInternal3DS, X3DLoadInternalOBJ,
  X3DLoadInternalCollada, X3DLoadInternalSpine, X3DLoadInternalSTL, X3DLoadInternalMD3,
  CastleInternalNodeInterpolator;

function Load3D(const URL: string;
  AllowStdIn, NilOnUnrecognizedFormat: boolean): TX3DRootNode;

  function LoadAnimFrames(const URL: string): TX3DRootNode;
  var
    Animations: TNodeInterpolator.TAnimationList;
  begin
    Animations := TNodeInterpolator.LoadAnimFramesToKeyNodes(URL);
    try
      Result := TNodeInterpolator.LoadToX3D(Animations);
    finally FreeAndNil(Animations) end;
  end;

  function LoadMD3(const URL: string): TX3DRootNode;
  var
    Animations: TNodeInterpolator.TAnimationList;
  begin
    Animations := LoadMD3Sequence(URL);
    try
      Result := TNodeInterpolator.LoadToX3D(Animations);
    finally FreeAndNil(Animations) end;
  end;

var
  MimeType: string;
  Gzipped: boolean;
begin
  if AllowStdIn and (URL = '-') then
    result := LoadX3DClassic(URL, true, false) else
  begin
    MimeType := URIMimeType(URL, Gzipped);

    if (MimeType = 'application/x-inventor') or
       (MimeType = 'model/vrml') or
       (MimeType = 'model/x3d+vrml') then
      Result := LoadX3DClassic(URL, false, Gzipped) else

    if MimeType = 'model/x3d+xml' then
      Result := LoadX3DXml(URL, Gzipped) else

    if MimeType = 'application/x-geo' then
      Result := LoadGEO(URL) else

    if MimeType = 'image/x-3ds' then
      Result := Load3DS(URL) else

    if MimeType = 'application/x-wavefront-obj' then
      Result := LoadWavefrontOBJ(URL) else

    if MimeType = 'model/vnd.collada+xml' then
      Result := LoadCollada(URL) else

    if (MimeType = 'application/json') or
       { For Spine, we will strip anchor in LoadSpine, so we can guess MIME
         based on URL without anchor too. Otherwise xxx.json#skinname
         would not be detected as Spine JSON.
         Note that we should not do this in URIMimeType implementation,
         as it depends on reader implementation whether anchor is understood
         (and stripped). }
       (URIMimeType(URIDeleteAnchor(URL, true), Gzipped) = 'application/json') then
      Result := LoadSpine(URL) else

    if MimeType = 'application/x-castle-anim-frames' then
      Result := LoadAnimFrames(URL) else

    if MimeType = 'application/x-md3' then
      Result := LoadMD3(URL) else

    if (MimeType = 'application/x-stl') or
       { try also other STL mime types }
       (MimeType = 'application/wavefront-stl') or
       (MimeType = 'application/vnd.ms-pki.stl') or
       (MimeType = 'application/x-navistyle') then
      Result := LoadSTL(URL) else

    if NilOnUnrecognizedFormat then
      Result := nil else
      raise Exception.CreateFmt(
        'Unrecognized file type "%s" for 3D model file "%s"',
        [MimeType, URIDisplay(URL)]);
  end;
end;

procedure Load3DSequence(const URL: string;
  const AllowStdIn: boolean;
  const KeyNodes: TX3DNodeList;
  const KeyTimes: TSingleList;
  out ScenesPerTime: Cardinal;
  out Epsilon: Single;
  out TimeLoop, TimeBackwards: boolean);

  procedure LoadNodeAnimation(Animations: TNodeInterpolator.TAnimationList);
  var
    Animation: TNodeInterpolator.TAnimation;
    I: Integer;
  begin
    { This obsolete routine just reads the 1st animation only.
      There's no way to support multiple animations with this interface. }
    Animation := Animations[0];

    for I := 0 to Animation.KeyNodes.Count - 1 do
      KeyNodes.Add(Animation.KeyNodes[I]);
    for I := 0 to Animation.KeyTimes.Count - 1 do
      KeyTimes.Add(Animation.KeyTimes[I]);
    ScenesPerTime   := Animation.ScenesPerTime;
    Epsilon         := Animation.Epsilon;
    TimeLoop        := Animation.Loop;
    TimeBackwards   := Animation.Backwards;

    FreeAndNil(Animations);
  end;

  procedure LoadSingle(Node: TX3DNode);
  begin
    KeyNodes.Add(Node);
    KeyTimes.Add(0); { One time value }
    ScenesPerTime := 1;      { doesn't matter }
    Epsilon := 0.0;  { doesn't matter }
    TimeLoop := false;      { doesn't matter }
    TimeBackwards := false; { doesn't matter }
  end;

var
  MimeType: string;
begin
  Assert(KeyTimes.Count = 0);
  Assert(KeyNodes.Count = 0);

  MimeType := URIMimeType(URL);

  if MimeType = 'application/x-castle-anim-frames' then
    LoadNodeAnimation(TNodeInterpolator.LoadAnimFramesToKeyNodes(URL))
  else
  if MimeType = 'application/x-md3' then
    LoadNodeAnimation(LoadMD3Sequence(URL))
  else
    LoadSingle(Load3D(URL, AllowStdIn));
end;

end.