Skip to content

Commit 8b1520f

Browse files
feat(vtfpp): add PPL support
1 parent 09fe426 commit 8b1520f

File tree

12 files changed

+457
-102
lines changed

12 files changed

+457
-102
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,20 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
207207
</tr>
208208
<tr><!-- empty row to disable github striped bg color --></tr>
209209
<tr>
210-
<td rowspan="1"><code>vtfpp</code></td>
210+
<td rowspan="3"><code>vtfpp</code></td>
211+
<td><a href="https://developer.valvesoftware.com/wiki/PPL">PPL</a> v0</td>
212+
<td align="center">✅</td>
213+
<td align="center">✅</td>
214+
<td rowspan="3" align="center"></td>
215+
</tr>
216+
<tr><!-- empty row to disable github striped bg color --></tr>
217+
<tr>
211218
<td>
212219
<a href="https://developer.valvesoftware.com/wiki/VTF_(Valve_Texture_Format)">VTF</a> v7.0-7.6
213220
<br> &bull; <a href="https://stratasource.org">Strata Source</a> modifications
214221
</td>
215222
<td align="center">✅</td>
216223
<td align="center">✅</td>
217-
<td rowspan="1" align="center"></td>
218224
</tr>
219225
</table>
220226

docs/index.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,19 @@ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one
181181
<td align="center">✅</td>
182182
</tr>
183183
<tr>
184-
<td rowspan="1"><code>vtfpp</code></td>
184+
<td rowspan="2"><code>vtfpp</code></td>
185+
<td><a href="https://developer.valvesoftware.com/wiki/PPL">PPL</a> v0</td>
186+
<td align="center">✅</td>
187+
<td align="center">✅</td>
188+
<td rowspan="2" align="center"></td>
189+
</tr>
190+
<tr>
185191
<td>
186192
<a href="https://developer.valvesoftware.com/wiki/VTF_(Valve_Texture_Format)">VTF</a> v7.0-7.6
187193
<br> &bull; <a href="https://stratasource.org">Strata Source</a> modifications
188194
</td>
189195
<td align="center">✅</td>
190196
<td align="center">✅</td>
191-
<td rowspan="1" align="center"></td>
192197
</tr>
193198
</table>
194199
\endhtmlonly

include/vtfpp/ImageConversion.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ namespace ImageConversion {
204204
/// Converts image data to a PNG or HDR file. HDR output will be used for floating-point formats.
205205
[[nodiscard]] std::vector<std::byte> convertImageDataToFile(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height);
206206

207+
[[nodiscard]] std::vector<std::byte> convertFileToImageData(std::span<const std::byte> fileData, ImageFormat& format, int& width, int& height, int& frameCount);
208+
207209
enum class ResizeEdge {
208210
// Matches stbir_edge
209211
CLAMP = 0,

include/vtfpp/PPL.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#pragma once
2+
3+
#include <cstddef>
4+
#include <optional>
5+
#include <span>
6+
#include <string>
7+
#include <unordered_map>
8+
#include <vector>
9+
10+
#include <sourcepp/math/Integer.h>
11+
12+
#include "ImageConversion.h"
13+
14+
namespace vtfpp {
15+
16+
class PPL {
17+
public:
18+
struct Image {
19+
uint32_t width;
20+
uint32_t height;
21+
std::vector<std::byte> data;
22+
};
23+
24+
explicit PPL(uint32_t checksum_, ImageFormat format_ = ImageFormat::RGB888, uint32_t version_ = 0);
25+
26+
explicit PPL(std::span<const std::byte> pplData);
27+
28+
explicit PPL(const std::string& pplPath);
29+
30+
[[nodiscard]] explicit operator bool() const;
31+
32+
[[nodiscard]] uint32_t getVersion() const;
33+
34+
void setVersion(uint32_t newVersion);
35+
36+
[[nodiscard]] uint32_t getChecksum() const;
37+
38+
void setChecksum(uint32_t newChecksum);
39+
40+
[[nodiscard]] ImageFormat getFormat() const;
41+
42+
void setFormat(ImageFormat newFormat);
43+
44+
[[nodiscard]] bool hasImageForLOD(uint32_t lod) const;
45+
46+
[[nodiscard]] std::vector<uint32_t> getImageLODs() const;
47+
48+
[[nodiscard]] const Image* getImageRaw(uint32_t lod = 0) const;
49+
50+
[[nodiscard]] std::optional<Image> getImageAs(ImageFormat newFormat, uint32_t lod = 0) const;
51+
52+
[[nodiscard]] std::optional<Image> getImageAsRGB888(uint32_t lod = 0) const;
53+
54+
bool setImage(std::span<const std::byte> imageData, ImageFormat format_, uint32_t width, uint32_t height, uint32_t lod = 0);
55+
56+
bool setImage(std::span<const std::byte> imageData, ImageFormat format_, uint32_t width, uint32_t height, uint32_t resizedWidth, uint32_t resizedHeight, uint32_t lod = 0, ImageConversion::ResizeFilter filter = ImageConversion::ResizeFilter::BILINEAR);
57+
58+
bool setImage(const std::string& imagePath, uint32_t lod);
59+
60+
bool setImage(const std::string& imagePath, uint32_t resizedWidth, uint32_t resizedHeight, uint32_t lod = 0, ImageConversion::ResizeFilter filter = ImageConversion::ResizeFilter::BILINEAR);
61+
62+
[[nodiscard]] std::vector<std::byte> saveImageToFile(uint32_t lod = 0) const;
63+
64+
bool saveImageToFile(const std::string& imagePath, uint32_t lod = 0) const; // NOLINT(*-use-nodiscard)
65+
66+
[[nodiscard]] std::vector<std::byte> bake();
67+
68+
bool bake(const std::string& pplPath);
69+
70+
protected:
71+
uint32_t version{};
72+
uint32_t checksum{};
73+
ImageFormat format{};
74+
75+
std::unordered_map<uint32_t, Image> images;
76+
};
77+
78+
} // namespace vtfpp

include/vtfpp/VTF.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,9 @@ class VTF {
318318

319319
bool setImage(const std::string& imagePath, ImageConversion::ResizeFilter filter = ImageConversion::ResizeFilter::BILINEAR, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0);
320320

321-
[[nodiscard]] std::vector<std::byte> convertAndSaveImageDataToFile(uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0) const;
321+
[[nodiscard]] std::vector<std::byte> saveImageToFile(uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0) const;
322322

323-
void convertAndSaveImageDataToFile(const std::string& imagePath, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0) const;
323+
bool saveImageToFile(const std::string& imagePath, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0) const; // NOLINT(*-use-nodiscard)
324324

325325
[[nodiscard]] bool hasThumbnailData() const;
326326

@@ -334,9 +334,9 @@ class VTF {
334334

335335
void removeThumbnail();
336336

337-
[[nodiscard]] std::vector<std::byte> convertAndSaveThumbnailDataToFile() const;
337+
[[nodiscard]] std::vector<std::byte> saveThumbnailToFile() const;
338338

339-
void convertAndSaveThumbnailDataToFile(const std::string& imagePath) const;
339+
bool saveThumbnailToFile(const std::string& imagePath) const; // NOLINT(*-use-nodiscard)
340340

341341
[[nodiscard]] std::vector<std::byte> bake();
342342

include/vtfpp/vtfpp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77

88
#include "ImageConversion.h"
99
#include "ImageFormats.h"
10+
#include "PPL.h"
1011
#include "VTF.h"

src/vtfpp/ImageConversion.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <algorithm>
44
#include <bit>
55
#include <cstring>
6+
#include <memory>
67
#include <span>
78

89
#ifdef SOURCEPP_BUILD_WITH_TBB
@@ -11,6 +12,7 @@
1112

1213
#include <Compressonator.h>
1314
#include <sourcepp/math/Float.h>
15+
#include <stb_image.h>
1416
#include <stb_image_resize2.h>
1517
#include <stb_image_write.h>
1618

@@ -864,6 +866,87 @@ std::vector<std::byte> ImageConversion::convertImageDataToFile(std::span<const s
864866
return out;
865867
}
866868

869+
std::vector<std::byte> ImageConversion::convertFileToImageData(std::span<const std::byte> fileData, ImageFormat& format, int& width, int& height, int& frameCount) {
870+
stbi_convert_iphone_png_to_rgb(true);
871+
872+
format = ImageFormat::EMPTY;
873+
width = 0;
874+
height = 0;
875+
int channels = 0;
876+
frameCount = 1;
877+
878+
if (stbi_is_hdr_from_memory(reinterpret_cast<const stbi_uc*>(fileData.data()), static_cast<int>(fileData.size()))) {
879+
std::unique_ptr<float, void(*)(void*)> stbImage{
880+
stbi_loadf_from_memory(reinterpret_cast<const stbi_uc*>(fileData.data()), static_cast<int>(fileData.size()), &width, &height, &channels, 0),
881+
&stbi_image_free,
882+
};
883+
if (!stbImage) {
884+
return {};
885+
}
886+
887+
switch (channels) {
888+
case 1: format = ImageFormat::R32F; break;
889+
case 3: format = ImageFormat::RGB323232F; break;
890+
case 4: format = ImageFormat::RGBA32323232F; break;
891+
default: return {};
892+
}
893+
894+
return {reinterpret_cast<std::byte*>(stbImage.get()), reinterpret_cast<std::byte*>(stbImage.get()) + ImageFormatDetails::getDataLength(format, width, height)};
895+
} else if (stbi_is_16_bit_from_memory(reinterpret_cast<const stbi_uc*>(fileData.data()), static_cast<int>(fileData.size()))) {
896+
std::unique_ptr<stbi_us, void(*)(void*)> stbImage{
897+
stbi_load_16_from_memory(reinterpret_cast<const stbi_uc*>(fileData.data()), static_cast<int>(fileData.size()), &width, &height, &channels, 0),
898+
&stbi_image_free,
899+
};
900+
if (!stbImage) {
901+
return {};
902+
}
903+
904+
if (channels == 4) {
905+
format = ImageFormat::RGBA16161616;
906+
} else {
907+
return {};
908+
}
909+
910+
return {reinterpret_cast<std::byte*>(stbImage.get()), reinterpret_cast<std::byte*>(stbImage.get()) + ImageFormatDetails::getDataLength(format, width, height)};
911+
} else if (fileData.size() >= 3 && static_cast<char>(fileData[0]) == 'G' && static_cast<char>(fileData[1]) == 'I' && static_cast<char>(fileData[2]) == 'F') {
912+
std::unique_ptr<stbi_uc, void(*)(void*)> stbImage{
913+
stbi_load_gif_from_memory(reinterpret_cast<const stbi_uc*>(fileData.data()), static_cast<int>(fileData.size()), nullptr, &width, &height, &frameCount, &channels, 0),
914+
&stbi_image_free,
915+
};
916+
if (!stbImage || !frameCount) {
917+
return {};
918+
}
919+
920+
switch (channels) {
921+
case 1: format = ImageFormat::I8; break;
922+
case 2: format = ImageFormat::UV88; break;
923+
case 3: format = ImageFormat::RGB888; break;
924+
case 4: format = ImageFormat::RGBA8888; break;
925+
default: return {};
926+
}
927+
928+
return {reinterpret_cast<std::byte*>(stbImage.get()), reinterpret_cast<std::byte*>(stbImage.get() + (ImageFormatDetails::getDataLength(format, width, height) * frameCount))};
929+
} else {
930+
std::unique_ptr<stbi_uc, void(*)(void*)> stbImage{
931+
stbi_load_from_memory(reinterpret_cast<const stbi_uc*>(fileData.data()), static_cast<int>(fileData.size()), &width, &height, &channels, 0),
932+
&stbi_image_free,
933+
};
934+
if (!stbImage) {
935+
return {};
936+
}
937+
938+
switch (channels) {
939+
case 1: format = ImageFormat::I8; break;
940+
case 2: format = ImageFormat::UV88; break;
941+
case 3: format = ImageFormat::RGB888; break;
942+
case 4: format = ImageFormat::RGBA8888; break;
943+
default: return {};
944+
}
945+
946+
return {reinterpret_cast<std::byte*>(stbImage.get()), reinterpret_cast<std::byte*>(stbImage.get()) + ImageFormatDetails::getDataLength(format, width, height)};
947+
}
948+
}
949+
867950
uint16_t ImageConversion::getResizedDim(uint16_t n, ResizeMethod method) {
868951
switch (method) {
869952
case ResizeMethod::NONE: break;

0 commit comments

Comments
 (0)