Skip to content

Commit bb5d864

Browse files
committed
Merge branch 'main' into vtfpp-endian
2 parents 6206f0d + 82d8f75 commit bb5d864

File tree

15 files changed

+922
-76
lines changed

15 files changed

+922
-76
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ if(SOURCEPP_BUILD_PYTHON_WRAPPERS)
251251
"sourcepp._sourcepp_impl.vtfpp"
252252
"sourcepp._sourcepp_impl.vtfpp.ImageFormatDetails"
253253
"sourcepp._sourcepp_impl.vtfpp.ImageDimensions"
254-
"sourcepp._sourcepp_impl.vtfpp.ImageConversion")
254+
"sourcepp._sourcepp_impl.vtfpp.ImageConversion"
255+
"sourcepp._sourcepp_impl.vtfpp.ImageQuantize")
255256
foreach(MODULE ${${SOURCEPP_PYTHON_NAME}_MODULES})
256257
string(REPLACE "." "/" MODULE_DIR "${MODULE}")
257258
string(REPLACE "." "_" MODULE_NAME_NORMALIZED "${MODULE}")

FUTURE.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
- There is literally nothing else that supports BC6H
1111
- `bsppp`
1212
- Console paklump support
13-
- Note that XBOX uses PC format. X360, PS3 do not
13+
- Note that XBOX uses XZP lump, X360, PS3 use PC lump but console style zip
1414
- Support parsing more lumps
1515
- Think about GoldSrc support
1616
- `dmxpp`
@@ -42,6 +42,3 @@
4242
- XZP write support
4343
- `vtfpp`
4444
- Add a MKS parser/writer
45-
- Add DPID resize filter
46-
- Allow directly applying an HDRI to a VTF without requiring the user to write a custom wrapper
47-
- XTF support

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,14 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
393393
<td align="center">✅</td>
394394
<td align="center">✅</td>
395395
</tr>
396+
<tr><!-- empty row to disable github striped bg color --></tr>
397+
<tr>
398+
<td>
399+
<a href="https://developer.valvesoftware.com/wiki/Half-Life_2_(Xbox)/Modding_Guide">XTF</a> v5.0
400+
</td>
401+
<td align="center">✅</td>
402+
<td align="center">✅</td>
403+
</tr>
396404
</table>
397405

398406
(\*) These libraries are incomplete and still in development. Their interfaces are unstable and will likely change in the future.

docs/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,13 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
342342
<td align="center">✅</td>
343343
<td align="center">✅</td>
344344
</tr>
345+
<tr>
346+
<td>
347+
<a href="https://developer.valvesoftware.com/wiki/Half-Life_2_(Xbox)/Modding_Guide">XTF</a> v5.0
348+
</td>
349+
<td align="center">✅</td>
350+
<td align="center">✅</td>
351+
</tr>
345352
</table>
346353
\endhtmlonly
347354

include/vtfpp/ImageFormats.h

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,20 @@ namespace ImageFormatDetails {
734734
return length;
735735
}
736736

737+
// XTF (PLATFORM_XBOX) has padding between frames to align each one to 512 bytes
738+
[[nodiscard]] constexpr uint32_t getDataLengthXBOX(bool padded, ImageFormat format, uint8_t mipCount, uint16_t frameCount, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t sliceCount = 1) {
739+
uint32_t length = 0;
740+
for (int j = 0; j < frameCount; j++) {
741+
for (int i = 0; i < mipCount; i++) {
742+
length += ImageFormatDetails::getDataLength(format, ImageDimensions::getMipDim(i, width), ImageDimensions::getMipDim(i, height), sliceCount) * faceCount;
743+
}
744+
if (padded && j + 1 != frameCount && length > 512) {
745+
length += sourcepp::math::paddingForAlignment(512, length);
746+
}
747+
}
748+
return length;
749+
}
750+
737751
[[nodiscard]] constexpr bool getDataPosition(uint32_t& offset, uint32_t& length, ImageFormat format, uint8_t mip, uint8_t mipCount, uint16_t frame, uint16_t frameCount, uint8_t face, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t slice = 0, uint16_t sliceCount = 1) {
738752
offset = 0;
739753
length = 0;
@@ -745,16 +759,39 @@ namespace ImageFormatDetails {
745759
if (i == mip && j == frame && k == face && l == slice) {
746760
length = imageSize;
747761
return true;
748-
} else {
749-
offset += imageSize;
750762
}
763+
offset += imageSize;
751764
}
752765
}
753766
}
754767
}
755768
return false;
756769
}
757770

771+
// XTF (PLATFORM_XBOX) is more like DDS layout
772+
[[nodiscard]] constexpr bool getDataPositionXbox(uint32_t& offset, uint32_t& length, bool padded, ImageFormat format, uint8_t mip, uint8_t mipCount, uint16_t frame, uint16_t frameCount, uint8_t face, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t slice = 0, uint16_t sliceCount = 1) {
773+
offset = 0;
774+
length = 0;
775+
for (int j = 0; j < frameCount; j++) {
776+
for (int k = 0; k < faceCount; k++) {
777+
for (int i = 0; i < mipCount; i++) {
778+
for (int l = 0; l < sliceCount; l++) {
779+
const auto imageSize = ImageFormatDetails::getDataLength(format, ImageDimensions::getMipDim(i, width), ImageDimensions::getMipDim(i, height));
780+
if (i == mip && j == frame && k == face && l == slice) {
781+
length = imageSize;
782+
return true;
783+
}
784+
offset += imageSize;
785+
}
786+
}
787+
}
788+
if (padded && j + 1 != frameCount && offset > 512) {
789+
offset += sourcepp::math::paddingForAlignment(512, offset);
790+
}
791+
}
792+
return false;
793+
}
794+
758795
} // namespace ImageFormatDetails
759796

760797
} // namespace vtfpp

include/vtfpp/ImageQuantize.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
#include "ImageConversion.h"
4+
5+
namespace vtfpp::ImageQuantize {
6+
7+
/// Converts a paletted image to something usable.
8+
[[nodiscard]] std::vector<std::byte> convertP8ImageDataToBGRA8888(std::span<const std::byte> paletteData, std::span<const std::byte> imageData);
9+
10+
} // namespace vtfpp::ImageQuantize

