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

PredatorCZ / RevilLib / 168

15 Nov 2025 04:55PM UTC coverage: 11.16% (-0.05%) from 11.207%
168

push

github

PredatorCZ
fix mtf texture data read

0 of 32 new or added lines in 1 file covered. (0.0%)

78 existing lines in 1 file now uncovered.

757 of 6783 relevant lines covered (11.16%)

6682.27 hits per line

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

0.0
/src/tex.cpp
1
/*  Revil Format Library
2
    Copyright(C) 2020-2025 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 "revil/tex.hpp"
19
#include "spike/except.hpp"
20
#include "spike/format/DDS.hpp"
21
#include "spike/io/binreader_stream.hpp"
22
#include "spike/type/bitfield.hpp"
23
#include <map>
24
#include <vector>
25

26
using namespace revil;
27

28
enum class TextureType : uint8 {
29
  None,
30
  ColorPixel,
31
  General,
32
  Cubemap,
33
  Volume,
34
};
35

36
enum class TextureTypeV2 {
37
  General = 2,
38
  Volume = 3,
39
  Cubemap = 6,
40
};
41

42
enum class GeneralTextureType {
43
  None,
44
  IllumMap,  // IM
45
  ColorMap,  // BM, LM, or SRGB??
46
  NormalMap, // NM XGXA
47
};
48

49
enum class CubemapTextureType {
50
  Eye, // LP PC, some struct dump
51
  Classic,
52
};
53

54
enum class TEXFormat : uint32 {
55
  DXT1 = CompileFourCC("DXT1"),
56
  DXT2 = CompileFourCC("DXT2"),
57
  DXT3 = CompileFourCC("DXT3"),
58
  DXT5 = CompileFourCC("DXT5"),
59
  RGBA8_PACKED = 0x15,
60
  RG8_SNORM = 0x3c,
61

62
  /*360
63
  405274959
64
  405275014
65
  438305106
66
  438305107
67
  438305108
68
  438305137
69
  438305147
70
  438305148*/
71
};
72

73
enum class TEXFormatV2 : uint8 {
74
  UNK = 0,
75
  RGBA16F = 0x2,
76
  R8 = 0x7,
77
  DXT5_YUV = 0xA,
78
  BC7 = 0x10,
79
  DXT1 = 0x13,
80
  DXT3 = 0x15,
81
  DXT5 = 0x17,
82
  DXT1_Gray = 0x19, // BC4 for some?
83
  DXT1_NM = 0x1e,
84
  DXT5_NM = 0x1f,
85
  DXT5_LM = 0x20, // rgb lightmap, alpha ambient occlusion?
86
  DXT5_PM = 0x25, // rgb NM, alpha HM
87
  DXT5_ID = 0x2a,
88
  RGBA8 = 0x27,
89
};
90

91
enum class TEXFormatV2PS4 : uint8 {
92
  R8 = 0x7,
93
  DXT5_YUV = 0xA,
94
  BC7 = 0x10,
95
  DXT1 = 0x13,
96
  DXT3 = 0x15,
97
  DXT5 = 0x17,
98
  DXT1_NM = 0x1e,
99
  BC5S = 0x1f,
100
  BC4 = 0x19,
101
};
102

103
enum class TEXFormatA0 : uint8 {
104
  UNK = 0,
105
  RGBA8 = 7,
106
  BC3_YUV = 0xA,
107
  BC1 = 0x13,
108
  BC2 = 0x15,
109
  BC3 = 0x17,
110
  BC4 = 0x19,
111
  BC1_NM = 0x1e,
112
  BC5 = 0x1f,
113
};
114

115
static constexpr uint32 TEXID = CompileFourCC("TEX");
116
static constexpr uint32 TEXSID = CompileFourCC("TEX ");
117
static constexpr uint32 XETID = CompileFourCC("\0XET");
118

