/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "ImageLoaderKtx.hpp" #include #include #include #include #include namespace { void KtxDestroy(ktxTexture* tex) { ktxTexture_Destroy(tex); } } namespace OpenVulkano::Image { std::unique_ptr ImageLoaderKtx::loadFromFile(const std::string& filePath) { ktxTexture* tmp = nullptr; KTX_error_code error_code = ktxTexture_CreateFromNamedFile(filePath.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &tmp); std::unique_ptr texture(tmp, &KtxDestroy); if (error_code != KTX_SUCCESS) { throw std::runtime_error("Failed to load KTX texture: " + std::string(ktxErrorString(error_code))); } auto result = ExtractImage(texture.get()); return result; } std::unique_ptr ImageLoaderKtx::loadFromMemory(const std::vector& buffer) { ktxTexture* tmp = nullptr; KTX_error_code error_code = ktxTexture_CreateFromMemory(buffer.data(), buffer.size(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &tmp); std::unique_ptr texture(tmp, &KtxDestroy); if (error_code != KTX_SUCCESS) { throw std::runtime_error("Failed to load KTX texture from memory: " + std::string(ktxErrorString(error_code))); } auto result = ExtractImage(texture.get()); return result; } Math::Vector2i ImageLoaderKtx::GetImageDimensions(const std::string& filename) { ktxTexture* tmp = nullptr; KTX_error_code result = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &tmp); std::unique_ptr texture(tmp, &KtxDestroy); if (result != KTX_SUCCESS) { throw std::runtime_error("Failed to load KTX texture for dimensions: " + std::string(ktxErrorString(result))); } Math::Vector2i dimensions(texture->baseWidth, texture->baseHeight); return dimensions; } std::unique_ptr ImageLoaderKtx::ExtractImage(ktxTexture* texture) { if (!texture->pData) { throw std::runtime_error("No image data found in KTX texture."); } auto width = static_cast(texture->baseWidth); auto height = static_cast(texture->baseHeight); auto image = std::make_unique(); image->resolution.x = width; image->resolution.y = height; image->resolution.z = 1; if (texture->classId == ktxTexture1_c) { ktxTexture1* tx = reinterpret_cast(texture); DataFormat format = DataFormat::Format::UNDEFINED; switch (tx->glInternalformat) { case 0x8051: /* GL_RGB8_EXT */ format = DataFormat::Format::R8G8B8_UNORM; break; case 0x8054: /* GL_RGB16_EXT */ format = DataFormat::Format::R16G16B16_UNORM; break; case 0x8057: /* GL_RGB5_A1_EXT */ format = DataFormat::Format::R5G5B5A1_UNORM_PACK16; break; case 0x8058: /* GL_RGBA8_EXT */ format = DataFormat::Format::R8G8B8A8_UNORM; break; case 0x8059: /* GL_RGB10_A2_EXT */ format = DataFormat::Format::A2R10G10B10_UNORM_PACK32; break; case 0x805B: /* GL_RGBA16_EXT */ format = DataFormat::Format::R16G16B16A16_UNORM; break; default: throw std::runtime_error("Unhandled texture1 format: " + tx->glInternalformat); } image->dataFormat = format; } else if (texture->classId == ktxTexture2_c) { ktxTexture2* tx = reinterpret_cast(texture); image->dataFormat = reinterpret_cast(tx->vkFormat); } else [[unlikely]] { throw std::runtime_error("ktxTexture has unhandled classId!"); } image->data = Array(texture->dataSize); memcpy(image->data.Data(), texture->pData, image->data.Size()); return image; } }