• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PredatorCZ / HavokLib / 89

06 Nov 2025 01:09PM UTC coverage: 63.837% (-3.2%) from 67.014%
89

push

github

PredatorCZ
s

3354 of 5254 relevant lines covered (63.84%)

129082.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.81
/source/packfile/hka_skeleton.cpp
1
/*  Havok Format Library
2
    Copyright(C) 2016-2023 Lukas Cone
3

4
    This program is free software : you can redistribute it and / or modify
5
    it under the terms of the GNU General Public License as published by
6
    the Free Software Foundation, either version 3 of the License, or
7
    (at your option) any later version.
8

9
    This program is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12
    GNU General Public License for more details.
13

14
    You should have received a copy of the GNU General Public License
15
    along with this program.If not, see <https://www.gnu.org/licenses/>.
16
*/
17

18
#include "internal/hka_skeleton.hpp"
19
#include "base.hpp"
20
#include "hka_skeleton.inl"
21
#include "spike/uni/list_vector.hpp"
22
#include <span>
23

24
struct hkaSkeletonSaver {
25
  const hkaSkeletonInternalInterface *in;
26
  const clgen::hkaSkeleton::Interface *out;
27

28
  void Save(BinWritterRef wr, hkFixups &fixups) {
×
29
    const size_t sBegin = wr.Tell();
×
30
    auto &locals = fixups.locals;
×
31
    auto &lay = *out->layout;
×
32
    using mm = clgen::hkaSkeleton::Members;
33

34
    wr.WriteBuffer(out->data, lay.totalSize);
×
35
    wr.ApplyPadding();
×
36
    locals.emplace_back(sBegin + out->m(mm::name), wr.Tell());
×
37
    wr.WriteContainer(in->Name());
×
38
    wr.Skip(1);
×
39

40
    const size_t numBones = in->GetNumBones();
×
41

42
    if (numBones) {
×
43
      wr.ApplyPadding(8);
×
44
      locals.emplace_back(sBegin + out->m(mm::parentIndices), wr.Tell());
×
45

46
      for (auto i : in->BoneParentIDs()) {
×
47
        wr.Write(i);
×
48
      }
49

50
      wr.ApplyPadding();
×
51
      locals.emplace_back(sBegin + out->m(mm::transforms), wr.Tell());
×
52

53
      for (auto i : in->BoneTransforms()) {
×
54
        wr.Write(i);
×
55
      }
56

57
      wr.ApplyPadding(8);
×
58
      locals.emplace_back(sBegin + out->m(mm::bones), wr.Tell());
×
59
      size_t curFixup = locals.size();
×
60
      const auto boneType =
61
          clgen::GetLayout(clgen::hkaBone::LAYOUTS, out->lookup);
×
62

63
      if (out->LayoutVersion() < HK700) {
×
64
        size_t curGFixup = fixups.globals.size();
×
65

66
        for (size_t i = 0; i < numBones; i++) {
×
67
          fixups.globals.emplace_back(wr.Tell());
×
68
          wr.Skip(lay.ptrSize);
×
69
        }
70

71
        auto fndFinal =
72
            std::find_if(fixups.finals.begin(), fixups.finals.end(),
×
73
                         [&](const hkFixup &f) { return f.destClass == in; });
×
74

75
        if (es::IsEnd(fixups.finals, fndFinal)) {
×
76
          throw std::runtime_error("hkaBone final was not found");
×
77
        }
78

79
        for (size_t i = 0; i < numBones; i++) {
×
80
          wr.ApplyPadding(8);
×
81
          fixups.globals[curGFixup++].destination = wr.Tell();
×
82
          const size_t bneBegin = wr.Tell();
×
83
          fndFinal->destination = bneBegin;
×
84
          fndFinal++;
×
85
          wr.Skip(boneType->totalSize);
×
86
          wr.ApplyPadding(8);
×
87
          locals.emplace_back(bneBegin, wr.Tell());
×
88
          wr.WriteContainer(in->GetBoneName(i));
×
89
          wr.Skip(1);
×
90
        }
91
      } else {
92
        for (size_t i = 0; i < numBones; i++) {
×
93
          locals.emplace_back(wr.Tell());
×
94
          wr.Skip(boneType->totalSize);
×
95
        }
96
        for (auto i : in->BoneNames()) {
×
97
          wr.ApplyPadding(8);
×
98
          locals[curFixup++].destination = wr.Tell();
×
99
          wr.WriteContainer(i);
×
100
          wr.Skip(1);
×
101
        }
102
      }
103
    }
104
  }
105
};
106