119
struct TEXx70 {
×
120
  using TextureType = BitMemberDecl<0, 4>;
121
  using TextureSubtype = BitMemberDecl<1, 4>;
122
  using TextureLayout = BitFieldType<uint16, TextureType, TextureSubtype>;
123
  uint32 id = TEXID;
124
  uint16 version;
125
  TextureLayout type;
126
  uint8 numMips;
127
  uint8 numFaces = 1; // 6 for cubemap
128
  uint16 null = 0;
129
  uint16 width;
130
  uint16 height;
131
  uint32 arraySize = 0;
132
  TEXFormat fourcc;
133
  Vector4 colorCorrection{1.f, 1.f, 1.f, 0};
134

135
  void SwapEndian(bool way) {
×
136
    FByteswapper(id);
×
137
    FByteswapper(version);
×
138
    FByteswapper(type, way);
×
139
    FByteswapper(width);
×
140
    FByteswapper(height);
×
141
    FByteswapper(arraySize);
×
142
    FByteswapper(fourcc);
×
143
    FByteswapper(colorCorrection);
×
144
  }
145
};
146

147
struct TEXx66 {
×
148
  using TextureType = BitMemberDecl<0, 4>;
149
  using TextureSubtype = BitMemberDecl<1, 4>;
150
  using TextureLayout = BitFieldType<uint16, TextureType, TextureSubtype>;
151
  uint32 id = TEXID;
152
  uint16 version;
153
  TextureLayout type;
154
  uint8 numMips;
155
  uint8 numFaces = 1;
156
  uint16 width;
157
  uint16 height;
158
  uint16 arraySize;
159
  TEXFormat fourcc;
160
  Vector4 colorCorrection{1.f, 1.f, 1.f, 0};
161

162
  void SwapEndian(bool way) {
×
163
    FByteswapper(id);
×
164
    FByteswapper(version);
×
165
    FByteswapper(type, way);
×
166
    FByteswapper(width);
×
167
    FByteswapper(height);
×
168
    FByteswapper(arraySize);
×
169
    FByteswapper(fourcc);
×
170
    FByteswapper(colorCorrection);
×
171
  }
172
};
173

174
struct TEXx56 {
175
  enum class TextureLayout : uint8 { General, Illum, Corrected = 4 };
176

177
  uint32 id;
178
  uint8 version;
179
  TextureType type;
180
  TextureLayout layout;
181
  uint8 numMips;
182
  uint32 width;
183
  uint32 height;
184
  uint32 arraySize;
185
  TEXFormat fourcc;
186

187
  void SwapEndian() {
×
188
    FByteswapper(id);
×
189
    FByteswapper(width);
×
190
    FByteswapper(height);
×
191
    FByteswapper(arraySize);
×
192
    FByteswapper(fourcc);
×
193
  }
194
};
195

196
struct TEXx87 {
197
  using TextureType = BitMemberDecl<0, 4>;
198
  using NumMips = BitMemberDecl<1, 5>;
199
  using NumFaces = BitMemberDecl<2, 8>;
200
  using Width = BitMemberDecl<3, 13>;
201
  using Tier0 = BitFieldType<uint32, TextureType, NumMips, NumFaces, Width>;
202
  using Height = BitMemberDecl<0, 13>;
203
  using Depth = BitMemberDecl<1, 13>;
204
  using Null = BitMemberDecl<2, 6>;
205
  using Tier1 = BitFieldType<uint32, Height, Depth, Null>;
206

207
  uint32 id;
208
  uint16 version;
209
  uint16 null;
210
  Tier0 tier0;
211
  Tier1 tier1;
212
  TEXFormatV2 format;
213

214
  void SwapEndian(bool way) {
×
215
    FByteswapper(id);
×
216
    FByteswapper(version);
×
217
    FByteswapper(tier0, way);
×
218
    FByteswapper(tier1, way);
219
  }
220
};
221

222
struct TEXx9D {
223
  using Version = BitMemberDecl<0, 8>;
224
  using Unk00 = BitMemberDecl<1, 6>;
225
  using Unk01 = BitMemberDecl<2, 14>;
226
  using TextureType = BitMemberDecl<3, 4>;
227
  using Tier0 = BitFieldType<uint32, Version, Unk00, Unk01, TextureType>;
228

229
  using NumMips = BitMemberDecl<0, 6>;
230
  using Width = BitMemberDecl<1, 13>;
231
  using Height = BitMemberDecl<2, 13>;
232
  using Tier1 = BitFieldType<uint32, NumMips, Width, Height>;
233

234
  using NumFaces = BitMemberDecl<0, 8>;
235
  using TextureFormat = BitMemberDecl<1, 5>;
236
  using Flags = BitMemberDecl<2, 3>;
237
  using Depth = BitMemberDecl<3, 16>;
238
  using Tier2 = BitFieldType<uint32, NumFaces, TextureFormat, Flags, Depth>;
239

240
  uint32 id;
241
  Tier0 tier0;
242
  Tier1 tier1;
243
  Tier2 tier2;
244

245
  void SwapEndian(bool) {
×
246
    FByteswapper(id);
×
247
    FByteswapper(tier0.value);
×
248
    FByteswapper(tier1.value);
×
249
    FByteswapper(tier2.value);
×
250
  }
251
};
252

253
enum class TEXFormatAndr : uint8 {
254
  RGBA8 = 0x1,
255
  RGBA4 = 0x7,
256
  ETC1 = 0x0A,
257
  PVRTC4 = 0x0D,
258
};
259

260
enum class TEXTypeAndr : uint32 {
261
  Base = 0x11,
262
  Normal = 0x21,
263
  Mask = 0x31,
264
  CubeMap = 0x61,
265
};
266

267
struct TEXx09 {
268
  uint32 id;
269
  uint16 version;
270
  TEXFormatAndr format;
271
  uint8 unk; // 4
272
  TEXTypeAndr type;
273

274
  uint32 width : 13;
275
  uint32 height : 13;
276
  uint32 numMips : 4;
277
  uint32 unk0 : 1;
278
  uint32 unk1 : 1;
279

280
  uint32 offset0;
281
  uint32 pvrtcOffset;
282
  uint32 offset1;
283

284
  uint32 unkSize;
285
  uint32 pvrtcSize;
286
  uint32 dxtSize;
287
};
288

289
struct TEXCubemapData {
290
  float unk[27];
291
};
292

293
TexelInputFormat ConvertTEXFormat(TEXFormat fmt) {
×
294
  TexelInputFormat retVal;
295

296
  switch (fmt) {
×
297
  case TEXFormat::DXT1:
298
    retVal.type = TexelInputFormatType::BC1;
299
    break;
300
  case TEXFormat::DXT2:
×
301
    retVal.type = TexelInputFormatType::BC2;
302
    retVal.premultAlpha = true;
303
    break;
×
304
  case TEXFormat::DXT3:
×
305
    retVal.type = TexelInputFormatType::BC2;
306
    break;
×
307
  case TEXFormat::DXT5:
×
308
    retVal.type = TexelInputFormatType::BC3;
309
    break;
×
310
  case TEXFormat::RGBA8_PACKED:
×
311
    retVal.type = TexelInputFormatType::RGBA8;
312
    break;
×
313
  case TEXFormat::RG8_SNORM:
×
314
    retVal.type = TexelInputFormatType::RG8;
315
    retVal.snorm = true;
316
    break;
×
317

318
  default:
×
319
    throw std::runtime_error("Unknown texture format!");
×
320
  }
321

322
  return retVal;
×
323
}
324

325
TexelInputFormat ConvertTEXFormat(TEXFormatV2 fmt) {
×
326
  TexelInputFormat retVal;
327

328
  switch (fmt) {
×
329
  case TEXFormatV2::DXT1:
330
  case TEXFormatV2::DXT1_Gray:
331
  case TEXFormatV2::DXT1_NM:
332
    retVal.type = TexelInputFormatType::BC1;
333
    break;
334
  case TEXFormatV2::DXT3:
×
335
    retVal.type = TexelInputFormatType::BC2;
336
    break;
×
337
  case TEXFormatV2::DXT5:
×
338
  case TEXFormatV2::DXT5_NM:
339
  case TEXFormatV2::DXT5_LM:
340
  case TEXFormatV2::DXT5_PM:
341
  case TEXFormatV2::DXT5_ID:
342
  case TEXFormatV2::DXT5_YUV:
343
  case TEXFormatV2::UNK:
344
    retVal.type = TexelInputFormatType::BC3;
345
    break;
×
346
  case TEXFormatV2::RGBA16F:
×
347
    retVal.type = TexelInputFormatType::RGBA16;
348
    break;
×
349
  case TEXFormatV2::RGBA8:
×
350
    retVal.type = TexelInputFormatType::RGBA8;
351
    break;
×
NEW
352
  case TEXFormatV2::R8:
×
353
    retVal.type = TexelInputFormatType::R8;
NEW
354
    break;
×
355

356
  default:
×
357
    throw std::runtime_error("Unknown texture format!");
×
358
  }
359

360
  return retVal;
×
361
}
362

363
TexelInputFormat ConvertTEXFormat(TEXFormatV2PS4 fmt) {
×
364
  TexelInputFormat retVal;
365

366
  switch (fmt) {
×
367
  case TEXFormatV2PS4::DXT1:
368
  case TEXFormatV2PS4::DXT1_NM:
369
    retVal.type = TexelInputFormatType::BC1;
370
    break;
371
  case TEXFormatV2PS4::DXT3:
×
372
    retVal.type = TexelInputFormatType::BC2;
373
    break;
×
374
  case TEXFormatV2PS4::DXT5:
×
375
  case TEXFormatV2PS4::DXT5_YUV:
376
    retVal.type = TexelInputFormatType::BC3;
377
    break;
×
378
  case TEXFormatV2PS4::BC4:
×
379
    retVal.type = TexelInputFormatType::BC4;
380
    break;
×
381
  case TEXFormatV2PS4::BC5S:
×
382
    retVal.type = TexelInputFormatType::BC5;
383
    retVal.snorm = true;
384
    break;
×
385
  case TEXFormatV2PS4::BC7:
×
386
    retVal.type = TexelInputFormatType::BC7;
387
    break;
×
388
  case TEXFormatV2PS4::R8:
×
389
    retVal.type = TexelInputFormatType::R8;
390
    break;
×
391
  default:
×
392
    throw std::runtime_error("Unknown texture format!");
×
393
  }
394

395
  return retVal;
×
396
}
397

398
TexelInputFormat ConvertTEXFormat(TEXFormatA0 fmt) {
×
399
  TexelInputFormat retVal;
400

401
  switch (fmt) {
×
402
  case TEXFormatA0::BC1:
403
  case TEXFormatA0::BC1_NM:
404
    retVal.type = TexelInputFormatType::BC1;
405
    break;
406
  case TEXFormatA0::BC2:
×
407
    retVal.type = TexelInputFormatType::BC2;
408
    break;
×
NEW
409
  case TEXFormatA0::UNK:
×
410
  case TEXFormatA0::BC3:
411
  case TEXFormatA0::BC3_YUV:
412
    retVal.type = TexelInputFormatType::BC3;
413
    break;
×
414
  case TEXFormatA0::BC4:
×
415
    retVal.type = TexelInputFormatType::BC4;
416
    break;
×
417
  case TEXFormatA0::BC5:
×
418
    retVal.type = TexelInputFormatType::BC5;
419
    break;
×
420
  case TEXFormatA0::RGBA8:
×
421
    retVal.type = TexelInputFormatType::RGBA8;
422
    retVal.swizzle.b = TexelSwizzleType::Red;
423
    retVal.swizzle.r = TexelSwizzleType::Blue;
424
    break;
×
425
  default:
×
UNCOV
426
    throw std::runtime_error("Unknown texture format!");
×
427
  }
428

429
  return retVal;
×
430
}
431

432
void ApplyModifications(NewTexelContextCreate &ctx, Platform platform) {
×
433
  if (ctx.baseFormat.type == TexelInputFormatType::RGBA8 &&
×
434
      platform == Platform::PS3 && IsPow2(ctx.width) && IsPow2(ctx.height)) {
×
435
    ctx.baseFormat.tile = TexelTile::Morton;
×
436
  } else if (platform == Platform::PS4) {
×
437
    ctx.baseFormat.tile = TexelTile::MortonForcePow2;
×
438
  } else if (platform == Platform::NSW) {
×
439
    ctx.baseFormat.tile = TexelTile::NX;
×
440
  }
441
}
442

443
TEX LoadTEXx56(BinReaderRef_e rd) {
×
444
  TEX main;
445
  TEXx56 header;
446
  rd.Read(header);
×
447

448
  if (header.layout == TEXx56::TextureLayout::Corrected) {
×
449
    rd.Read(main.color);
×
450
  }
451

452
  if (header.type == TextureType::Volume) {
×
453
    BinReaderRef rdn(rd);
454
    DDS_Header ddsHdr;
455
    DDS_PixelFormat ddsPf;
×
456
    DDS_HeaderEnd ddsFt;
×
457
    rdn.Read(ddsHdr);
458
    rdn.Read(ddsPf);
459
    rdn.Read(ddsFt);
460

461
    main.ctx.width = ddsHdr.width;
×
462
    main.ctx.height = ddsHdr.height;
×
463
    main.ctx.depth = ddsHdr.depth;
×
464
    main.ctx.numMipmaps = ddsHdr.mipMapCount;
×
465

466
    if (ddsPf == DDSFormat_DXT5) {
×
467
      main.ctx.baseFormat.type = TexelInputFormatType::BC3;
×
468
    } else {
469
      throw std::runtime_error("Unknown texture format!");
×
470
    }
471
  } else if (header.type == TextureType::Cubemap) {
×
472
    throw std::runtime_error("Cubemaps are not supported.");
×
473
  } else {
474
    main.ctx.width = header.width;
×
475
    main.ctx.height = header.height;
×
476
    main.ctx.depth = header.arraySize;
×
477
    main.ctx.numMipmaps = header.numMips;
×
478
    main.ctx.baseFormat = ConvertTEXFormat(header.fourcc);
×
479
  }
480

481
  size_t bufferSize = rd.GetSize() - rd.Tell();
×
482
  rd.ReadContainer(main.buffer, bufferSize);
×
483
  ApplyModifications(main.ctx, Platform::Win32);
484

485
  return main;
×
486
}
×
487

488
template <class header_type>
489
TEX LoadTEXx66(BinReaderRef_e rd, Platform platform) {
×
490
  TEX main;
491
  header_type header;
492
  rd.Read(header);
×
493

494
  main.ctx.width = header.width;
×
495
  main.ctx.height = header.height;
×
NEW
496
  main.ctx.depth = std::max(1, int(header.arraySize));
×
497
  main.ctx.numMipmaps = header.numMips;
×
498
  main.ctx.baseFormat = ConvertTEXFormat(header.fourcc);
×
499
  main.color = Vector4A16(header.colorCorrection);
×
500

501
  TextureType type = static_cast<TextureType>(
502
      header.type.template Get<typename header_type::TextureType>());
503

504
  if (type == TextureType::Cubemap) {
×
NEW
505
    main.ctx.numFaces = 6;
×
NEW
506
    rd.Read(main.harmonics);
×
507
  }
508

509
  rd.ReadContainer(main.offsets, header.numFaces * header.numMips);
×
NEW
510
  uint32 bufferBegin = rd.Tell();
×
511

NEW
512
  for (uint32 &o : main.offsets) {
×
NEW
513
    o -= bufferBegin;
×
514
  }
515

NEW
516
  size_t bufferSize = rd.GetSize() - bufferBegin;
×
517

518
  rd.ReadContainer(main.buffer, bufferSize);
×
519
  ApplyModifications(main.ctx, platform);
×
520

NEW
521
  if (rd.SwappedEndian() &&
×
NEW
522
      main.ctx.baseFormat.type == TexelInputFormatType::RGBA8) {
×
NEW
523
    main.ctx.baseFormat.swapPacked = true;
×
524
  }
525

526
  return main;
×
527
}
×
528

×
529
TEX LoadTEXx87(BinReaderRef_e rd, Platform platform) {
530
  TEX main;
531
  TEXx87 header;
×
532
  rd.Read(header);
533
  using t = TEXx87;
×
534

×
535
  main.ctx.width = header.tier0.Get<t::Width>();
×
536
  main.ctx.height = header.tier1.Get<t::Height>();
×
537
  main.ctx.depth = header.tier1.Get<t::Depth>();
×
538
  main.ctx.numMipmaps = header.tier0.Get<t::NumMips>();
×
539
  main.ctx.baseFormat = ConvertTEXFormat(header.format);
540

541
  TextureTypeV2 type = (TextureTypeV2)header.tier0.Get<t::TextureType>();
542

543
  if (type == TextureTypeV2::Cubemap) {
×
NEW
544
    main.ctx.numFaces = 6;
×
NEW
545
    rd.Read(main.harmonics);
×
546
  }
547

NEW
548
  uint32 numOffsets =
×
NEW
549
      std::max(int8(1), main.ctx.numFaces) * main.ctx.numMipmaps;
×
550
  rd.ReadContainer(main.offsets, numOffsets);
551

×
NEW
552
  uint32 bufferBegin = rd.Tell();
×
553

554
  for (uint32 &o : main.offsets) {
NEW
555
    o -= bufferBegin;
×
556
  }
557

×
NEW
558
  size_t bufferSize = rd.GetSize() - bufferBegin;
×
559
  rd.ReadContainer(main.buffer, bufferSize);
NEW
560
  ApplyModifications(main.ctx, platform);
×
NEW
561

×
NEW
562
  if (rd.SwappedEndian() &&
×
563
      main.ctx.baseFormat.type == TexelInputFormatType::RGBA8) {
564
    main.ctx.baseFormat.swapPacked = true;
NEW
565
  }
×
566

×
567
  return main;
×
568
}
569