include/vtfpp/VTF.h

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
namespace vtfpp {
2121

2222
constexpr uint32_t VTF_SIGNATURE = sourcepp::parser::binary::makeFourCC("VTF\0");
23+
constexpr uint32_t XTF_SIGNATURE = sourcepp::parser::binary::makeFourCC("XTF\0");
2324
constexpr uint32_t VTFX_SIGNATURE = sourcepp::parser::binary::makeFourCC("VTFX");
2425
constexpr uint32_t VTF3_SIGNATURE = sourcepp::parser::binary::makeFourCC("VTF3");
2526

@@ -34,8 +35,10 @@ enum class CompressionMethod : int16_t {
3435

3536
struct Resource {
3637
enum Type : uint32_t {
37-
TYPE_UNKNOWN = 0, // Unknown
38+
TYPE_UNKNOWN = 0, // Unknown
3839
TYPE_THUMBNAIL_DATA = 1,
40+
TYPE_PALETTE_DATA = 2, // Hack for XBOX platform
41+
TYPE_FALLBACK_DATA = 3, // Hack for XBOX platform
3942
TYPE_PARTICLE_SHEET_DATA = 16,
4043
TYPE_HOTSPOT_DATA = 43,
4144
TYPE_IMAGE_DATA = 48,
@@ -45,13 +48,16 @@ struct Resource {
4548
TYPE_LOD_CONTROL_INFO = sourcepp::parser::binary::makeFourCC("LOD\0"),
4649
TYPE_KEYVALUES_DATA = sourcepp::parser::binary::makeFourCC("KVD\0"),
4750
};
48-
static consteval std::array<Type, 9> getOrder() {
51+
static consteval std::array<Type, 11> getOrder() {
4952
return {
5053
TYPE_THUMBNAIL_DATA,
54+
TYPE_PALETTE_DATA,
55+
TYPE_FALLBACK_DATA,
5156
TYPE_PARTICLE_SHEET_DATA,
5257
TYPE_HOTSPOT_DATA,
5358
// regular Source can't handle out of order resources, but Strata can,
54-
// and it's the only branch that can read this and 7.6
59+
// and it's the only branch that can read this and 7.6.
60+
// Put this before the image data to fix resources being cut off when skipping mips
5561
TYPE_AUX_COMPRESSION,
5662
TYPE_IMAGE_DATA,
5763
TYPE_EXTENDED_FLAGS,
@@ -168,6 +174,12 @@ class VTF {
168174
};
169175
static constexpr uint32_t FLAGS_MASK_V2 = FLAG_V2_NO_DEPTH_BUFFER | FLAG_V2_CLAMP_U;
170176

177+
enum FlagsXBOX : uint32_t {
178+
FLAG_XBOX_CACHEABLE = 1 << 27,
179+
FLAG_XBOX_UNFILTERABLE_OK = 1 << 28,
180+
};
181+
static constexpr uint32_t FLAGS_MASK_XBOX = FLAG_XBOX_CACHEABLE | FLAG_XBOX_UNFILTERABLE_OK;
182+
171183
enum FlagsV3 : uint32_t {
172184
FLAG_V3_LOAD_ALL_MIPS = 1 << 10,
173185
FLAG_V3_VERTEX_TEXTURE = 1 << 26,
@@ -212,6 +224,7 @@ class VTF {
212224
enum Platform : uint32_t {
213225
PLATFORM_UNKNOWN = 0x000,
214226
PLATFORM_PC = 0x007,
227+
PLATFORM_XBOX = 0x005,
215228
PLATFORM_X360 = 0x360,
216229
PLATFORM_PS3_ORANGEBOX = 0x333,
217230
PLATFORM_PS3_PORTAL2 = 0x334,
@@ -239,6 +252,7 @@ class VTF {
239252
float bumpMapScale = 1.f;
240253
float gammaCorrection = 1.f;
241254
bool invertGreenChannel = false;
255+
uint8_t xboxMipScale = 0;
242256
};
243257

244258
/// This value is only valid when passed to VTF::create through CreationOptions
@@ -363,6 +377,12 @@ class VTF {
363377

364378
[[nodiscard]] uint8_t getThumbnailHeight() const;
365379

380+
[[nodiscard]] uint8_t getFallbackWidth() const;
381+
382+
[[nodiscard]] uint8_t getFallbackHeight() const;
383+
384+
[[nodiscard]] uint8_t getFallbackMipCount() const;
385+
366386
[[nodiscard]] const std::vector<Resource>& getResources() const;
367387

368388
[[nodiscard]] const Resource* getResource(Resource::Type type) const;
@@ -434,6 +454,8 @@ class VTF {
434454

435455
void setThumbnail(std::span<const std::byte> imageData_, ImageFormat format_, uint16_t width_, uint16_t height_, float quality = ImageConversion::DEFAULT_COMPRESSED_QUALITY);
436456

457+
bool setThumbnail(const std::string& imagePath, float quality = ImageConversion::DEFAULT_COMPRESSED_QUALITY); // NOLINT(*-use-nodiscard)
458+
437459
void computeThumbnail(ImageConversion::ResizeFilter filter = ImageConversion::ResizeFilter::DEFAULT, float quality = ImageConversion::DEFAULT_COMPRESSED_QUALITY);
438460

439461
void removeThumbnail();
@@ -442,6 +464,26 @@ class VTF {
442464

443465
bool saveThumbnailToFile(const std::string& imagePath, ImageConversion::FileFormat fileFormat = ImageConversion::FileFormat::DEFAULT) const; // NOLINT(*-use-nodiscard)
444466

467+
[[nodiscard]] bool hasFallbackData() const;
468+
469+
[[nodiscard]] std::span<const std::byte> getFallbackDataRaw(uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0) const;
470+
471+
[[nodiscard]] std::vector<std::byte> getFallbackDataAs(ImageFormat newFormat, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0) const;
472+
473+
[[nodiscard]] std::vector<std::byte> getFallbackDataAsRGBA8888(uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0) const;
474+
475+
void computeFallback(ImageConversion::ResizeFilter filter = ImageConversion::ResizeFilter::DEFAULT);
476+
477+
void removeFallback();
478+
479+
[[nodiscard]] std::vector<std::byte> saveFallbackToFile(uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, ImageConversion::FileFormat fileFormat = ImageConversion::FileFormat::DEFAULT) const;
480+
481+
bool saveFallbackToFile(const std::string& imagePath, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, ImageConversion::FileFormat fileFormat = ImageConversion::FileFormat::DEFAULT) const; // NOLINT(*-use-nodiscard)
482+
483+
[[nodiscard]] uint8_t getXBOXMipScale() const;
484+
485+
void setXBOXMipScale(uint8_t xboxMipScale_);
486+
445487
[[nodiscard]] std::vector<std::byte> bake() const;
446488

447489
bool bake(const std::string& vtfPath) const; // NOLINT(*-use-nodiscard)
@@ -461,37 +503,37 @@ class VTF {
461503

462504
std::vector<std::byte> data;
463505

464-
//uint32_t signature;
465-
uint32_t version{};
466-
//uint32_t headerSize;
506+
uint32_t version = 4;
467507

468-
uint16_t width{};
469-
uint16_t height{};
470-
uint32_t flags{};
508+
uint16_t width = 0;
509+
uint16_t height = 0;
510+
uint32_t flags = VTF::FLAG_NO_MIP | VTF::FLAG_NO_LOD;
471511

472512
uint16_t frameCount = 1;
473-
uint16_t startFrame{};
513+
uint16_t startFrame = 0;
474514

475-
//uint8_t _padding0[4];
476-
sourcepp::math::Vec3f reflectivity{};
477-
//uint8_t _padding1[4];
515+
sourcepp::math::Vec3f reflectivity{0.2f, 0.2f, 0.2f};
478516

479-
float bumpMapScale{};
517+
float bumpMapScale = 0.f;
480518
ImageFormat format = ImageFormat::EMPTY;
481519
uint8_t mipCount = 1;
482520

483521
ImageFormat thumbnailFormat = ImageFormat::EMPTY;
484-
uint8_t thumbnailWidth{};
485-
uint8_t thumbnailHeight{};
522+
uint8_t thumbnailWidth = 0;
523+
uint8_t thumbnailHeight = 0;
524+
525+
uint8_t fallbackWidth = 0;
526+
uint8_t fallbackHeight = 0;
527+
uint8_t fallbackMipCount = 0;
528+
529+
// Number of times to multiply the scale of each mip by 2 when rendering on XBOX
530+
uint8_t xboxMipScale = 0;
486531

487532
// 1 for v7.1 and lower
488533
uint16_t sliceCount = 1;
489-
//uint8_t _padding2[3];
490534

491535
// Technically added in v7.3, but we use it to store image and thumbnail data in v7.2 and lower anyway
492-
//uint32_t resourceCount;
493536
std::vector<Resource> resources;
494-
//uint8_t _padding3[4];
495537

496538
// These aren't in the header
497539
Platform platform = PLATFORM_PC;

include/vtfpp/vtfpp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "HOT.h"
99
#include "ImageConversion.h"
1010
#include "ImageFormats.h"
11+
#include "ImageQuantize.h"
1112
#include "PPL.h"
1213
#include "SHT.h"
1314
#include "TTX.h"

0 commit comments

Comments
 (0)