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

PredatorCZ / HavokLib / 90

07 Nov 2025 09:36AM UTC coverage: 62.461% (-1.4%) from 63.837%
90

push

github

PredatorCZ
add support for scene data

556 of 1153 new or added lines in 22 files covered. (48.22%)

205 existing lines in 35 files now uncovered.

2777 of 4446 relevant lines covered (62.46%)

124997.44 hits per line

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

81.05
/source/hka_delta_decompressor.cpp
1
/*  Havok Format Library
2
    Copyright(C) 2016-2022 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 "hka_delta_decompressor.hpp"
19
#include <algorithm>
20
#include <climits>
21
#include <cmath>
22

23
void Decompress(float offset, float scale, char *buffer, char bitWidth,
174,720✔
24
                size_t numItems, std::vector<float> &container) {
25
  float refFrame = container.back();
174,720✔
26
  size_t curItem = 0;
27
  size_t currentBit = 0;
28
  const uint32 bitMask = (1 << bitWidth) - 1;
174,720✔
29
  uint32 *currentBuffer = reinterpret_cast<uint32 *>(buffer);
30
  const float fractal = 1.0f / bitMask;
174,720✔
31

32
  while (curItem < numItems) {
1,357,440✔
33
    uint32 curNumber = (*currentBuffer >> currentBit) & bitMask;
1,182,720✔
34
    currentBit += bitWidth;
1,182,720✔
35

36
    if (currentBit > 31) {
1,182,720✔
37
      currentBit -= 32;
336,000✔
38
      currentBuffer++;
336,000✔
39

40
      if (currentBit) {
336,000✔
41
        const uint32 subNumber = (*currentBuffer & ((1 << currentBit) - 1))
336,000✔
42
                                 << (bitWidth - currentBit);
336,000✔
43
        curNumber |= subNumber;
336,000✔
44
      }
45
    }
46

47
    float dequantized =
1,182,720✔
48
        refFrame + (offset + static_cast<float>(curNumber) * scale * fractal);
1,182,720✔
49
    refFrame = dequantized;
50
    container.push_back(dequantized);
1,182,720✔
51
    curItem++;
1,182,720✔
52
  }
53
}
174,720✔
54

55
void hkaDeltaDecompressor::Assign(
64✔
56
    hkaDeltaCompressedAnimationInternalInterface *input) {
57
  char *buffer = const_cast<char *>(input->GetData());
64✔
58
  auto anim = static_cast<const hkaAnimation *>(input);
64✔
59
  const size_t numTracks = anim->GetNumOfTransformTracks();
64✔
60
  const size_t numFloatTracks = anim->GetNumOfFloatTracks();
64✔
61
  const size_t numDynTracks = input->GetNumDynamicTracks();
64✔
62
  const size_t numFrames = input->GetNumOfPoses();
64✔
63

64
  uint8 *bitWidthStart =
65
      reinterpret_cast<uint8 *>(buffer + input->GetBitWidthOffset());
64✔
66
  StaticMask *masksStart =
67
      reinterpret_cast<StaticMask *>(buffer + input->GetStaticMaskOffset());
64✔
68
  float *offsetsStart =
69
      reinterpret_cast<float *>(buffer + input->GetOffsetsOffset());
64✔
70
  float *scalesStart =
71
      reinterpret_cast<float *>(buffer + input->GetScalesOffset());
64✔
72

73
  bitWidths = {bitWidthStart, numDynTracks};
64✔
74
  masks = {masksStart, numTracks + numFloatTracks};
64✔
75
  offsets = {offsetsStart, numDynTracks};
64✔
76
  scales = {scalesStart, numDynTracks};
64✔
77

78
  tracks.reserve(numTracks);
64✔
79
  floats.reserve(numFloatTracks);
64✔
80

81
  float *staticBuffer =
82
      reinterpret_cast<float *>(buffer + input->GetStaticDataOffset());
64✔
83

84
  buffer += input->GetQuantizedDataOffset();
64✔
85

86
  std::vector<DynamicTrack<float>> dynamicTracks;
64✔
87
  dynamicTracks.resize(numDynTracks);
64✔
88

89
  const size_t blockSize = input->GetBlockSize();
64✔
90
  const size_t numBlocks =
64✔
91
      static_cast<size_t>(ceilf(numFrames / static_cast<float>(blockSize)));
64✔
92
  const size_t numPreserved = input->GetNumPreserved();
64✔
93

94
  for (size_t b = 0; b < numBlocks; b++) {
896✔
95
    size_t numItems = blockSize * (b + 1);
832✔
96

97
    if (numItems > numFrames)
832✔
98
      numItems = numFrames % blockSize;
64✔
99
    else
100
      numItems = blockSize;
101

102
    for (size_t p = 0; p < numDynTracks; p++) {
175,552✔
103
      auto &tck = dynamicTracks[p];
104

105
      for (size_t pr = 0; pr < numPreserved; pr++) {
349,440✔
106
        tck.items.push_back(*reinterpret_cast<float *>(buffer));
174,720✔
107
        buffer += 4;
174,720✔
108
      }
109

110
      const size_t deltaSize = (bitWidths[p] * (numItems - 1) + 7) >> 3;
174,720✔
111

112
      Decompress(offsets[p], scales[p], buffer, bitWidths[p], numItems - 1,
174,720✔
113
                 tck.items);
174,720✔
114
      buffer += deltaSize;
174,720✔
115
    }
116
  }
117

118
  size_t curDynTrack = 0;
64✔
119

120
  for (size_t p = 0; p < numTracks; p++) {
6,016✔
121
    const StaticMask &mask = masks[p];
122
    tracks.emplace_back(std::make_unique<MasterTrack>(mask));
5,952✔
123
    auto &mRef = tracks.back();
124

125
    auto CopyDynamic = [&](StaticMask::MaskType msk, size_t id,
19,776✔
126
                           DynamicTrack<Vector4A16> *tck) {
127
      if (mask.UseSubTrack(msk)) {
19,776✔
128
        auto cTrack = dynamicTracks[curDynTrack++].items.begin();
13,440✔
129
        for (auto &c : tck->items) {
1,370,880✔
130
          c[id] = *cTrack++;
1,357,440✔
131
        }
132
      }
133
    };
5,952✔
134

135
    switch (mask.GetPosTrackType()) {
5,952✔
136
    case TT_STATIC: {
137
      StaticTrack<Vector4A16> *tck =
138
          static_cast<StaticTrack<Vector4A16> *>(mRef->pos.get());
139
      tck->track = reinterpret_cast<Vector &>(*staticBuffer);
5,632✔
140
      staticBuffer += 3;
5,632✔
141
      break;
5,632✔
142
    }
143
    case TT_DYNAMIC: {
144
      DynamicTrack<Vector4A16> *tck =
145
          static_cast<DynamicTrack<Vector4A16> *>(mRef->pos.get());
146

147
      Vector staticValues;
148

149
      if (!mask.UseSubTrack(StaticMask::posX)) {
192✔
150
        staticValues.X = *staticBuffer;
151
        staticBuffer++;
152
      }
153
      if (!mask.UseSubTrack(StaticMask::posY)) {
192✔
154
        staticValues.Y = *staticBuffer;
64✔
155
        staticBuffer++;
64✔
156
      }
157
      if (!mask.UseSubTrack(StaticMask::posZ)) {
192✔
158
        staticValues.Z = *staticBuffer;
159
        staticBuffer++;
160
      }
161

UNCOV
162
      if (mask.UseSubTrack(StaticMask::posX) ||
×
163
          mask.UseSubTrack(StaticMask::posY) ||
192✔
164
          mask.UseSubTrack(StaticMask::posZ)) {
165
        tck->items.insert(tck->items.begin(), numFrames, staticValues);
192✔
166
      }
167

168
      CopyDynamic(StaticMask::posX, 0, tck);
192✔
169
      CopyDynamic(StaticMask::posY, 1, tck);
192✔
170
      CopyDynamic(StaticMask::posZ, 2, tck);
192✔
171

172
      break;
173
    }
174
    default:
175
      break;
176
    }
177

178
    switch (mask.GetRotTrackType()) {
5,952✔
179
    case TT_STATIC: {
180
      StaticTrack<Vector4A16> *tck =
181
          static_cast<StaticTrack<Vector4A16> *>(mRef->rot.get());
182
      memcpy(tck->track._arr, staticBuffer, sizeof(Vector4A16));
1,152✔
183
      staticBuffer += 4;
1,152✔
184
      break;
1,152✔
185
    }
186
    case TT_DYNAMIC: {
187
      DynamicTrack<Vector4A16> *tck =
188
          static_cast<DynamicTrack<Vector4A16> *>(mRef->rot.get());
189

190
      Vector4A16 staticValues;
191

192
      if (!mask.UseSubTrack(StaticMask::rotX)) {
4,800✔
193
        staticValues.X = *staticBuffer;
640✔
194
        staticBuffer++;
640✔
195
      }
196
      if (!mask.UseSubTrack(StaticMask::rotY)) {
4,800✔
197
        staticValues.Y = *staticBuffer;
768✔
198
        staticBuffer++;
768✔
199
      }
200
      if (!mask.UseSubTrack(StaticMask::rotZ)) {
4,800✔
201
        staticValues.Z = *staticBuffer;
320✔
202
        staticBuffer++;
320✔
203
      }
204
      if (!mask.UseSubTrack(StaticMask::rotW)) {
4,800✔
205
        staticValues.W = *staticBuffer;
4,544✔
206
        staticBuffer++;
4,544✔
207
      }
208

209
      if (mask.UseSubTrack(StaticMask::rotX) ||
640✔
210
          mask.UseSubTrack(StaticMask::rotY) ||
640✔
211
          mask.UseSubTrack(StaticMask::rotZ) ||
4,800✔
212
          mask.UseSubTrack(StaticMask::rotW)) {
213
        tck->items.insert(tck->items.begin(), numFrames, staticValues);
4,800✔
214
      }
215

216
      CopyDynamic(StaticMask::rotX, 0, tck);
4,800✔
217
      CopyDynamic(StaticMask::rotY, 1, tck);
4,800✔
218
      CopyDynamic(StaticMask::rotZ, 2, tck);
4,800✔
219
      CopyDynamic(StaticMask::rotW, 3, tck);
4,800✔
220

221
      for (auto &t : tck->items) {
489,600✔
222
        if (t.W == 2.0f || t.W == -2.0f) {
484,800✔
223
          float basis = t.W * 0.5f;
452,480✔
224
          t.W = 0.f;
452,480✔
225
          t.QComputeElement();
226
          t.W *= basis;
452,480✔
227
        }
228
      }
229
      break;
230
    }
231
    default:
232
      break;
233
    }
234

235
    switch (mask.GetScaleTrackType()) {
5,952✔
236
    case TT_STATIC: {
237
      StaticTrack<Vector4A16> *tck =
238
          static_cast<StaticTrack<Vector4A16> *>(mRef->scale.get());
239
      tck->track = reinterpret_cast<Vector &>(*staticBuffer);
×
240
      staticBuffer += 3;
241
      break;
×
242
    }
243
    case TT_DYNAMIC: {
244
      DynamicTrack<Vector4A16> *tck =
245
          static_cast<DynamicTrack<Vector4A16> *>(mRef->scale.get());
246

247
      Vector staticValues;
248

249
      if (!mask.UseSubTrack(StaticMask::scaleX)) {
×
250
        staticValues.X = *staticBuffer;
251
        staticBuffer++;
252
      }
253
      if (!mask.UseSubTrack(StaticMask::scaleY)) {
×
254
        staticValues.Y = *staticBuffer;
255
        staticBuffer++;
256
      }
257
      if (!mask.UseSubTrack(StaticMask::scaleZ)) {
×
258
        staticValues.Z = *staticBuffer;
259
        staticBuffer++;
260
      }
261

262
      if (mask.UseSubTrack(StaticMask::scaleX) ||
×
263
          mask.UseSubTrack(StaticMask::scaleY) ||
×
264
          mask.UseSubTrack(StaticMask::scaleZ)) {
265
        tck->items.insert(tck->items.begin(), numFrames, staticValues);
×
266
      }
267

268
      CopyDynamic(StaticMask::scaleX, 0, tck);
×
269
      CopyDynamic(StaticMask::scaleY, 1, tck);
×
270
      CopyDynamic(StaticMask::scaleZ, 2, tck);
×
271

272
      break;
273
    }
274
    default:
275
      break;
276
    }
277

278
    for (size_t f = numTracks; f < numFloatTracks + numTracks; f++) {
5,952✔
279
      StaticMask &m = masks[f];
280

281
      switch (m.GetPosTrackType()) {
×
282
      case TT_IDENTITY:
×
283
        floats.emplace_back(std::make_unique<StaticTrack<float>>());
×
284
        break;
×
285
      case TT_STATIC:
×
286
        floats.emplace_back(
×
287
            std::make_unique<StaticTrack<float>>(*staticBuffer++));
×
288
        break;
×
289
      case TT_DYNAMIC: {
×
290
        auto cFloatTrack = std::make_unique<DynamicTrack<float>>();
×
291
        cFloatTrack->items.swap(dynamicTracks[curDynTrack++].items);
×
292
        floats.emplace_back(std::move(cFloatTrack));
×
293
        break;
294
      }
295
      }
296
    }
297
  }
298
}
64✔
299

300
MasterTrack::MasterTrack(const StaticMask &mask) {
17,856✔
301
  switch (mask.GetPosTrackType()) {
17,856✔
302
  case TT_IDENTITY:
17,280✔
303
  case TT_STATIC:
304
    pos = std::make_unique<StaticTrack<Vector4A16>>();
305
    break;
306
  case TT_DYNAMIC:
576✔
307
    pos = std::make_unique<DynamicTrack<Vector4A16>>();
576✔
308
    break;
576✔
309
  }
310

311
  switch (mask.GetRotTrackType()) {
17,856✔
312
  case TT_IDENTITY:
313
    rot = std::make_unique<StaticTrack<Vector4A16>>(Vector4A16{{}, 1.f});
314
    break;
×
315
  case TT_STATIC:
3,456✔
316
    rot = std::make_unique<StaticTrack<Vector4A16>>();
317
    break;
318
  case TT_DYNAMIC:
14,400✔
319
    rot = std::make_unique<DynamicTrack<Vector4A16>>();
14,400✔
320
    break;
14,400✔
321
  }
322

323
  switch (mask.GetScaleTrackType()) {
17,856✔
324
  case TT_IDENTITY:
325
    scale = std::make_unique<StaticTrack<Vector4A16>>(
326
        Vector4A16{1.f, 1.f, 1.f, 0.f});
327
    break;
328
  case TT_STATIC:
×
329
    scale = std::make_unique<StaticTrack<Vector4A16>>();
330
    break;
331
  case TT_DYNAMIC:
×
332
    scale = std::make_unique<DynamicTrack<Vector4A16>>();
×
333
    break;
×
334
  }
335
}
17,856✔
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

© 2025 Coveralls, Inc