UNCOV
570
TEX LoadTEXx9D(BinReaderRef_e rd, Platform platform) {
×
571
  TEX main;
572
  TEXx9D header;
×
UNCOV
573
  rd.Read(header);
×
574
  using t = TEXx9D;
×
575

×
576
  main.ctx.width = header.tier1.Get<t::Width>();
×
577
  main.ctx.height = header.tier1.Get<t::Height>();
×
578
  main.ctx.depth = header.tier2.Get<t::Depth>();
579
  main.ctx.numMipmaps = header.tier1.Get<t::NumMips>();
580

581
  TextureTypeV2 type = (TextureTypeV2)header.tier0.Get<t::TextureType>();
UNCOV
582

×
UNCOV
583
  if (type == TextureTypeV2::Cubemap) {
×
NEW
584
    main.ctx.numFaces = 6;
×
585
    rd.Read(main.harmonics);
586
  }
UNCOV
587

×
NEW
588
  uint32 numOffsets =
×
589
      std::max(int8(1), main.ctx.numFaces) * main.ctx.numMipmaps;
UNCOV
590

×
UNCOV
591
  auto fallback = [&] {
×
592
    rd.ReadContainer(main.offsets, numOffsets);
593
    main.ctx.baseFormat =
594
        ConvertTEXFormat((TEXFormatV2)header.tier2.Get<t::TextureFormat>());
×
595
  };
UNCOV
596

×
UNCOV
597
  if (!rd.SwappedEndian()) {
×
598
    uint32 offset0;
599
    rd.Push();
×
UNCOV
600
    rd.Read(offset0);
×
601
    rd.Pop();
×
602
    uint32 dataBeginPredict = (numOffsets * sizeof(uint32)) + rd.Tell();
603

604
    if (offset0 == dataBeginPredict) {
×
UNCOV
605
      fallback();
×
606
    } else {
607
      std::vector<uint64> offsets;
×
608
      rd.ReadContainer(offsets, numOffsets);
609
      main.offsets.assign(offsets.begin(), offsets.end());
610
      platform = Platform::PS4;
×
611
      main.ctx.baseFormat = ConvertTEXFormat(
612
          (TEXFormatV2PS4)header.tier2.Get<t::TextureFormat>());
613
    }
×
614
  } else {
×
UNCOV
615
    fallback();
×
UNCOV
616
  }
×
UNCOV
617

×
618
  uint32 bufferBegin = rd.Tell();
619

620
  for (uint32 &o : main.offsets) {
NEW
621
    o -= bufferBegin;
×
622
  }
×
623

×
624
  size_t bufferSize = rd.GetSize() - bufferBegin;
625

626
  rd.ReadContainer(main.buffer, bufferSize);
627
  ApplyModifications(main.ctx, platform);
×
UNCOV
628

×
629
  return main;
630
}
×
631

UNCOV
632
TEX LoadTEXx09(BinReaderRef_e rd_, Platform platform) {
×
633
  BinReaderRef rd(rd_);
×
634
  TEX main;
635
  TEXx09 header;
636
  rd.Read(header);
×
UNCOV
637

×
638
  main.ctx.width = header.width;
×
639
  main.ctx.height = header.height;
UNCOV
640
  main.ctx.numMipmaps = header.numMips;
×
641

×
UNCOV
642
  switch (header.format) {
×
643
  case TEXFormatAndr::PVRTC4:
644
    main.ctx.baseFormat.type = TexelInputFormatType::PVRTC4;
645
    break;
×
646
  case TEXFormatAndr::ETC1:
×
647
    main.ctx.baseFormat.type = TexelInputFormatType::ETC1;
UNCOV
648
    break;
×
649
  case TEXFormatAndr::RGBA4:
650
    main.ctx.baseFormat.type = TexelInputFormatType::RGBA4;
651
    break;
×
652
  case TEXFormatAndr::RGBA8:
653
    main.ctx.baseFormat.type = TexelInputFormatType::RGBA8;
UNCOV
654
    break;
×
655
  default:
×
UNCOV
656
    throw std::runtime_error("Unknown texture format!");
×
657
  }
×
658

659
  ApplyModifications(main.ctx, platform);
660

UNCOV
661
  return main;
×
UNCOV
662
}
×
663