107
class hkFullBone : public uni::Bone {
108
public:
109
  std::string_view name;
110
  const hkQTransform *tm = nullptr;
111
  hkFullBone *parent = nullptr;
112
  size_t id;
113

114
  uni::TransformType TMType() const override {
186✔
115
    return uni::TransformType::TMTYPE_RTS;
186✔
116
  }
117
  void GetTM(uni::RTSValue &out) const override {
93✔
118
    out = tm ? *tm : uni::RTSValue{};
93✔
119
  }
93✔
120
  const Bone *Parent() const override { return parent; }
93✔
121
  size_t Index() const override { return id; }
182✔
122
  std::string Name() const override { return std::string{name}; }
93✔
123
  operator uni::Element<const uni::Bone>() const {
94✔
124
    return {static_cast<const uni::Bone *>(this), false};
94✔
125
  }
126
};
127

128
struct hkaSkeletonMidInterface : hkaSkeletonInternalInterface {
129
  clgen::hkaSkeleton::Interface interface;
130
  std::unique_ptr<hkaSkeletonSaver> saver;
131
  uni::VectorList<uni::Bone, hkFullBone> bones;
132

133
  hkaSkeletonMidInterface(clgen::LayoutLookup rules, char *data)
137✔
134
      : interface{data, rules} {}
137✔
135

136
  void SetDataPointer(void *ptr) override {
137✔
137
    interface.data = static_cast<char *>(ptr);
137✔
138
  }
137✔
139

140
  const void *GetPointer() const override { return interface.data; }
201✔
141

142
  size_t GetNumBones() const override { return interface.NumBones(); }
425✔
143

144
  void Process() override {
137✔
145
    const size_t numParentIndices = interface.NumParentIndices();
137✔
146
    const size_t numTransforms = interface.NumTransforms();
137✔
147

148
    if (!numParentIndices || !numTransforms) {
137✔
149
      return;
×
150
    }
151

152
    size_t numBones = GetNumBones();
137✔
153
    bones.storage.resize(numBones);
137✔
154

155
    if (interface.LayoutVersion() >= HK700) {
137✔
156
      auto bonesIter = interface.BonesHK700();
105✔
157

158
      for (size_t b = 0; b < numBones; b++, bonesIter.Next()) {
5,742✔
159
        bones.storage.at(b).name = bonesIter.Name();
5,637✔
160
      }
161
    } else {
162
      auto bonesIter = interface.Bones();
32✔
163

164
      for (size_t b = 0; b < numBones; b++, bonesIter.Next()) {
1,632✔
165
        hkFullBone &bone = bones.storage.at(b);
1,600✔
166
        bone.name = (**bonesIter).Name();
1,600✔
167
      }
168
    }
169

170
    for (size_t b = 0; b < numBones; b++) {
7,374✔
171
      hkFullBone &bone = bones.storage.at(b);
7,237✔
172
      bone.id = b;
7,237✔
173
      int16 prentID = interface.ParentIndices()[b];
7,237✔
174
      bone.parent = prentID < 0 ? nullptr : &bones.storage[prentID];
7,237✔
175
      bone.tm = interface.Transforms() + b;
7,237✔
176
    }
177
  }
178

179
  std::string_view GetBoneName(size_t id) const override {
6,696✔
180
    return bones.storage.at(id).name;
6,696✔
181
  }
182
  const hkQTransform *GetBoneTM(size_t id) const override {
6,696✔
183
    return bones.storage.at(id).tm;
6,696✔
184
  }
185
  int16 GetBoneParentID(size_t id) const override {
6,696✔
186
    if (auto parent = bones.storage.at(id).parent) {
6,696✔
187
      return parent->id;
6,408✔
188
    }
189

190
    return -1;
288✔
191
  }
192
  std::string Name() const override { return interface.Name(); };
73✔
193
  uni::SkeletonBonesConst Bones() const override {
2✔
194
    return uni::SkeletonBonesConst(
195
        static_cast<const uni::List<uni::Bone> *>(&bones), false);
2✔
196
  }
197

198
  size_t GetNumFloatSlots() const override {
144✔
199
    return interface.NumFloatSlots();
144✔
200
  };
201
  std::string_view GetFloatSlot(size_t id) const override {
216✔
202
    return **interface.FloatSlots().Next(id);
216✔
203
  };
204
  size_t GetNumLocalFrames() const override {
×
205
    return interface.NumLocalFrames();
×
206
  };
207
  hkLocalFrameOnBone GetLocalFrame(size_t id) const override {
×
208
    auto item = interface.LocalFrames().Next(id);
×
209
    return {item.LocalFrame(), item.BoneIndex()};
×
210
  };
211
  size_t GetNumPartitions() const override {
16✔
212
    return interface.NumPartitions();
16✔
213
  };
214
  hkaPartition GetPartition(size_t id) const override {
64✔
215
    auto item = interface.Partitions().Next(id);
64✔
216
    return {item.Name(), item.StartBoneIndex(), item.NumBones()};
64✔
217
  };
218
  size_t GetNumReferenceFloats() const override {
96✔
219
    return interface.NumReferenceFloats();
96✔
220
  };
221
  float GetReferenceFloat(size_t id) const override {
144✔
222
    return interface.ReferenceFloats()[id];
144✔
223
  }
224

225
  void SwapEndian() override {
69✔
226
    clgen::EndianSwap(interface);
69✔
227

228
    for (std::span<int16> indices(interface.ParentIndices(),
69✔
229
                                  interface.NumParentIndices());
69✔
230
         auto &i : indices) {
3,803✔
231
      FByteswapper(i);
3,665✔
232
    }
233

234
    for (std::span<hkQTransform> tms(interface.Transforms(),
69✔
235
                                     interface.NumTransforms());
69✔
236
         auto &i : tms) {
3,803✔
237
      FByteswapper(i.rotation);
3,665✔
238
      FByteswapper(i.scale);
3,665✔
239
      FByteswapper(i.translation);
3,665✔
240
    }
241

242
    for (std::span<float> refs(interface.ReferenceFloats(),
69✔
243
                               interface.NumReferenceFloats());
69✔
244
         auto &i : refs) {
213✔
245
      FByteswapper(i);
75✔
246
    }
247

248
    {
249
      size_t numParts = interface.NumPartitions();
69✔
250
      auto parts = interface.Partitions();
69✔
251

252
      for (size_t i = 0; i < numParts; i++, parts.Next()) {
173✔
253
        clgen::EndianSwap(parts);
104✔
254
      }
255
    }
256

257
    {
258
      size_t numParts = interface.NumLocalFrames();
69✔
259
      auto parts = interface.LocalFrames();
69✔
260

261
      for (size_t i = 0; i < numParts; i++, parts.Next()) {
69✔
262
        clgen::EndianSwap(parts);
×
263
      }
264
    }
265
  }
69✔
266

267
  void Reflect(const IhkVirtualClass *other) override {
×
268
    interface.data = static_cast<char *>(malloc(interface.layout->totalSize));
×
269
    saver = std::make_unique<hkaSkeletonSaver>();
×
270
    saver->in = static_cast<const hkaSkeletonInternalInterface *>(
×
271
        checked_deref_cast<const hkaSkeleton>(other));
×
272
    saver->out = &interface;
×
273
    interface.NumBones(saver->in->GetNumBones());
×
274
    interface.NumParentIndices(saver->in->GetNumBones());
×
275
    interface.NumTransforms(saver->in->GetNumBones());
×
276
    interface.NumFloatSlots(saver->in->GetNumFloatSlots());
×
277
    interface.NumReferenceFloats(saver->in->GetNumReferenceFloats());
×
278
    interface.NumPartitions(saver->in->GetNumPartitions());
×
279
    interface.NumLocalFrames(saver->in->GetNumLocalFrames());
×
280
  }
281

282
  void Save(BinWritterRef wr, hkFixups &fixups) const override {
×
283
    saver->Save(wr, fixups);
×
284
  }
285

286
  ~hkaSkeletonMidInterface() {
274✔
287
    if (saver) {
137✔
288
      free(interface.data);
×
289
    }
290
  }
274✔
291
};
137✔
292

293
CREATE_HK_CLASS(hkaSkeleton);
294

295
REFLECT(CLASS(hkaPartition), MEMBER(name), MEMBER(startBoneIndex),
137✔
296
        MEMBER(numBones));
137✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc