This file is indexed.

/usr/src/castle-game-engine-5.2.0/x3d/x3dloadinternalspine_skeleton.inc is in castle-game-engine-src 5.2.0-3.

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
{
  Copyright 2014-2014 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.

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

{ Spine skeleton, corresponding to a single Spine JSON file. }

{$ifdef read_interface}
  TSkeleton = class
    Root: TBone;
    { Bones, in the order specified in JSON file, so it's guaranteed
      that parent is always specified before any of it's children
      (this is very comfortable for processing). }
    Bones: TBoneList;
    Slots: TSlotList;
    Skins: TSkinList;
    Animations: TAnimationList;
    { After parsing skins, we calculate default and current skin
      (used to search for attachments). They cannot be @nil.
      It is possible that CurrentSkin = DefaultSkin.
      For now, CurrentSkin remains local in BuildNodes, no need to make
      it public.
      @groupBegin }
    DefaultSkin: TSkin;
    { @groupEnd }
    { List of bones/slots (all present also on TSkeleton.Bones/Slots list)
      that have their translation/rotation/scale (in case of bones)
      or attachment/color (in case of slots) modified by @italic(any) animation.
      This is useful to gather, as this is the minimal set of things
      reset to bring back model to initial (pose) state.
      Calculated during TSkeleton.Parse, used during TSkeleton.BuildNodes.
      @groupBegin }
    BonesAnimated: TBonesAnimated;
    SlotsAnimated: TSlotsAnimated;
    { @groupEnd }
    constructor Create;
    destructor Destroy; override;
    procedure Parse(const Json: TJSONData);
    procedure BuildNodes(const BaseUrl: string; const TextureLoader: TTextureLoader;
      const Container: TX3DRootNode; const SkinName: string);
  end;
{$endif}

{$ifdef read_implementation}
constructor TSkeleton.Create;
begin
  inherited;
  Bones := TBoneList.Create;
  Slots := TSlotList.Create;
  Skins := TSkinList.Create;
  Animations := TAnimationList.Create;
  BonesAnimated := TBonesAnimated.Create;
  SlotsAnimated := TSlotsAnimated.Create;
end;

destructor TSkeleton.Destroy;
begin
  DefaultSkin := nil;
  FreeAndNil(Skins);
  FreeAndNil(Slots);
  Root := nil;
  FreeAndNil(Bones);
  FreeAndNil(Animations);
  FreeAndNil(BonesAnimated);
  FreeAndNil(SlotsAnimated);
  inherited;
end;

procedure TSkeleton.Parse(const Json: TJSONData);
var
  O: TJSONObject;
begin
  if not (Json is TJSONObject) then
    raise ESpineReadError.Create('Spine JSON skeleton: Expected JSONObject at root');
  O := TJSONObject(Json);

  Bones.Parse(O, Root);
  Slots.Parse(O, Bones);
  Skins.Parse(O, DefaultSkin, Bones);
  Animations.Parse(O, Bones, BonesAnimated, Slots, SlotsAnimated);

  WritelnLog('Spine', Format('Skeleton read, bones: %d, slots: %d, skins: %d, animations: %d',
    [Bones.Count, Slots.Count, Skins.Count, Animations.Count]));
end;

procedure TSkeleton.BuildNodes(const BaseUrl: string; const TextureLoader: TTextureLoader;
  const Container: TX3DRootNode; const SkinName: string);
var
  CurrentSkin: TSkin;

  procedure SkinLog;
  var
    S: string;
    I: Integer;
  begin
    S := Format('Available skins count: %d', [Skins.Count]) + NL;
    for I := 0 to Skins.Count - 1 do
      S += Format('  Available skin %d: %s', [I, Skins[I].Name]) + NL;
    S += Format('Using skin: %s', [CurrentSkin.Name]);
    WritelnLogMultiline('Spine', S);
  end;

var
  NavigationInfo: TNavigationInfoNode;
begin
  { add NavigationInfo indicating blendingSort = 2D }
  NavigationInfo := TNavigationInfoNode.Create('', BaseUrl);
  NavigationInfo.BlendingSort := obs2D;
  Container.FdChildren.Add(NavigationInfo);

  Bones.BuildNodes(BaseUrl, BonesAnimated);
  Root.NodeUsedAsChild := true;
  Container.FdChildren.Add(Root.Node);
  Skins.BuildNodes(BaseUrl, TextureLoader);

  CurrentSkin := nil;
  if SkinName <> '' then
    CurrentSkin := Skins.Find(SkinName, true);
  if CurrentSkin = nil then
  begin
    { prefer non-default skin, if exists, since default skin may miss some
      attachments, see goblins.json example }
    if Skins.Count > 1 then
      CurrentSkin := Skins[1] else
      CurrentSkin := DefaultSkin;
  end;
  if Log then
    SkinLog;

  Slots.BuildNodes(BaseUrl, SlotsAnimated, CurrentSkin.Attachments, DefaultSkin.Attachments, Container);
  Animations.BuildNodes(BaseUrl, Container, BonesAnimated, SlotsAnimated);
end;
{$endif}