diff --git a/3rdParty/CMakeLists.txt b/3rdParty/CMakeLists.txt index c9bc665..d327508 100644 --- a/3rdParty/CMakeLists.txt +++ b/3rdParty/CMakeLists.txt @@ -42,4 +42,5 @@ if(ENABLE_TEST) endif() add_subdirectory(tinyusdz) -add_subdirectory(ktx-software) \ No newline at end of file +add_subdirectory(ktx-software) +add_subdirectory(dds_image) \ No newline at end of file diff --git a/3rdParty/dds_image/CMakeLists.txt b/3rdParty/dds_image/CMakeLists.txt new file mode 100644 index 0000000..0f37104 --- /dev/null +++ b/3rdParty/dds_image/CMakeLists.txt @@ -0,0 +1,15 @@ +include(FetchContent) + +if(NOT DEFINED DDS_IMAGE_REPO) + set(DDS_IMAGE_REPO https://github.com/spnda/dds_image.git) +endif () + +FetchContent_Declare( + dds_image + EXCLUDE_FROM_ALL + GIT_REPOSITORY ${DDS_IMAGE_REPO} + GIT_TAG main + GIT_SHALLOW TRUE +) + +FetchContent_MakeAvailable(dds_image) \ No newline at end of file diff --git a/openVulkanoCpp/CMakeLists.txt b/openVulkanoCpp/CMakeLists.txt index dfb5641..6a86577 100644 --- a/openVulkanoCpp/CMakeLists.txt +++ b/openVulkanoCpp/CMakeLists.txt @@ -67,7 +67,7 @@ if (NOT ANDROID AND NOT IOS) endif() endif() -target_link_libraries(openVulkanoCpp PUBLIC magic_enum yaml-cpp fmt spdlog glm pugixml stb eigen utf8cpp imgui_internal TracyClient stud-uuid ryml unordered_dense units ktx) +target_link_libraries(openVulkanoCpp PUBLIC magic_enum yaml-cpp fmt spdlog glm pugixml stb eigen utf8cpp imgui_internal TracyClient stud-uuid ryml unordered_dense units ktx dds_image) LinkAssimp(openVulkanoCpp) LinkLibArchive(openVulkanoCpp) LinkLibJpegTurbo(openVulkanoCpp) diff --git a/openVulkanoCpp/Image/ImageLoaderDds.cpp b/openVulkanoCpp/Image/ImageLoaderDds.cpp new file mode 100644 index 0000000..cdf1c6e --- /dev/null +++ b/openVulkanoCpp/Image/ImageLoaderDds.cpp @@ -0,0 +1,294 @@ +/* + * 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 "ImageLoaderDds.hpp" + +#include + +namespace OpenVulkano::Image +{ + std::unique_ptr ImageLoaderDds::loadFromFile(const std::string& filePath) + { + dds::Image image; + if (dds::readFile(filePath, &image) != dds::ReadResult::Success) + { + throw std::runtime_error("Failed to load DDS texture"); + } + return ExtractImage(&image); + } + + std::unique_ptr ImageLoaderDds::loadFromMemory(const std::vector& buffer) + { + dds::Image image; + if (dds::readImage(const_cast(buffer.data()), buffer.size(), &image) != dds::ReadResult::Success) + { + throw std::runtime_error("Failed to load DDS texture"); + } + return ExtractImage(&image); + } + + Math::Vector2i ImageLoaderDds::GetImageDimensions(const std::string& filename) + { + dds::Image image; + if (dds::readFile(filename, &image) != dds::ReadResult::Success) + { + throw std::runtime_error("Failed to load DDS texture"); + } + + Math::Vector2i result; + result.x = image.width; + result.y = image.height; + + return result; + } + + std::unique_ptr ImageLoaderDds::ExtractImage(dds::Image* ddsImage) + { + auto image = std::make_unique(); + + image->resolution.x = ddsImage->width; + image->resolution.y = ddsImage->height; + image->resolution.z = 1; + + if (ddsImage->mipmaps.size() == 0) + { + throw std::runtime_error("Failed to read an image from a texture with no mipmaps"); + } + + dds::span texture = ddsImage->mipmaps[0]; + + image->data = Array(texture.size_bytes()); + memcpy(image->data.Data(), texture.data(), texture.size_bytes()); + + image->dataFormat = DataFormat::Format::UNDEFINED; + switch (ddsImage->format) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + image->dataFormat = DataFormat::Format::R32G32B32A32_SFLOAT; + break; + case DXGI_FORMAT_R32G32B32A32_UINT: + image->dataFormat = DataFormat::Format::R32G32B32A32_UINT; + break; + case DXGI_FORMAT_R32G32B32A32_SINT: + image->dataFormat = DataFormat::Format::R32G32B32A32_SINT; + break; + case DXGI_FORMAT_R32G32B32_FLOAT: + image->dataFormat = DataFormat::Format::R32G32B32_SFLOAT; + break; + case DXGI_FORMAT_R32G32B32_UINT: + image->dataFormat = DataFormat::Format::R32G32B32_UINT; + break; + case DXGI_FORMAT_R32G32B32_SINT: + image->dataFormat = DataFormat::Format::R32G32B32_SINT; + break; + + case DXGI_FORMAT_R16G16B16A16_FLOAT: + image->dataFormat = DataFormat::Format::R16G16B16A16_SFLOAT; + break; + case DXGI_FORMAT_R16G16B16A16_UNORM: + image->dataFormat = DataFormat::Format::R16G16B16A16_UNORM; + break; + case DXGI_FORMAT_R16G16B16A16_UINT: + image->dataFormat = DataFormat::Format::R16G16B16A16_UINT; + break; + case DXGI_FORMAT_R16G16B16A16_SNORM: + image->dataFormat = DataFormat::Format::R16G16B16A16_SNORM; + break; + case DXGI_FORMAT_R16G16B16A16_SINT: + image->dataFormat = DataFormat::Format::R16G16B16A16_SINT; + break; + + case DXGI_FORMAT_R32G32_FLOAT: + image->dataFormat = DataFormat::Format::R32G32_SFLOAT; + break; + case DXGI_FORMAT_R32G32_UINT: + image->dataFormat = DataFormat::Format::R32G32_UINT; + break; + case DXGI_FORMAT_R32G32_SINT: + image->dataFormat = DataFormat::Format::R32G32_SINT; + break; + + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + image->dataFormat = DataFormat::Format::D32_SFLOAT_S8_UINT; + break; + + case DXGI_FORMAT_R8G8B8A8_UNORM: + image->dataFormat = DataFormat::Format::R8G8B8A8_UNORM; + break; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + image->dataFormat = DataFormat::Format::R8G8B8A8_SRGB; + break; + case DXGI_FORMAT_R8G8B8A8_UINT: + image->dataFormat = DataFormat::Format::R8G8B8A8_UINT; + break; + case DXGI_FORMAT_R8G8B8A8_SNORM: + image->dataFormat = DataFormat::Format::R8G8B8A8_SNORM; + break; + case DXGI_FORMAT_R8G8B8A8_SINT: + image->dataFormat = DataFormat::Format::R8G8B8A8_SINT; + break; + + case DXGI_FORMAT_R16G16_FLOAT: + image->dataFormat = DataFormat::Format::R16G16_SFLOAT; + break; + case DXGI_FORMAT_R16G16_UNORM: + image->dataFormat = DataFormat::Format::R16G16_UNORM; + break; + case DXGI_FORMAT_R16G16_UINT: + image->dataFormat = DataFormat::Format::R16G16_UINT; + break; + case DXGI_FORMAT_R16G16_SNORM: + image->dataFormat = DataFormat::Format::R16G16_SNORM; + break; + case DXGI_FORMAT_R16G16_SINT: + image->dataFormat = DataFormat::Format::R16G16_SINT; + break; + + case DXGI_FORMAT_D32_FLOAT: + image->dataFormat = DataFormat::Format::D32_SFLOAT; + break; + + case DXGI_FORMAT_R32_FLOAT: + image->dataFormat = DataFormat::Format::R32_SFLOAT; + break; + case DXGI_FORMAT_R32_UINT: + image->dataFormat = DataFormat::Format::R32_UINT; + break; + case DXGI_FORMAT_R32_SINT: + image->dataFormat = DataFormat::Format::R32_SINT; + break; + + case DXGI_FORMAT_D24_UNORM_S8_UINT: + image->dataFormat = DataFormat::Format::D24_UNORM_S8_UINT; + break; + + case DXGI_FORMAT_R8G8_UNORM: + image->dataFormat = DataFormat::Format::R8G8_UNORM; + break; + case DXGI_FORMAT_R8G8_UINT: + image->dataFormat = DataFormat::Format::R8G8_UINT; + break; + case DXGI_FORMAT_R8G8_SNORM: + image->dataFormat = DataFormat::Format::R8G8_SNORM; + break; + case DXGI_FORMAT_R8G8_SINT: + image->dataFormat = DataFormat::Format::R8G8_SINT; + break; + + case DXGI_FORMAT_D16_UNORM: + image->dataFormat = DataFormat::Format::D16_UNORM; + break; + case DXGI_FORMAT_R16_FLOAT: + image->dataFormat = DataFormat::Format::R16_SFLOAT; + break; + case DXGI_FORMAT_R16_UNORM: + image->dataFormat = DataFormat::Format::R16_UNORM; + break; + case DXGI_FORMAT_R16_UINT: + image->dataFormat = DataFormat::Format::R16_UINT; + break; + case DXGI_FORMAT_R16_SNORM: + image->dataFormat = DataFormat::Format::R16_SNORM; + break; + case DXGI_FORMAT_R16_SINT: + image->dataFormat = DataFormat::Format::R16_SINT; + break; + + case DXGI_FORMAT_R8_UNORM: + image->dataFormat = DataFormat::Format::R8_UNORM; + break; + case DXGI_FORMAT_R8_UINT: + image->dataFormat = DataFormat::Format::R8_UINT; + break; + case DXGI_FORMAT_R8_SNORM: + image->dataFormat = DataFormat::Format::R8_SNORM; + break; + case DXGI_FORMAT_R8_SINT: + image->dataFormat = DataFormat::Format::R8_SINT; + break; + + case DXGI_FORMAT_BC1_UNORM: + image->dataFormat = DataFormat::Format::BC1_RGBA_UNORM_BLOCK; + break; + case DXGI_FORMAT_BC1_UNORM_SRGB: + image->dataFormat = DataFormat::Format::BC1_RGBA_SRGB_BLOCK; + break; + + case DXGI_FORMAT_BC2_UNORM: + image->dataFormat = DataFormat::Format::BC2_UNORM_BLOCK; + break; + case DXGI_FORMAT_BC2_UNORM_SRGB: + image->dataFormat = DataFormat::Format::BC2_SRGB_BLOCK; + break; + + case DXGI_FORMAT_BC3_UNORM: + image->dataFormat = DataFormat::Format::BC3_UNORM_BLOCK; + break; + case DXGI_FORMAT_BC3_UNORM_SRGB: + image->dataFormat = DataFormat::Format::BC3_SRGB_BLOCK; + break; + + case DXGI_FORMAT_BC4_UNORM: + image->dataFormat = DataFormat::Format::BC4_UNORM_BLOCK; + break; + case DXGI_FORMAT_BC4_SNORM: + image->dataFormat = DataFormat::Format::BC4_SNORM_BLOCK; + break; + + case DXGI_FORMAT_BC5_UNORM: + image->dataFormat = DataFormat::Format::BC5_UNORM_BLOCK; + break; + case DXGI_FORMAT_BC5_SNORM: + image->dataFormat = DataFormat::Format::BC5_SNORM_BLOCK; + break; + + case DXGI_FORMAT_B5G6R5_UNORM: + image->dataFormat = DataFormat::Format::B5G6R5_UNORM_PACK16; + break; + case DXGI_FORMAT_B5G5R5A1_UNORM: + image->dataFormat = DataFormat::Format::B5G5R5A1_UNORM_PACK16; + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM: + image->dataFormat = DataFormat::Format::B8G8R8A8_UNORM; + break; + case DXGI_FORMAT_B8G8R8X8_UNORM: + image->dataFormat = DataFormat::Format::B8G8R8A8_SNORM; + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + image->dataFormat = DataFormat::Format::B8G8R8A8_SRGB; + break; + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + image->dataFormat = DataFormat::Format::B8G8R8A8_SRGB; + break; + + case DXGI_FORMAT_BC6H_UF16: + image->dataFormat = DataFormat::Format::BC6H_UFLOAT_BLOCK; + break; + case DXGI_FORMAT_BC6H_SF16: + image->dataFormat = DataFormat::Format::BC6H_SFLOAT_BLOCK; + break; + + case DXGI_FORMAT_BC7_UNORM: + image->dataFormat = DataFormat::Format::BC7_UNORM_BLOCK; + break; + case DXGI_FORMAT_BC7_UNORM_SRGB: + image->dataFormat = DataFormat::Format::BC7_SRGB_BLOCK; + break; + + case DXGI_FORMAT_B4G4R4A4_UNORM: + image->dataFormat = DataFormat::Format::B4G4R4A4_UNORM_PACK16; + break; + + default: + throw std::runtime_error("Unhandled DDS texture format: " + + std::to_string(*reinterpret_cast(&ddsImage->format))); + } + + return image; + } +} diff --git a/openVulkanoCpp/Image/ImageLoaderDds.hpp b/openVulkanoCpp/Image/ImageLoaderDds.hpp new file mode 100644 index 0000000..05717c3 --- /dev/null +++ b/openVulkanoCpp/Image/ImageLoaderDds.hpp @@ -0,0 +1,28 @@ +/* + * 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/. + */ + +#pragma once + +#include "ImageLoader.hpp" + +namespace dds +{ + struct Image; +} + +namespace OpenVulkano::Image +{ + class ImageLoaderDds : public IImageLoader + { + public: + std::unique_ptr loadFromFile(const std::string& filePath) override; + std::unique_ptr loadFromMemory(const std::vector& buffer) override; + Math::Vector2i GetImageDimensions(const std::string& filename) override; + + protected: + std::unique_ptr ExtractImage(dds::Image* ddsImage); + }; +}