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

PredatorCZ / RevilLib / 117

06 Nov 2023 06:12PM UTC coverage: 5.723% (-0.6%) from 6.277%
117

push

github

PredatorCZ
add mod xD3 x64

2 of 28 new or added lines in 3 files covered. (7.14%)

1200 existing lines in 3 files now uncovered.

351 of 6133 relevant lines covered (5.72%)

743.71 hits per line

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

0.09
/src/mtf_mod/serialize.cpp
1
/*  Revil Format Library
2
    Copyright(C) 2017-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 "header.hpp"
19
#include "spike/io/binreader.hpp"
20
#include "spike/io/binwritter.hpp"
21
#include "spike/util/endian.hpp"
22
#include "traits.hpp"
23
#include <map>
24

25
using namespace revil;
26

27
static constexpr uint32 MODID = CompileFourCC("MOD");
28
static constexpr uint32 DOMID = CompileFourCC("\0DOM");
29

30
template <class traits> void MODInner<traits>::Reflect(bool swap) {
×
31
  this->boneData.storage.reserve(bones.size());
×
32
  for (size_t i = 0; i < bones.size(); i++) {
×
33
    this->boneData.storage.emplace_back(*this, i, bones[i]);
×
34
  }
35

36
  this->primitives.storage.reserve(meshes.size());
×
37
  if (swap) {
×
38
    for (size_t i = 0; i < meshes.size(); i++) {
×
39
      this->primitives.storage.emplace_back(meshes[i].ReflectBE(*this));
×
40
    }
41
  } else {
42
    for (size_t i = 0; i < meshes.size(); i++) {
×
43
      this->primitives.storage.emplace_back(meshes[i].ReflectLE(*this));
×
44
    }
45
  }
46

47
  if (!bones.empty()) {
×
48
    this->skins.storage.reserve(std::min(skinRemaps.size(), size_t(1)));
×
49

50
    if (skinRemaps.empty()) {
×
51
      MODSkinProxy remap;
52
      remap.numRemaps = bones.size();
×
53
      remap.poses = transforms.data();
×
54
      this->skins.storage.emplace_back(remap);
×
55
    } else {
56
      for (auto &r : skinRemaps) {
×
57
        MODSkinProxy remap;
58
        remap.numRemaps = r.count;
×
59
        remap.remaps = r.bones;
×
60
        remap.poses = transforms.data();
×
61
        this->skins.storage.emplace_back(remap);
×
62
      }
63
    }
64
  }
65
}
66

×
67
template <class traits>
×
68
uni::PrimitivesConst MODInner<traits>::Primitives() const {
×
69
  return {&this->primitives, false};
×
70
}
71

72
template <class traits> uni::SkinsConst MODInner<traits>::Skins() const {
×
73
  return {&this->skins, false};
×
74
}
×
75

×
76
template <class traits>
77
uni::ResourcesConst MODInner<traits>::Resources() const {
78
  return {&this->paths, false};
×
79
}
×
80

81
template <class traits>
82
uni::MaterialsConst MODInner<traits>::Materials() const {
83
  return {&materials, false};
×
84
}
×
85

86
template <class material_type>
×
87
void MODMaterialProxy<material_type>::Write(BinWritterRef wr) const {
88
  auto main_ = main;
×
89
  main_.baseTextureIndex++;
×
90
  main_.normalTextureIndex++;
×
91
  main_.maskTextureIndex++;
92
  main_.lightTextureIndex++;
×
93
  main_.shadowTextureIndex++;
94
  main_.additionalTextureIndex++;
×
95
  main_.cubeMapTextureIndex++;
×
96
  main_.detailTextureIndex++;
×
97
  main_.AOTextureIndex++;
×
98
  wr.Write(main_);
99
}
100

101
template <class material_type>
102
void MODMaterialProxy<material_type>::Read(BinReaderRef_e rd) {
×
103
  rd.Read(main);
×
104
  if constexpr (!std::is_same_v<material_type, MODMaterialHash> &&
×
105
                !std::is_same_v<material_type, MODMaterialName>) {
×
106
    main.baseTextureIndex--;
107
    main.normalTextureIndex--;
108
    main.maskTextureIndex--;
×
109
    main.lightTextureIndex--;
×
110
    main.shadowTextureIndex--;
×
111
    main.additionalTextureIndex--;
×
112
    main.cubeMapTextureIndex--;
113
    main.detailTextureIndex--;
114
    main.AOTextureIndex--;
×
115
  }
×
116
}
117

118
template <class material_type>
119
std::string MODMaterialProxy<material_type>::TypeName() const {
×
120
  return "";
×
121
}
122

×
123
template <class T> using use_name = decltype(std::declval<T>().Name());
124
template <class C>
×
125
constexpr static bool use_name_v = es::is_detected_v<use_name, C>;
×
126

×
127
template <class material_type>
128
std::string MODMaterialProxy<material_type>::Name() const {
×
129
  if constexpr (use_name_v<material_type>) {
130
    return main.Name();
×
131
  } else {
×
132
    return "";
×
133
  }
×
134
}
135

136
template <class material_type>
137
size_t MODMaterialProxy<material_type>::Version() const {
138
  return material_type::Version();
×
139
}
×
140

×
141
template <class material_type>
×
142
uni::MetadataConst MODMaterialProxy<material_type>::Metadata() const {
143
  return {&asMetadata, false};
144
}
×
145

×
146
#pragma region Endian Swappers
×
147

×
148
template <> void FByteswapper(MODBoneV1 &self, bool) {
149
  FByteswapper(self.absolutePosition);
150
  FByteswapper(self.parentDistance);
×
151
}
×
152

153
template <> void FByteswapper(MODBoneV1_5 &self, bool) {
154
  FByteswapper(self.absolutePosition);
155
  FByteswapper(self.parentDistance);
×
156
  FByteswapper(self.furthestVertexDistance);
×
157
}
158

×
159
template <> void FByteswapper(MODBoneV2 &self, bool) {
160
  FByteswapper(self.absolutePosition);
×
161
  FByteswapper(self.parentDistance);
×
162
  FByteswapper(self.furthestVertexDistance);
×
163
  FByteswapper(self.index);
164
}
×
165

166
template <> void FByteswapper(MODBounds &self, bool) {
×
167
  FByteswapper(self.bboxMax);
×
168
  FByteswapper(self.bboxMin);
×
169
  FByteswapper(self.boundingSphere);
×
170
}
171

172
template <> void FByteswapper(MODEnvelope &self, bool) {
173
  FByteswapper(self.absolutePosition);
174
  FByteswapper(self.boneIndex);
×
175
  FByteswapper(self.bounds);
×
176
}
×
177

×
178
template <> void FByteswapper(MODGroup &self, bool) {
179
  FByteswapper(self.boundingSphere);
180
  FByteswapper(self.index);
×
181
}
×
182

×
183
template <> void FByteswapper(MODMetaDataV1 &self, bool) {
×
184
  FByteswapper(self.lightGroup);
185
  FByteswapper(self.lowDistance);
186
  FByteswapper(self.middleDistance);
×
187
}
×
188

189
template <> void FByteswapper(MODMetaDataV2 &self, bool) {
190
  FByteswapper(static_cast<MODMetaDataV1 &>(self));
191
  FByteswapper(self.numEnvelopes);
×
192
}
×
193

194
template <> void FByteswapper(MODSkinRemap<32> &self, bool) {
×
195
  FByteswapper(self.count);
196
}
×
197

×
198
template <> void FByteswapper(MODSkinRemap<64> &self, bool) {
×
199
  FByteswapper(self.count);
200
}
×
201

202
template <> void FByteswapper(MODHeaderCommon &self, bool) {
×
203
  FByteswapper(self.id);
×
204
  FByteswapper(self.version);
×
205
  FByteswapper(self.numBones);
×
206
  FByteswapper(self.numMeshes);
207
  FByteswapper(self.numMaterials);
208
  FByteswapper(self.numVertices);
209
  FByteswapper(self.numIndices);
210
  FByteswapper(self.numEdges);
×
211
}
×
212

×
213
template <> void FByteswapper(MODHeaderX99 &self, bool) {
×
214
  FByteswapper(static_cast<MODHeaderCommon &>(self));
215
  FByteswapper(self.vertexBufferSize);
216
  FByteswapper(self.unkBufferSize);
×
217
  FByteswapper(self.numTextures);
×
218
  FByteswapper(self.numGroups);
×
219
  FByteswapper(self.numBoneMaps);
×
220
  FByteswapper(self.bones);
221
  FByteswapper(self.groups);
222
  FByteswapper(self.textures);
×
223
  FByteswapper(self.meshes);
×
224
  FByteswapper(self.vertexBuffer);
225
  FByteswapper(self.unkBuffer);
226
  FByteswapper(self.indices);
227
}
×
228

×
229
template <> void FByteswapper(MODHeaderXC5 &self, bool) {
230
  FByteswapper(static_cast<MODHeaderCommon &>(self));
×
231
  FByteswapper(self.vertexBufferSize);
232
  FByteswapper(self.numTextures);
×
233
  FByteswapper(self.numGroups);
×
234
  FByteswapper(self.bones);
×
235
  FByteswapper(self.groups);
236
  FByteswapper(self.textures);
×
237
  FByteswapper(self.meshes);
238
  FByteswapper(self.vertexBuffer);
×
239
  FByteswapper(self.indices);
×
240
}
×
241

×
242
template <> void FByteswapper(MODHeaderXD2 &self, bool) {
243
  FByteswapper(static_cast<MODHeaderCommon &>(self));
244
  FByteswapper(self.vertexBufferSize);
245
  FByteswapper(self.numTextures);
246
  FByteswapper(self.numGroups);
×
247
  FByteswapper(self.bones);
×
248
  FByteswapper(self.groups);
×
249
  FByteswapper(self.materialHashes);
×
250
  FByteswapper(self.meshes);
251
  FByteswapper(self.vertexBuffer);
252
  FByteswapper(self.indices);
×
253
  FByteswapper(self.dataEnd);
×
254
}
×
255

×
256
template <> void FByteswapper(MODHeaderX70 &self, bool) {
257
  FByteswapper(static_cast<MODHeaderCommon &>(self));
258
  FByteswapper(self.vertexBufferSize);
×
259
  FByteswapper(self.unkBufferSize);
×
260
  FByteswapper(self.numTextures);
261
  FByteswapper(self.bones);
262
  FByteswapper(self.textures);
263
  FByteswapper(self.meshes);
×
264
  FByteswapper(self.vertexBuffer);
×
265
  FByteswapper(self.unkBuffer);
266
  FByteswapper(self.indices);
×
267
}
268

×
269
template <> void FByteswapper(MODHeaderX170 &self, bool) {
×
270
  FByteswapper(static_cast<MODHeaderCommon &>(self));
×
271
  FByteswapper(self.vertexBufferSize);
272
  FByteswapper(self.unkBufferSize);
×
273
  FByteswapper(self.numTextures);
274
  FByteswapper(self.bones);
×
275
  FByteswapper(self.textures);
×
276
  FByteswapper(self.meshes);
×
277
  FByteswapper(self.vertexBuffer);
×
278
  FByteswapper(self.unkBuffer);
279
  FByteswapper(self.indices);
280
}
281

282
template <> void FByteswapper(MODMaterialX70 &self, bool way) {
×
283
  FByteswapper(self.pshData);
×
284
  FByteswapper(self.vshData, way);
×
285
  FByteswapper(self.baseTextureIndex);
×
286
  FByteswapper(self.normalTextureIndex);
287
  FByteswapper(self.maskTextureIndex);
288
  FByteswapper(self.lightTextureIndex);
×
289
  FByteswapper(self.shadowTextureIndex);
×
290
  FByteswapper(self.additionalTextureIndex);
×
291
  FByteswapper(self.cubeMapTextureIndex);
×
292
  FByteswapper(self.detailTextureIndex);
293
  FByteswapper(self.AOTextureIndex);
294
  FByteswapper(self.transparency);
×
295
  FByteswapper(self.fresnelFactor);
×
296
  FByteswapper(self.fresnelBias);
297
  FByteswapper(self.specularPower);
298
  FByteswapper(self.envMapPower);
299
  FByteswapper(self.lightMapScale);
×
300
  FByteswapper(self.detailFactor);
×
301
  FByteswapper(self.detailWrap);
302
  FByteswapper(self.envMapBias);
×
303
  FByteswapper(self.normalBias);
304
  FByteswapper(self.transmit);
×
305
  FByteswapper(self.paralax);
×
306
  FByteswapper(self.hash);
×
307
}
308

×
309
template <> void FByteswapper(MODMaterialX170 &self, bool) {
310
  FByteswapper(self.pshData);
×
311
  FByteswapper(self.vshData);
×
312
  FByteswapper(self.baseTextureIndex);
×
313
  FByteswapper(self.normalTextureIndex);
×
314
  FByteswapper(self.maskTextureIndex);
315
  FByteswapper(self.lightTextureIndex);
316
  FByteswapper(self.shadowTextureIndex);
317
  FByteswapper(self.additionalTextureIndex);
318
  FByteswapper(self.cubeMapTextureIndex);
×
319
  FByteswapper(self.detailTextureIndex);
×
320
  FByteswapper(self.AOTextureIndex);
×
321
  FByteswapper(self.transparency);
×
322
  FByteswapper(self.unk00);
323
  FByteswapper(self.fresnelFactor);
324
  FByteswapper(self.fresnelBias);
×
325
  FByteswapper(self.specularPower);
×
326
  FByteswapper(self.envMapPower);
×
327
  FByteswapper(self.lightMapScale);
×
328
  FByteswapper(self.detailFactor);
329
  FByteswapper(self.detailWrap);
330
  FByteswapper(self.envMapBias);
×
331
  FByteswapper(self.normalBias);
×
332
  FByteswapper(self.transmit);
333
  FByteswapper(self.paralax);
334
  FByteswapper(self.hash);
335
}
×
336

×
337
template <> void FByteswapper(MODMaterialXC5 &self, bool way) {
338
  FByteswapper(self.pshData, way);
×
339
  FByteswapper(self.vshData, way);
340
  FByteswapper(self.baseTextureIndex);
×
341
  FByteswapper(self.normalTextureIndex);
×
342
  FByteswapper(self.maskTextureIndex);
×
343
  FByteswapper(self.lightTextureIndex);
344
  FByteswapper(self.shadowTextureIndex);
×
345
  FByteswapper(self.additionalTextureIndex);
346
  FByteswapper(self.cubeMapTextureIndex);
×
347
  FByteswapper(self.detailTextureIndex);
×
348
  FByteswapper(self.AOTextureIndex);
×
349
  FByteswapper(self.transparency);
×
350
  FByteswapper(self.unk01);
351
  FByteswapper(self.specularPower);
352
  FByteswapper(self.envMapPower);
353
  FByteswapper(self.lightMapScale);
UNCOV
354
  FByteswapper(self.detailFactor);
×
UNCOV
355
  FByteswapper(self.detailWrap);
×
356
  FByteswapper(self.envMapBias);
×
357
  FByteswapper(self.normalBias);
×
358
  FByteswapper(self.unk02);
359
  FByteswapper(self.unk03);
360
  FByteswapper(self.unk04);
×
UNCOV
361
  FByteswapper(self.unk05);
×
362
  FByteswapper(self.unk06);
×
363
  FByteswapper(self.unk07);
×
364
}
365

366
template <> void FByteswapper(MODMaterialHash &self, bool) {
×
UNCOV
367
  FByteswapper(self.hash);
×
368
}
369

370
template <> void FByteswapper(MODMeshX99 &self, bool) {
371
  FByteswapper(self.unk);
×
372
  FByteswapper(self.materialIndex);
×
373
  FByteswapper(self.numVertices);
374
  FByteswapper(self.endIndex);
×
375
  FByteswapper(self.vertexStart);
UNCOV
376
  FByteswapper(self.vertexStreamOffset);
×
377
  FByteswapper(self.vertexStream2Offset);
×
378
  FByteswapper(self.indexStart);
×
379
  FByteswapper(self.numIndices);
380
  FByteswapper(self.indexValueOffset);
×
381
  FByteswapper(self.startIndex);
UNCOV
382
  FByteswapper(self.skinInfo);
×
UNCOV
383
}
×
384

×
385
template <> void FByteswapper(MODMeshX70 &self, bool) {
×
386
  FByteswapper(self.unk);
387
  FByteswapper(self.materialIndex);
388
  FByteswapper(self.numVertices);
389
  FByteswapper(self.vertexStart);
390
  FByteswapper(self.vertexStreamOffset);
391
  FByteswapper(self.vertexStream2Offset);
UNCOV
392
  FByteswapper(self.indexStart);
×
393
  FByteswapper(self.numIndices);
×
394
  FByteswapper(self.indexValueOffset);
UNCOV
395
  FByteswapper(self.bboxMin);
×
396
  FByteswapper(self.bboxMax);
×
397
}
UNCOV
398

×
399
template <> void FByteswapper(MODMeshXC5 &self, bool way) {
×
400
  FByteswapper(self.unk);
UNCOV
401
  FByteswapper(self.numVertices);
×
402
  FByteswapper(self.data0, way);
×
403
  FByteswapper(self.data1, way);
UNCOV
404
  FByteswapper(self.vertexStart);
×
405
  FByteswapper(self.vertexStreamOffset);
×
406
  FByteswapper(self.vertexFormat);
UNCOV
407
  FByteswapper(self.indexStart);
×
408
  FByteswapper(self.numIndices);
×
409
  FByteswapper(self.indexValueOffset);
UNCOV
410
  FByteswapper(self.numEnvelopes);
×
UNCOV
411
  FByteswapper(self.meshIndex);
×
412
  FByteswapper(self.minVertex);
413
  FByteswapper(self.maxVertex);
×
414
  FByteswapper(self.hash);
×
415
}
416

×
417
template <> void FByteswapper(MODMeshXD2 &self, bool way) {
×
418
  FByteswapper(self.unk);
419
  FByteswapper(self.numVertices);
×
420
  FByteswapper(self.data0, way);
×
421
  FByteswapper(self.data1, way);
422
  FByteswapper(self.vertexStart);
423
  FByteswapper(self.vertexStreamOffset);
×
UNCOV
424
  FByteswapper(self.vertexFormat);
×
425
  FByteswapper(self.indexStart);
426
  FByteswapper(self.numIndices);
×
UNCOV
427
  FByteswapper(self.indexValueOffset);
×
428
  FByteswapper(self.meshIndex);
429
  FByteswapper(self.minVertex);
×
UNCOV
430
  FByteswapper(self.maxVertex);
×
431
  FByteswapper(self.unk);
432
}
×
UNCOV
433

×
434
#pragma endregion
435
#pragma region Savers
×
UNCOV
436
void SaveMODX99(const MODInner<MODTraitsX99LE> &main, BinWritterRef wr) {
×
437
  MODHeaderX99 header{};
438
  header.id = MODID;
×
UNCOV
439
  header.version = 0x99;
×
440
  wr.Push();
UNCOV
441
  wr.Skip(sizeof(header));
×
442
  wr.ApplyPadding();
×
443
  wr.Skip(sizeof(main.bounds) + sizeof(main.metadata));
UNCOV
444
  wr.ApplyPadding();
×
445

×
446
  header.numBones = main.bones.size();
UNCOV
447

×
448
  if (header.numBones) {
×
449
    header.bones = wr.Tell();
UNCOV
450
    header.numBoneMaps = main.skinRemaps.size();
×
451
    wr.WriteContainer(main.bones);
×
452
    wr.WriteContainer(main.refPoses);
453
    wr.WriteContainer(main.transforms);
454
    wr.Write(main.remaps);
455
    wr.WriteContainer(main.skinRemaps);
×
UNCOV
456
  }
×
457

458
  wr.ApplyPadding();
×
UNCOV
459
  header.numGroups = main.groups.size();
×
460

461
  if (header.numGroups) {
×
UNCOV
462
    header.groups = wr.Tell();
×
463
    wr.WriteContainer(main.groups);
464
  }
×
UNCOV
465

×
466
  wr.ApplyPadding();
467
  header.numTextures = main.paths.Size();
×
UNCOV
468
  header.numMaterials = main.materials.Size();
×
469

UNCOV
470
  if (header.numTextures || header.numMaterials) {
×
471
    header.textures = wr.Tell();
×
472
    for (auto &p : main.paths.storage) {
473
      wr.WriteContainer(p.path);
×
474
      wr.Skip(MODTraitsX99LE::pathSize - p.path.size());
×
475
    }
476
    wr.WriteContainer(main.materials.storage);
×
477
  }
×
478

479
  wr.ApplyPadding();
×
480
  header.numMeshes = main.meshes.size();
×
481
  header.meshes = wr.Tell();
UNCOV
482
  wr.WriteContainer(main.meshes);
×
UNCOV
483
  wr.WriteContainerWCount(main.envelopes);
×
484
  wr.ApplyPadding();
485
  header.vertexBufferSize = main.vertexBufferSize;
486
  header.unkBufferSize = main.unkBufferSize;
487
  header.vertexBuffer = wr.Tell();
×
488
  wr.WriteBuffer(main.buffer.data(), header.vertexBufferSize);
×
489

490
  if (header.unkBufferSize) {
×
491
    wr.ApplyPadding();
×
492
    header.unkBuffer = wr.Tell();
493
    wr.WriteBuffer(main.buffer.data() + header.vertexBufferSize,
×
494
                   header.unkBufferSize);
×
495
  }
UNCOV
496

×
497
  wr.ApplyPadding();
×
498
  header.indices = wr.Tell();
499
  header.numIndices = (main.indexBufferSize / sizeof(uint16)) + 1;
×
500
  wr.WriteBuffer(main.buffer.data() + header.vertexBufferSize +
×
501
                     header.unkBufferSize,
502
                 main.indexBufferSize);
×
503
  const size_t eof = wr.Tell();
×
504
  wr.Pop();
505
  wr.Write(header);
×
506
  wr.ApplyPadding();
×
507
  wr.Write(main.bounds);
UNCOV
508
  wr.Write(main.metadata);
×
UNCOV
509
  wr.Seek(eof);
×
510
  wr.ApplyPadding();
UNCOV
511
}
×
512

×
513
void SaveMODXC5(const MODInner<MODTraitsXC5> &main, BinWritterRef wr) {
UNCOV
514
  MODHeaderXC5 header{};
×
UNCOV
515
  header.id = MODID;
×
516
  header.version = 0xC5;
517
  wr.Push();
518
  wr.Skip(sizeof(header));
519
  wr.ApplyPadding();
×
520
  wr.Skip(sizeof(main.bounds) + sizeof(main.metadata));
×
521
  wr.ApplyPadding();
×
522

×
523
  header.numBones = main.bones.size();
×
524

×
UNCOV
525
  if (header.numBones) {
×
UNCOV
526
    header.bones = wr.Tell();
×
527
    wr.WriteContainer(main.bones);
×
528
    wr.WriteContainer(main.refPoses);
×
UNCOV
529
    wr.WriteContainer(main.transforms);
×
530
    wr.Write(main.remaps);
531
  }
532

×
533
  wr.ApplyPadding();
×
534
  header.numGroups = main.groups.size();
×
535

×
536
  if (header.numGroups) {
×
537
    header.groups = wr.Tell();
×
538
    wr.WriteContainer(main.groups);
×
539
  }
×
UNCOV
540

×
UNCOV
541
  wr.ApplyPadding();
×
542
  header.numTextures = main.paths.Size();
×
543
  header.numMaterials = main.materials.Size();
544

UNCOV
545
  if (header.numTextures || header.numMaterials) {
×
546
    header.textures = wr.Tell();
×
547
    for (auto &p : main.paths.storage) {
×
548
      wr.WriteContainer(p.path);
×
549
      wr.Skip(MODTraitsXC5::pathSize - p.path.size());
×
550
    }
×
551
    wr.WriteContainer(main.materials.storage);
×
552
  }
×
553

×
554
  wr.ApplyPadding();
×
UNCOV
555
  header.numMeshes = main.meshes.size();
×
556
  header.meshes = wr.Tell();
557
  wr.WriteContainer(main.meshes);
558
  wr.WriteContainerWCount(main.envelopes);
559
  wr.ApplyPadding();
560
  header.vertexBufferSize = main.vertexBufferSize;
×
UNCOV
561
  header.vertexBuffer = wr.Tell();
×
562
  wr.WriteBuffer(main.buffer.data(), header.vertexBufferSize);
563

UNCOV
564
  wr.ApplyPadding();
×
565
  header.indices = wr.Tell();
×
566
  header.numIndices = main.indexBufferSize / sizeof(uint16);
×
UNCOV
567
  wr.WriteBuffer(main.buffer.data() + header.vertexBufferSize,
×
568
                 main.indexBufferSize);
×
569
  const size_t eof = wr.Tell();
×
UNCOV
570
  wr.Pop();
×
571
  wr.Write(header);
×
572
  wr.ApplyPadding();
×
573
  wr.Write(main.bounds);
574
  wr.Write(main.metadata);
UNCOV
575
  wr.Seek(eof);
×
UNCOV
576
  wr.ApplyPadding();
×
577
}
578
#pragma endregion
UNCOV
579
#pragma region Loaders
×
580

×
UNCOV
581
template <class Header, class Traits>
×
582
MODImpl::ptr LoadMODX70(BinReaderRef_e rd) {
×
UNCOV
583
  Header header;
×
584
  MODInner<Traits> main;
×
UNCOV
585
  rd.Read(header);
×
UNCOV
586
  rd.ApplyPadding();
×
587
  rd.Read(main.bounds);
×
588
  rd.Read(main.metadata);
589
  header.numIndices--;
UNCOV
590

×
UNCOV
591
  if (header.numBones) {
×
592
    rd.Seek(header.bones);
593
    rd.ReadContainer(main.bones, header.numBones);
594
    rd.ReadContainer(main.refPoses, header.numBones);
×
UNCOV
595
    rd.ReadContainer(main.transforms, header.numBones);
×
UNCOV
596
  }
×
UNCOV
597

×
598
  rd.Seek(header.textures);
×
UNCOV
599
  rd.ReadContainerLambda(main.paths.storage, header.numTextures,
×
UNCOV
600
                         [](BinReaderRef_e rd, MODPathProxy &p) {
×
601
                           MODPath<Traits::pathSize> path;
×
UNCOV
602
                           rd.Read(path);
×
603
                           p.path = path.path;
604
                         });
605
  rd.ReadContainer(main.materials.storage, header.numMaterials);
606

UNCOV
607
  rd.Seek(header.meshes);
×
608
  rd.ReadContainer(main.meshes, header.numMeshes);
×
609

610
  main.vertexBufferSize = header.vertexBufferSize;
×
UNCOV
611
  main.indexBufferSize = header.numIndices * sizeof(uint16);
×
612
  main.unkBufferSize = header.unkBufferSize;
UNCOV
613

×
UNCOV
614
  main.buffer.resize(main.vertexBufferSize + main.indexBufferSize +
×
615
                     main.unkBufferSize);
UNCOV
616

×
617
  rd.Seek(header.vertexBuffer);
×
618
  rd.ReadBuffer(&main.buffer[0], header.vertexBufferSize);
UNCOV
619

×
620
  if (header.unkBufferSize) {
×
621
    rd.Seek(header.unkBuffer);
622
    rd.ReadBuffer(&main.buffer[header.vertexBufferSize], header.unkBufferSize);
623
  }
624

625
  rd.Seek(header.indices);
626
  rd.ReadBuffer(&main.buffer[header.vertexBufferSize + header.unkBufferSize],
627
                main.indexBufferSize);
UNCOV
628

×
629
  return std::make_unique<decltype(main)>(std::move(main));
630
}
×
631

UNCOV
632
MODImpl::ptr LoadMODXC5(BinReaderRef_e rd) {
×
633
  MODHeaderXC5 header;
634
  MODInner<MODTraitsXC5> main;
635
  rd.Read(header);
×
636
  rd.ApplyPadding();
637
  rd.Read(main.bounds);
×
638
  rd.Read(main.metadata);
639

640
  if (header.numBones) {
641
    rd.Seek(header.bones);
UNCOV
642
    rd.ReadContainer(main.bones, header.numBones);
×
643
    rd.ReadContainer(main.refPoses, header.numBones);
644
    rd.ReadContainer(main.transforms, header.numBones);
645
    rd.Read(main.remaps);
646
  }
×
647

648
  if (header.numGroups) {
UNCOV
649
    rd.Seek(header.groups);
×
650
    rd.ReadContainer(main.groups, header.numGroups);
UNCOV
651
  }
×
652

653
  rd.Seek(header.textures);
654
  rd.ReadContainerLambda(main.paths.storage, header.numTextures,
655
                         [](BinReaderRef_e rd, MODPathProxy &p) {
UNCOV
656
                           MODPath<MODTraitsXC5::pathSize> path;
×
657
                           rd.Read(path);
658
                           p.path = path.path;
×
659
                         });
660
  rd.ReadContainer(main.materials.storage, header.numMaterials);
661

662
  rd.Seek(header.meshes);
663
  rd.ReadContainer(main.meshes, header.numMeshes);
664
  rd.ReadContainer(main.envelopes);
665

×
666
  main.vertexBufferSize = header.vertexBufferSize;
×
667
  main.indexBufferSize = header.numIndices * sizeof(uint16);
UNCOV
668

×
UNCOV
669
  main.buffer.resize(main.vertexBufferSize + main.indexBufferSize);
×
670

671
  rd.Seek(header.vertexBuffer);
×
672
  rd.ReadBuffer(&main.buffer[0], header.vertexBufferSize);
×
673

UNCOV
674
  rd.Seek(header.indices);
×
UNCOV
675
  rd.ReadBuffer(&main.buffer[header.vertexBufferSize], main.indexBufferSize);
×
676

677
  return std::make_unique<decltype(main)>(std::move(main));
×
678
}
×
679

680
MODImpl::ptr LoadMODXC3(BinReaderRef_e rd) {
681
  MODHeaderXC5 header;
682
  MODInner<MODTraitsXC5> main;
×
683
  rd.Read(header);
×
684
  rd.ApplyPadding();
UNCOV
685
  rd.Read(main.bounds);
×
UNCOV
686
  rd.Read(main.metadata);
×
687

688
  if (header.numBones) {
×
689
    rd.Seek(header.bones);
×
690
    rd.ReadContainer(main.bones, header.numBones);
UNCOV
691
    rd.ReadContainer(main.refPoses, header.numBones);
×
UNCOV
692
    rd.ReadContainer(main.transforms, header.numBones);
×
693
    rd.Read(main.remaps);
694
  }
×
695

×
696
  if (header.numGroups) {
697
    rd.Seek(header.groups);
698
    rd.ReadContainer(main.groups, header.numGroups);
699
  }
UNCOV
700

×
UNCOV
701
  rd.Seek(header.textures);
×
702
  rd.ReadContainerLambda(main.paths.storage, header.numTextures,
×
703
                         [](BinReaderRef_e rd, MODPathProxy &p) {
704
                           MODPath<MODTraitsXC5::pathSize> path;
UNCOV
705
                           rd.Read(path);
×
706
                           p.path = path.path;
×
707
                         });
×
708
  rd.ReadContainer(main.materials.storage, header.numMaterials);
×
709

710
  rd.Seek(header.meshes);
711
  rd.ReadContainerLambda(main.meshes, header.numMeshes,
×
712
                         [](BinReaderRef_e rd, auto &m) {
×
713
                           rd.Read(m);
×
714
                           rd.Skip(8);
×
UNCOV
715
                         });
×
716
  rd.ReadContainer(main.envelopes);
717

718
  main.vertexBufferSize = header.vertexBufferSize;
×
719
  main.indexBufferSize = header.numIndices * sizeof(uint16);
×
720

×
721
  main.buffer.resize(main.vertexBufferSize + main.indexBufferSize);
×
722

723
  rd.Seek(header.vertexBuffer);
724
  rd.ReadBuffer(&main.buffer[0], header.vertexBufferSize);
×
725

×
726
  rd.Seek(header.indices);
×
727
  rd.ReadBuffer(&main.buffer[header.vertexBufferSize], main.indexBufferSize);
728

729
  return std::make_unique<decltype(main)>(std::move(main));
730
}
×
UNCOV
731

×
UNCOV
732
template <class Traits> MODImpl::ptr LoadMODX99(BinReaderRef_e rd) {
×
733
  MODHeaderX99 header;
734
  MODInner<Traits> main;
735
  rd.Read(header);
×
736
  rd.ApplyPadding();
×
737
  rd.Read(main.bounds);
×
738
  rd.Read(main.metadata);
×
739
  header.numIndices--;
740

741
  if (header.numBones) {
×
742
    rd.Seek(header.bones);
×
743
    rd.ReadContainer(main.bones, header.numBones);
×
744
    rd.ReadContainer(main.refPoses, header.numBones);
745
    rd.ReadContainer(main.transforms, header.numBones);
746
    rd.Read(main.remaps);
×
747
    rd.ReadContainer(main.skinRemaps, header.numBoneMaps);
×
748
  }
749

750
  if (header.numGroups) {
×
751
    rd.Seek(header.groups);
×
752
    rd.ReadContainer(main.groups, header.numGroups);
753
  }
754

×
755
  rd.Seek(header.textures);
×
756
  rd.ReadContainerLambda(main.paths.storage, header.numTextures,
×
757
                         [](BinReaderRef_e rd, MODPathProxy &p) {
×
UNCOV
758
                           MODPath<Traits::pathSize> path;
×
UNCOV
759
                           rd.Read(path);
×
760
                           p.path = path.path;
×
761
                         });
×
762
  rd.ReadContainer(main.materials.storage, header.numMaterials);
×
763

764
  rd.Seek(header.meshes);
765
  rd.ReadContainer(main.meshes, header.numMeshes);
×
766
  rd.ReadContainer(main.envelopes);
×
767

×
768
  main.vertexBufferSize = header.vertexBufferSize;
×
769
  main.indexBufferSize = header.numIndices * sizeof(uint16);
×
770
  main.unkBufferSize = header.unkBufferSize;
×
UNCOV
771

×
UNCOV
772
  main.buffer.resize(main.vertexBufferSize + main.indexBufferSize +
×
773
                     main.unkBufferSize);
×
774

×
775
  rd.Seek(header.vertexBuffer);
×
776
  rd.ReadBuffer(&main.buffer[0], header.vertexBufferSize);
×
777

×
778
  if (header.unkBufferSize) {
×
779
    rd.Seek(header.unkBuffer);
780
    rd.ReadBuffer(&main.buffer[header.vertexBufferSize], header.unkBufferSize);
781
  }
×
782

×
783
  rd.Seek(header.indices);
×
UNCOV
784
  rd.ReadBuffer(&main.buffer[header.vertexBufferSize + header.unkBufferSize],
×
UNCOV
785
                main.indexBufferSize);
×
786

×
787
  return std::make_unique<decltype(main)>(std::move(main));
×
788
}
×
789

×
790
template <class Traits> MODImpl::ptr LoadMODXD2x32(BinReaderRef_e rd) {
×
791
  MODHeaderXD2 header;
×
792
  MODInner<Traits> main;
793
  rd.Read(header);
794
  rd.ApplyPadding();
×
795
  rd.Read(main.bounds);
×
796
  rd.Read(main.metadata);
×
797

×
798
  if (header.numBones) {
×
799
    rd.Seek(header.bones);
×
800
    rd.ReadContainer(main.bones, header.numBones);
×
801
    rd.ReadContainer(main.refPoses, header.numBones);
×
802
    rd.ReadContainer(main.transforms, header.numBones);
×
803
    rd.Read(main.remaps);
×
804
  }
×
805

×
806
  if (header.numGroups) {
807
    rd.Seek(header.groups);
808
    rd.ReadContainer(main.groups, header.numGroups);
×
809
  }
×
810

×
UNCOV
811
  rd.ReadContainer(main.materials.storage, header.numMaterials);
×
UNCOV
812

×
813
  rd.Seek(header.meshes);
×
814
  rd.ReadContainerLambda(main.meshes, header.numMeshes,
×
UNCOV
815
                         [](BinReaderRef_e rd, auto &m) {
×
816
                           rd.Read(m);
×
817
                           rd.Skip(8);
×
818
                         });
×
819

820
  if constexpr (std::is_same_v<MODMetaDataV2, typename Traits::metadata>) {
821
    rd.ReadContainer(main.envelopes, main.metadata.numEnvelopes);
×
822
  } else {
×
823
    rd.ReadContainer(main.envelopes);
×
824
  }
×
825

×
826
  main.vertexBufferSize = header.vertexBufferSize;
×
827
  main.indexBufferSize = header.numIndices * sizeof(uint16);
×
828

×
829
  main.buffer.resize(main.vertexBufferSize + main.indexBufferSize);
×
830

×
831
  rd.Seek(header.vertexBuffer);
×
832
  rd.ReadBuffer(&main.buffer[0], header.vertexBufferSize);
833

834
  rd.Seek(header.indices);
×
835
  rd.ReadBuffer(&main.buffer[header.vertexBufferSize], main.indexBufferSize);
×
836

×
837
  return std::make_unique<decltype(main)>(std::move(main));
×
838
}
×
UNCOV
839

×
NEW
840
template<class Traits>
×
841
MODImpl::ptr LoadMODXD3x64(BinReaderRef_e rdn) {
×
842
  MODHeaderXD3X64 header;
×
NEW
843
  MODInner<Traits> main;
×
UNCOV
844
  BinReaderRef rd(rdn);
×
845
  rd.Push();
×
846
  rd.Read(header);
×
847
  rd.ApplyPadding();
×
848
  rd.Read(main.bounds);
×
849
  rd.Read(main.metadata);
×
850
  {
×
851
    uint64 maxPtr = header.bones | header.groups | header.materialNames |
×
852
                    header.meshes | header.vertexBuffer | header.indices |
×
853
                    header.dataEnd;
×
854
    size_t fileSize = rd.GetSize() << 1;
×
855

×
856
    if (maxPtr > fileSize) {
×
857
      rd.Pop();
×
858
      return LoadMODXD2x32<MODTraitsXD3>(rdn);
×
859
    }
860
  }
861

×
862
  if (header.numBones) {
×
863
    rd.Seek(header.bones);
864
    rd.ReadContainer(main.bones, header.numBones);
×
865
    rd.ReadContainer(main.refPoses, header.numBones);
×
866
    rd.ReadContainer(main.transforms, header.numBones);
×
867
    rd.Read(main.remaps);
×
868
  }
×
UNCOV
869

×
UNCOV
870
  if (header.numGroups) {
×
871
    rd.Seek(header.groups);
×
872
    rd.ReadContainer(main.groups, header.numGroups);
×
UNCOV
873
  }
×
UNCOV
874

×
875
  rdn.ReadContainer(main.materials.storage, header.numMaterials);
×
876

×
877
  rd.Seek(header.meshes);
×
878
  rdn.ReadContainerLambda(main.meshes, header.numMeshes,
×
879
                          [](BinReaderRef_e rd, auto &m) {
×
880
                            rd.Read(m);
×
881
                            rd.Skip(8);
×
882
                          });
×
883
  rd.ReadContainer(main.envelopes, main.metadata.numEnvelopes);
×
884

×
885
  main.vertexBufferSize = header.vertexBufferSize;
×
886
  main.indexBufferSize = header.numIndices * sizeof(uint16);
×
887

888
  main.buffer.resize(main.vertexBufferSize + main.indexBufferSize);
UNCOV
889

×
890
  rd.Seek(header.vertexBuffer);
×
891
  rd.ReadBuffer(&main.buffer[0], header.vertexBufferSize);
892

×
893
  rd.Seek(header.indices);
×
894
  rd.ReadBuffer(&main.buffer[header.vertexBufferSize], main.indexBufferSize);
×
895

×
896
  return std::make_unique<decltype(main)>(std::move(main));
×
897
}
×
898

×
899
MODImpl::ptr LoadMODX06(BinReaderRef_e rdn) {
×
900
  MODHeaderX06 header;
×
901
  MODInner<MODTraitsX06> main;
×
UNCOV
902
  BinReaderRef rd(rdn);
×
UNCOV
903
  rd.Push();
×
904
  rd.Read(header);
×
905
  rd.ApplyPadding();
×
906
  rd.Read(main.bounds);
×
907
  rd.Read(main.metadata);
×
UNCOV
908

×
909
  if (header.numBones) {
×
910
    rd.Seek(header.bones);
×
911
    rd.ReadContainer(main.bones, header.numBones);
×
912
    rd.ReadContainer(main.refPoses, header.numBones);
×
913
    rd.ReadContainer(main.transforms, header.numBones);
×
914
    rd.Read(main.remaps);
×
915
    rd.ReadContainer(main.skinRemaps, header.numSkins);
×
916
  }
917

918
  if (header.numGroups) {
×
919
    rd.Seek(header.groups);
×
920
    rd.ReadContainer(main.groups, header.numGroups);
921
  }
922

×
923
  rdn.ReadContainer(main.materials.storage, header.numMaterials);
×
924

×
925
  rd.Seek(header.meshes);
×
UNCOV
926
  rdn.ReadContainerLambda(main.meshes, header.numMeshes,
×
927
                          [](BinReaderRef_e rd, auto &m) {
×
928
                            rd.Read(m);
×
929
                            rd.Skip(8);
×
930
                          });
×
931
  rd.ReadContainer(main.envelopes);
×
932

×
933
  main.vertexBufferSize = header.vertexBufferSize;
×
934
  main.indexBufferSize = header.numIndices * sizeof(uint16);
×
935

936
  main.buffer.resize(main.vertexBufferSize + main.indexBufferSize);
UNCOV
937

×
UNCOV
938
  rd.Seek(header.vertexBuffer);
×
UNCOV
939
  rd.ReadBuffer(&main.buffer[0], header.vertexBufferSize);
×
UNCOV
940

×
941
  rd.Seek(header.indices);
×
942
  rd.ReadBuffer(&main.buffer[header.vertexBufferSize], main.indexBufferSize);
×
943

×
944
  return std::make_unique<decltype(main)>(std::move(main));
×
UNCOV
945
}
×
946

×
947
#pragma endregion
×
948

×
949
bool MODMaker::operator<(const MODMaker &i0) const {
950
  return reinterpret_cast<const uint64 &>(*this) <
951
         reinterpret_cast<const uint64 &>(i0);
×
UNCOV
952
}
×
953

×
954
static const std::map<MODMaker, MODImpl::ptr (*)(BinReaderRef_e)> modLoaders{
×
955
    {{MODVersion::X70, true}, LoadMODX70<MODHeaderX70, MODTraitsX70>},
956
    //{{0x170, false}, LoadMODX70<MODHeaderX170, MODTraitsX170>},
×
957
    {{MODVersion::X99, false}, LoadMODX99<MODTraitsX99LE>},
×
958
    {{MODVersion::X99, true}, LoadMODX99<MODTraitsX99BE>},
×
959
    {{MODVersion::XC3, true}, LoadMODXC3},
×
960
    {{MODVersion::XC5, false}, LoadMODXC5},
×
UNCOV
961
    {{MODVersion::XD2, true}, LoadMODXD2x32<MODTraitsXD2>},
×
UNCOV
962
    {{MODVersion::XD3, true}, LoadMODXD2x32<MODTraitsXD2>},
×
NEW
963
    {{MODVersion::XD3, false, false, Platform::PS4}, LoadMODXD3x64<MODTraitsXD3PS4>},
×
NEW
964
    {{MODVersion::XD3, false}, LoadMODXD3x64<MODTraitsXD3x64>},
×
UNCOV
965
    {{MODVersion::X05, false}, LoadMODX06},
×
UNCOV
966
    {{MODVersion::X06, false}, LoadMODX06},
×
967
};
968

969
template <class C> MODImpl::ptr makeMod() {
×
UNCOV
970
  return std::make_unique<MODInner<C>>();
×
UNCOV
971
}
×
972

×
973
static const std::map<MODMaker, MODImpl::ptr (*)()> modMakers{
974
    {{MODVersion::X70, true}, makeMod<MODTraitsX70>},
×
UNCOV
975
};
×
976

×
977
MOD::MOD(MODMaker make) {
×
978
  auto found = modMakers.find(make);
×
UNCOV
979

×
980
  if (es::IsEnd(modMakers, found)) {
×
UNCOV
981
    throw std::runtime_error("Cannon find specified MODMaker instance.");
×
UNCOV
982
  }
×
983

984
  pi = found->second();
985
}
986

987
void MOD::Load(const std::string &fileName) {
988
  BinReader rd(fileName);
×
989
  Load(rd);
×
990
}
×
991

×
992
void MOD::Load(BinReaderRef_e rd) {
993
  MODHeaderCommon header;
×
994
  rd.Push();
×
UNCOV
995
  rd.Read(header);
×
996
  rd.Pop();
×
997

998
  if (header.id == DOMID) {
×
999
    rd.SwapEndian(true);
1000
    FByteswapper(header);
×
UNCOV
1001
  } else if (header.id != MODID) {
×
UNCOV
1002
    throw es::InvalidHeaderError(header.id);
×
1003
  }
×
1004

×
1005
  MODMaker mk;
×
1006
  mk.version = static_cast<MODVersion>(header.version);
×
1007
  mk.swappedEndian = rd.SwappedEndian();
×
1008

1009
  auto found = modLoaders.find(mk);
UNCOV
1010

×
UNCOV
1011
  if (es::IsEnd(modLoaders, found)) {
×
1012
    throw es::InvalidVersionError(mk.version);
1013
  }
×
1014

×
UNCOV
1015
  pi = found->second(rd);
×
1016
  pi->Reflect(rd.SwappedEndian());
1017
}
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