×
664
TEX LoadTEXxA0(BinReaderRef_e rd, Platform platform) {
665
  TEX main;
666
  TEXx9D header;
UNCOV
667
  rd.Read(header);
×
668
  using t = TEXx9D;
UNCOV
669

×
670
  main.ctx.width = header.tier1.Get<t::Width>();
×
671
  main.ctx.height = header.tier1.Get<t::Height>();
UNCOV
672
  main.ctx.depth = header.tier2.Get<t::Depth>();
×
673
  main.ctx.numMipmaps = header.tier1.Get<t::NumMips>();
674

675
  TextureTypeV2 type = (TextureTypeV2)header.tier0.Get<t::TextureType>();
×
676

677
  if (type == TextureTypeV2::Cubemap) {
UNCOV
678
    main.ctx.numFaces = 6;
×
679
    rd.Read(main.harmonics);
UNCOV
680
  }
×
681

NEW
682
  uint32 numOffsets = main.ctx.numMipmaps;
×
UNCOV
683

×
684
  uint32 bufferSize;
UNCOV
685
  rd.Read(bufferSize);
×
686
  rd.ReadContainer(main.offsets, numOffsets);
×
687
  main.ctx.baseFormat =
×
688
      ConvertTEXFormat((TEXFormatA0)header.tier2.Get<t::TextureFormat>());
UNCOV
689

×
690
  if (type == TextureTypeV2::Cubemap) {
691
    uint32 faceSize;
692
    rd.Read(faceSize);
NEW
693
    auto offsets = main.offsets;
×
694

695
    for (uint32 f = 0; f < 5; f++) {
NEW
696
      for (auto &o : offsets) {
×
697
        o += faceSize;
NEW
698
      }
×
NEW
699

×
700
      main.offsets.insert(main.offsets.end(), offsets.begin(), offsets.end());
701
    }
702
  }
×
703

704
  rd.ReadContainer(main.buffer, bufferSize);
×
UNCOV
705
  ApplyModifications(main.ctx, platform);
×
706

UNCOV
707
  return main;
×
UNCOV
708
}
×
709

UNCOV
710
static const std::map<uint16, TEX (*)(BinReaderRef_e, Platform)> texLoaders{
×
711
    {0x66, LoadTEXx66<TEXx66>}, {0x70, LoadTEXx66<TEXx70>}, {0x87, LoadTEXx87},
712
    {0x9D, LoadTEXx9D},         {0x09, LoadTEXx09},         {0xA0, LoadTEXxA0},
713
};
714

715
void TEX::Load(BinReaderRef_e rd, Platform platform) {
716
  struct {
×
717
    uint32 id;
×
718
    union {
×
719
      uint8 versionV10;
720
      uint16 versionV11;
×
721
      uint32 versionV20;
×
722
    };
×
723

×
724
    void NoSwap();
×
725
  } header{};
×
726

×
727
  rd.Read(header);
×
728
  rd.Seek(0);
×
729

×
730
  if (header.id == XETID) {
×
UNCOV
731
    rd.SwapEndian(true);
×
UNCOV
732
  } else if (header.id != TEXID && header.id != TEXSID) {
×
733
    throw es::InvalidHeaderError(header.id);
×
UNCOV
734
  }
×
735

736
  if (header.versionV10 == 0x56) {
UNCOV
737
    if (rd.SwappedEndian()) {
×
738
      throw std::runtime_error("X360 texture format is unsupported.");
UNCOV
739
    }
×
UNCOV
740

×
741
    *this = LoadTEXx56(rd);
UNCOV
742
    return;
×
743
  } else if (rd.SwappedEndian()) {
744
    FByteswapper(header.versionV11);
745
  }
×
746

747
  if (platform == Platform::Auto) {
UNCOV
748
    platform = rd.SwappedEndian() ? Platform::PS3 : Platform::Win32;
×
UNCOV
749
  }
×
UNCOV
750

×
751
  auto found = texLoaders.find(header.versionV11);
×
752

753
  if (!es::IsEnd(texLoaders, found)) {
754
    *this = found->second(rd, platform);
UNCOV
755
    return;
×
756
  }
×
UNCOV
757

×
758
  if (rd.SwappedEndian()) {
759
    FByteswapper(header.versionV20);
760
  }
×
761

762
  found = texLoaders.find(header.versionV10);
UNCOV
763

×
764
  if (es::IsEnd(texLoaders, found)) {
×
765
    throw es::InvalidVersionError();
UNCOV
766
  }
×
767

768
  *this = found->second(rd, platform);
×
769
  return;
UNCOV
770
}
×
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