feat: add more image types to load from cooked files

This commit is contained in:
2026-10-24 13:23:30 +02:00
parent 118016bcc7
commit 9cf9242c2a
5 changed files with 73 additions and 4 deletions
@@ -14,6 +14,7 @@ namespace TextureFile {
enum class PixelFormat : std::uint32_t {
RGBA16Float,
RGBA8,
};
struct Texture {
@@ -26,6 +27,7 @@ namespace TextureFile {
[[nodiscard]] std::size_t BytesPerPixel(PixelFormat format);
[[nodiscard]] Texture FromRGBA32Float(std::uint32_t width, std::uint32_t height, std::span<const float> rgba);
[[nodiscard]] Texture FromRGBA8(std::uint32_t width, std::uint32_t height, std::span<const std::uint8_t> rgba);
[[nodiscard]] std::vector<std::uint8_t> Write(const Texture& texture);
[[nodiscard]] Texture Read(std::span<const std::uint8_t> bytes);
+15
View File
@@ -21,6 +21,8 @@ std::size_t TextureFile::BytesPerPixel(PixelFormat format) {
switch (format) {
case PixelFormat::RGBA16Float:
return 4 * sizeof(std::uint16_t);
case PixelFormat::RGBA8:
return 4;
}
throw std::runtime_error("Unknown cooked texture pixel format");
}
@@ -46,6 +48,19 @@ TextureFile::Texture TextureFile::FromRGBA32Float(std::uint32_t width, std::uint
return texture;
}
TextureFile::Texture TextureFile::FromRGBA8(std::uint32_t width, std::uint32_t height, std::span<const std::uint8_t> rgba) {
if (rgba.size() != std::size_t{width} * height * 4) {
throw std::invalid_argument("RGBA pixel data doesn't match the texture size");
}
return Texture{
.width = width,
.height = height,
.format = PixelFormat::RGBA8,
.pixels = {rgba.begin(), rgba.end()},
};
}
std::vector<std::uint8_t> TextureFile::Write(const Texture& texture) {
if (texture.pixels.size() != ExpectedByteSize(texture)) {
throw std::invalid_argument("Texture pixel data doesn't match its size and format");
+28 -3
View File
@@ -53,19 +53,44 @@ namespace util
return ext == TextureFile::Extension;
}
static VkFormat toVkFormat(TextureFile::PixelFormat format)
static VkFormat toVkFormat(TextureFile::PixelFormat format, TextureIntent intent)
{
switch (format) {
case TextureFile::PixelFormat::RGBA16Float: return VK_FORMAT_R16G16B16A16_SFLOAT;
case TextureFile::PixelFormat::RGBA8:
return intent == TextureIntent::ColorSrgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
}
return VK_FORMAT_UNDEFINED;
}
// TheChef writes <image>.dtex next to the copied source, so every caller that has the source path gets it
static std::filesystem::path findCookedSibling(const std::filesystem::path& p)
{
std::filesystem::path cooked = p;
cooked += TextureFile::Extension;
std::error_code error;
if (!std::filesystem::is_regular_file(cooked, error)) {
return {};
}
const auto sourceTime = std::filesystem::last_write_time(p, error);
if (!error && sourceTime > std::filesystem::last_write_time(cooked, error)) {
return {};
}
return cooked;
}
ImageData loadImage(const std::filesystem::path& p, TextureIntent intent)
{
ImageData data;
if (!isCookedTextureExt(p)) {
if (const auto cooked = findCookedSibling(p); !cooked.empty()) {
if (ImageData cookedData = loadImage(cooked, intent); cookedData.byteSize != 0) {
return cookedData;
}
}
}
if (isCookedTextureExt(p)) {
try {
@@ -77,7 +102,7 @@ namespace util
data.height = static_cast<int>(texture.height);
data.channels = 4;
data.vkFormat = toVkFormat(texture.format);
data.vkFormat = toVkFormat(texture.format, intent);
data.byteSize = data.cookedPixels.size();
} catch (const std::exception& exception) {
spdlog::error("Failed to read cooked texture '{}': {}", p.string(), exception.what());