From da2a76f6daea25f34a74297abc65d6e26f576a01 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 3 Jan 2026 13:58:46 +0100 Subject: [PATCH 1/5] chore: update image namespacing --- src/ImageConverter.lua | 2 + src/ImageConverter/ImageConverter.cpp | 51 +- src/ImageConverter/ImageConverterArgs.cpp | 2 +- src/ImageConverter/ImageConverterArgs.h | 17 +- src/ObjImage/Image/DdsLoader.cpp | 11 +- src/ObjImage/Image/DdsLoader.h | 2 +- src/ObjImage/Image/DdsTypes.h | 196 ++--- src/ObjImage/Image/DdsWriter.cpp | 430 +++++----- src/ObjImage/Image/DdsWriter.h | 20 +- src/ObjImage/Image/Dx12TextureLoader.cpp | 185 ++-- src/ObjImage/Image/Dx12TextureLoader.h | 43 +- src/ObjImage/Image/Dx9TextureLoader.cpp | 185 ++-- src/ObjImage/Image/Dx9TextureLoader.h | 41 +- src/ObjImage/Image/IImageWriter.h | 21 - src/ObjImage/Image/ImageFormat.cpp | 295 +++---- src/ObjImage/Image/ImageFormat.h | 197 ++--- src/ObjImage/Image/ImageWriter.h | 24 + src/ObjImage/Image/IwiLoader.cpp | 29 +- src/ObjImage/Image/IwiLoader.h | 4 +- src/ObjImage/Image/IwiTypes.h | 437 +++++----- src/ObjImage/Image/IwiWriter13.cpp | 8 +- src/ObjImage/Image/IwiWriter13.h | 8 +- src/ObjImage/Image/IwiWriter27.cpp | 8 +- src/ObjImage/Image/IwiWriter27.h | 8 +- src/ObjImage/Image/IwiWriter6.cpp | 8 +- src/ObjImage/Image/IwiWriter6.h | 8 +- src/ObjImage/Image/IwiWriter8.cpp | 8 +- src/ObjImage/Image/IwiWriter8.h | 8 +- src/ObjImage/Image/Texture.cpp | 787 +++++++++--------- src/ObjImage/Image/Texture.h | 195 ++--- src/ObjImage/Image/TextureConverter.cpp | 379 ++++----- src/ObjImage/Image/TextureConverter.h | 37 +- .../Game/IW3/Image/AssetLoaderImageIW3.cpp | 9 +- .../Game/IW5/Image/LoaderImageIW5.cpp | 2 +- .../Game/T6/Image/LoaderImageT6.cpp | 2 +- src/ObjLoading/Image/ImageLoaderCommon.cpp | 15 + src/ObjLoading/Image/ImageLoaderCommon.h | 23 + .../Game/IW3/Image/ImageDumperIW3.cpp | 9 +- .../Game/IW3/Image/ImageDumperIW3.h | 4 +- .../Game/IW4/Image/ImageDumperIW4.cpp | 9 +- .../Game/IW4/Image/ImageDumperIW4.h | 4 +- .../Game/IW5/Image/ImageDumperIW5.cpp | 9 +- .../Game/IW5/Image/ImageDumperIW5.h | 4 +- .../Game/T5/Image/ImageDumperT5.cpp | 9 +- src/ObjWriting/Game/T5/Image/ImageDumperT5.h | 4 +- .../Game/T6/Image/ImageDumperT6.cpp | 11 +- src/ObjWriting/Game/T6/Image/ImageDumperT6.h | 4 +- 47 files changed, 1940 insertions(+), 1832 deletions(-) delete mode 100644 src/ObjImage/Image/IImageWriter.h create mode 100644 src/ObjImage/Image/ImageWriter.h create mode 100644 src/ObjLoading/Image/ImageLoaderCommon.cpp create mode 100644 src/ObjLoading/Image/ImageLoaderCommon.h diff --git a/src/ImageConverter.lua b/src/ImageConverter.lua index 79a7f3cf..a34fa239 100644 --- a/src/ImageConverter.lua +++ b/src/ImageConverter.lua @@ -38,11 +38,13 @@ function ImageConverter:project() self:include(includes) Utils:include(includes) + Common:include(includes) ObjImage:include(includes) Raw:use() links:linkto(Utils) + links:linkto(Common) links:linkto(ObjImage) links:linkall() end diff --git a/src/ImageConverter/ImageConverter.cpp b/src/ImageConverter/ImageConverter.cpp index 2db2e011..bdca8853 100644 --- a/src/ImageConverter/ImageConverter.cpp +++ b/src/ImageConverter/ImageConverter.cpp @@ -1,5 +1,6 @@ #include "ImageConverter.h" +#include "Game/IGame.h" #include "Image/DdsLoader.h" #include "Image/DdsWriter.h" #include "Image/IwiLoader.h" @@ -17,10 +18,12 @@ #include #include #include +#include namespace fs = std::filesystem; +using namespace image; -namespace image_converter +namespace { constexpr auto EXTENSION_IWI = ".iwi"; constexpr auto EXTENSION_DDS = ".dds"; @@ -29,7 +32,7 @@ namespace image_converter { public: ImageConverterImpl() - : m_game_to_convert_to(image_converter::Game::UNKNOWN) + : m_game_to_convert_to(std::nullopt) { } @@ -76,7 +79,7 @@ namespace image_converter return false; } - const auto texture = iwi::LoadIwi(file); + const auto texture = image::LoadIwi(file); if (!texture) return false; @@ -103,7 +106,7 @@ namespace image_converter return false; } - const auto texture = dds::LoadDds(file); + const auto texture = image::LoadDds(file); if (!texture) return false; @@ -129,23 +132,23 @@ namespace image_converter if (m_iwi_writer) return true; - if (m_game_to_convert_to == Game::UNKNOWN && !ShowGameTui()) + if (!m_game_to_convert_to && !ShowGameTui()) return false; - switch (m_game_to_convert_to) + switch (*m_game_to_convert_to) { - case Game::IW3: - m_iwi_writer = std::make_unique(); + case GameId::IW3: + m_iwi_writer = std::make_unique(); break; - case Game::IW4: - case Game::IW5: - m_iwi_writer = std::make_unique(); + case GameId::IW4: + case GameId::IW5: + m_iwi_writer = std::make_unique(); break; - case Game::T5: - m_iwi_writer = std::make_unique(); + case GameId::T5: + m_iwi_writer = std::make_unique(); break; - case Game::T6: - m_iwi_writer = std::make_unique(); + case GameId::T6: + m_iwi_writer = std::make_unique(); break; default: assert(false); @@ -170,19 +173,19 @@ namespace image_converter switch (num) { case 1: - m_game_to_convert_to = Game::IW3; + m_game_to_convert_to = GameId::IW3; break; case 2: - m_game_to_convert_to = Game::IW4; + m_game_to_convert_to = GameId::IW4; break; case 3: - m_game_to_convert_to = Game::IW5; + m_game_to_convert_to = GameId::IW5; break; case 4: - m_game_to_convert_to = Game::T5; + m_game_to_convert_to = GameId::T5; break; case 5: - m_game_to_convert_to = Game::T6; + m_game_to_convert_to = GameId::T6; break; default: con::error("Invalid input"); @@ -193,13 +196,13 @@ namespace image_converter } ImageConverterArgs m_args; - image_converter::Game m_game_to_convert_to; + std::optional m_game_to_convert_to; DdsWriter m_dds_writer; - std::unique_ptr m_iwi_writer; + std::unique_ptr m_iwi_writer; }; -} // namespace image_converter +} // namespace std::unique_ptr ImageConverter::Create() { - return std::make_unique(); + return std::make_unique(); } diff --git a/src/ImageConverter/ImageConverterArgs.cpp b/src/ImageConverter/ImageConverterArgs.cpp index fad732b8..e9fddb16 100644 --- a/src/ImageConverter/ImageConverterArgs.cpp +++ b/src/ImageConverter/ImageConverterArgs.cpp @@ -86,7 +86,7 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[]{ }; ImageConverterArgs::ImageConverterArgs() - : m_game_to_convert_to(image_converter::Game::UNKNOWN), + : m_game_to_convert_to(std::nullopt), m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v) { } diff --git a/src/ImageConverter/ImageConverterArgs.h b/src/ImageConverter/ImageConverterArgs.h index 2a221523..fe63a6c4 100644 --- a/src/ImageConverter/ImageConverterArgs.h +++ b/src/ImageConverter/ImageConverterArgs.h @@ -1,24 +1,13 @@ #pragma once +#include "Game/IGame.h" #include "Utils/Arguments/ArgumentParser.h" #include +#include #include #include -namespace image_converter -{ - enum class Game : std::uint8_t - { - UNKNOWN, - IW3, - IW4, - IW5, - T5, - T6 - }; -} // namespace image_converter - class ImageConverterArgs { public: @@ -26,7 +15,7 @@ public: bool ParseArgs(int argc, const char** argv, bool& shouldContinue); std::vector m_files_to_convert; - image_converter::Game m_game_to_convert_to; + std::optional m_game_to_convert_to; private: /** diff --git a/src/ObjImage/Image/DdsLoader.cpp b/src/ObjImage/Image/DdsLoader.cpp index f2ef47aa..eb85379a 100644 --- a/src/ObjImage/Image/DdsLoader.cpp +++ b/src/ObjImage/Image/DdsLoader.cpp @@ -9,7 +9,9 @@ #include #include -namespace dds +using namespace image; + +namespace { class DdsLoaderInternal { @@ -193,7 +195,7 @@ namespace dds return ReadPixelFormatUnsigned(pf); } - _NODISCARD bool ReadHeader() + [[nodiscard]] bool ReadHeader() { DDS_HEADER header{}; m_stream.read(reinterpret_cast(&header), sizeof(header)); @@ -277,10 +279,13 @@ namespace dds unsigned m_depth; const ImageFormat* m_format; }; +} // namespace +namespace image +{ std::unique_ptr LoadDds(std::istream& stream) { DdsLoaderInternal internal(stream); return internal.LoadDds(); } -} // namespace dds +} // namespace image diff --git a/src/ObjImage/Image/DdsLoader.h b/src/ObjImage/Image/DdsLoader.h index 90619b9f..5b7a93fe 100644 --- a/src/ObjImage/Image/DdsLoader.h +++ b/src/ObjImage/Image/DdsLoader.h @@ -5,7 +5,7 @@ #include #include -namespace dds +namespace image { std::unique_ptr LoadDds(std::istream& stream); } diff --git a/src/ObjImage/Image/DdsTypes.h b/src/ObjImage/Image/DdsTypes.h index 0d368dad..fce20384 100644 --- a/src/ObjImage/Image/DdsTypes.h +++ b/src/ObjImage/Image/DdsTypes.h @@ -2,110 +2,114 @@ #include -constexpr uint32_t MakeFourCc(const char ch0, const char ch1, const char ch2, const char ch3) +namespace image { - return static_cast(ch0) | static_cast(ch1) << 8 | static_cast(ch2) << 16 | static_cast(ch3) << 24; -} + constexpr uint32_t MakeFourCc(const char ch0, const char ch1, const char ch2, const char ch3) + { + return static_cast(ch0) | static_cast(ch1) << 8 | static_cast(ch2) << 16 | static_cast(ch3) << 24; + } -enum DDP_FLAGS -{ - DDPF_ALPHAPIXELS = 0x1, - DDPF_ALPHA = 0x2, - DDPF_FOURCC = 0x4, - DDPF_RGB = 0x40, - DDPF_YUV = 0x200, - DDPF_LUMINANCE = 0x20000 -}; + enum DDP_FLAGS + { + DDPF_ALPHAPIXELS = 0x1, + DDPF_ALPHA = 0x2, + DDPF_FOURCC = 0x4, + DDPF_RGB = 0x40, + DDPF_YUV = 0x200, + DDPF_LUMINANCE = 0x20000 + }; -enum DDS_HEADER_FLAGS -{ - DDSD_CAPS = 0x1, - DDSD_HEIGHT = 0x2, - DDSD_WIDTH = 0x4, - DDSD_PITCH = 0x8, - DDSD_PIXELFORMAT = 0x1000, - DDSD_MIPMAPCOUNT = 0x20000, - DDSD_LINEARSIZE = 0x80000, - DDSD_DEPTH = 0x800000, -}; + enum DDS_HEADER_FLAGS + { + DDSD_CAPS = 0x1, + DDSD_HEIGHT = 0x2, + DDSD_WIDTH = 0x4, + DDSD_PITCH = 0x8, + DDSD_PIXELFORMAT = 0x1000, + DDSD_MIPMAPCOUNT = 0x20000, + DDSD_LINEARSIZE = 0x80000, + DDSD_DEPTH = 0x800000, + }; -enum DDS_HEADER_CAPS -{ - DDSCAPS_COMPLEX = 0x8, - DDSCAPS_TEXTURE = 0x1000, - DDSCAPS_MIPMAP = 0x400000, -}; + enum DDS_HEADER_CAPS + { + DDSCAPS_COMPLEX = 0x8, + DDSCAPS_TEXTURE = 0x1000, + DDSCAPS_MIPMAP = 0x400000, + }; -enum DDS_HEADER_CAPS2 -{ - DDSCAPS2_CUBEMAP = 0x200, - DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, - DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, - DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, - DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, - DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, - DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, - DDSCAPS2_VOLUME = 0x200000, -}; + enum DDS_HEADER_CAPS2 + { + DDSCAPS2_CUBEMAP = 0x200, + DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, + DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, + DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, + DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, + DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, + DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, + DDSCAPS2_VOLUME = 0x200000, + }; -struct DDS_PIXELFORMAT -{ - uint32_t dwSize; - uint32_t dwFlags; - uint32_t dwFourCC; - uint32_t dwRGBBitCount; - uint32_t dwRBitMask; - uint32_t dwGBitMask; - uint32_t dwBBitMask; - uint32_t dwABitMask; -}; + struct DDS_PIXELFORMAT + { + uint32_t dwSize; + uint32_t dwFlags; + uint32_t dwFourCC; + uint32_t dwRGBBitCount; + uint32_t dwRBitMask; + uint32_t dwGBitMask; + uint32_t dwBBitMask; + uint32_t dwABitMask; + }; -struct DDS_HEADER -{ - uint32_t dwSize; - uint32_t dwFlags; - uint32_t dwHeight; - uint32_t dwWidth; - uint32_t dwPitchOrLinearSize; - uint32_t dwDepth; - uint32_t dwMipMapCount; - uint32_t dwReserved1[11]; - DDS_PIXELFORMAT ddspf; - uint32_t dwCaps; - uint32_t dwCaps2; - uint32_t dwCaps3; - uint32_t dwCaps4; - uint32_t dwReserved2; -}; + struct DDS_HEADER + { + uint32_t dwSize; + uint32_t dwFlags; + uint32_t dwHeight; + uint32_t dwWidth; + uint32_t dwPitchOrLinearSize; + uint32_t dwDepth; + uint32_t dwMipMapCount; + uint32_t dwReserved1[11]; + DDS_PIXELFORMAT ddspf; + uint32_t dwCaps; + uint32_t dwCaps2; + uint32_t dwCaps3; + uint32_t dwCaps4; + uint32_t dwReserved2; + }; -enum D3D10_RESOURCE_DIMENSION -{ - D3D10_RESOURCE_DIMENSION_UNKNOWN, - D3D10_RESOURCE_DIMENSION_BUFFER, - D3D10_RESOURCE_DIMENSION_TEXTURE1D, - D3D10_RESOURCE_DIMENSION_TEXTURE2D, - D3D10_RESOURCE_DIMENSION_TEXTURE3D -}; + enum D3D10_RESOURCE_DIMENSION + { + D3D10_RESOURCE_DIMENSION_UNKNOWN, + D3D10_RESOURCE_DIMENSION_BUFFER, + D3D10_RESOURCE_DIMENSION_TEXTURE1D, + D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3D10_RESOURCE_DIMENSION_TEXTURE3D + }; -enum DDS_HEADER_DXT10_MISC -{ - DDS_RESOURCE_MISC_TEXTURECUBE = 0x4 -}; + enum DDS_HEADER_DXT10_MISC + { + DDS_RESOURCE_MISC_TEXTURECUBE = 0x4 + }; -enum DDS_HEADER_DXT10_MISC2 -{ - DDS_ALPHA_MODE_UNKNOWN = 0x0, - DDS_ALPHA_MODE_STRAIGHT = 0x1, - DDS_ALPHA_MODE_PREMULTIPLIED = 0x2, - DDS_ALPHA_MODE_OPAQUE = 0x3, - DDS_ALPHA_MODE_CUSTOM = 0x4, -}; + enum DDS_HEADER_DXT10_MISC2 + { + DDS_ALPHA_MODE_UNKNOWN = 0x0, + DDS_ALPHA_MODE_STRAIGHT = 0x1, + DDS_ALPHA_MODE_PREMULTIPLIED = 0x2, + DDS_ALPHA_MODE_OPAQUE = 0x3, + DDS_ALPHA_MODE_CUSTOM = 0x4, + }; -struct DDS_HEADER_DXT10 -{ - oat::DXGI_FORMAT dxgiFormat; - D3D10_RESOURCE_DIMENSION resourceDimension; - uint32_t miscFlag; - uint32_t arraySize; - uint32_t miscFlags2; -}; + struct DDS_HEADER_DXT10 + { + oat::DXGI_FORMAT dxgiFormat; + D3D10_RESOURCE_DIMENSION resourceDimension; + uint32_t miscFlag; + uint32_t arraySize; + uint32_t miscFlags2; + }; + +} // namespace image diff --git a/src/ObjImage/Image/DdsWriter.cpp b/src/ObjImage/Image/DdsWriter.cpp index 93e88da0..bc3e5800 100644 --- a/src/ObjImage/Image/DdsWriter.cpp +++ b/src/ObjImage/Image/DdsWriter.cpp @@ -7,234 +7,242 @@ #include #include -const std::map DDS_CONVERSION_TABLE{ - {ImageFormatId::R8_G8_B8, ImageFormatId::B8_G8_R8_X8}, -}; +using namespace image; -class DdsWriterInternal +namespace { -public: - static bool SupportsImageFormat(const ImageFormat* imageFormat) + const std::map DDS_CONVERSION_TABLE{ + {ImageFormatId::R8_G8_B8, ImageFormatId::B8_G8_R8_X8}, + }; + + class DdsWriterInternal { - return true; - } - - static std::string GetFileExtension() - { - return ".dds"; - } - - DdsWriterInternal(std::ostream& stream, const Texture* texture) - : m_stream(stream), - m_texture(texture), - m_use_dx10_extension(false) - { - } - - void DumpImage() - { - ConvertTextureIfNecessary(); - - DDS_HEADER header{}; - PopulateDdsHeader(header); - - constexpr auto magic = MakeFourCc('D', 'D', 'S', ' '); - - m_stream.write(reinterpret_cast(&magic), sizeof(magic)); - m_stream.write(reinterpret_cast(&header), sizeof(header)); - - if (m_use_dx10_extension) + public: + static bool SupportsImageFormat(const ImageFormat* imageFormat) { - DDS_HEADER_DXT10 dxt10{}; - PopulateDxt10Header(dxt10); - m_stream.write(reinterpret_cast(&dxt10), sizeof(dxt10)); + return true; } - const auto mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1; - for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++) + static std::string GetFileExtension() { - const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel); - const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount(); - m_stream.write(reinterpret_cast(buffer), static_cast(mipLevelSize)); - } - } - - static constexpr unsigned Mask1(const unsigned length) - { - if (length >= sizeof(unsigned) * 8) - return UINT32_MAX; - - return UINT32_MAX >> (sizeof(unsigned) * 8 - length); - } - - void PopulatePixelFormatBlockCompressed(DDS_PIXELFORMAT& pf, const ImageFormatBlockCompressed* format) - { - pf.dwSize = sizeof(DDS_PIXELFORMAT); - pf.dwFlags = DDPF_FOURCC; - pf.dwRGBBitCount = 0; - pf.dwRBitMask = 0; - pf.dwGBitMask = 0; - pf.dwBBitMask = 0; - pf.dwABitMask = 0; - - // Use standard pixel format for DXT1-5 for maximum compatibility and only otherwise use DX10 extension - switch (format->GetDxgiFormat()) - { - case oat::DXGI_FORMAT_BC1_UNORM: - pf.dwFourCC = MakeFourCc('D', 'X', 'T', '1'); - break; - case oat::DXGI_FORMAT_BC2_UNORM: - pf.dwFourCC = MakeFourCc('D', 'X', 'T', '3'); - break; - case oat::DXGI_FORMAT_BC3_UNORM: - pf.dwFourCC = MakeFourCc('D', 'X', 'T', '5'); - break; - default: - m_use_dx10_extension = true; - pf.dwFourCC = MakeFourCc('D', 'X', '1', '0'); - break; - } - } - - static void PopulatePixelFormatUnsigned(DDS_PIXELFORMAT& pf, const ImageFormatUnsigned* format) - { - pf.dwSize = sizeof(DDS_PIXELFORMAT); - pf.dwFourCC = 0; - pf.dwRGBBitCount = format->m_bits_per_pixel; - pf.dwRBitMask = format->HasR() ? Mask1(format->m_r_size) << format->m_r_offset : 0; - pf.dwGBitMask = format->HasG() ? Mask1(format->m_g_size) << format->m_g_offset : 0; - pf.dwBBitMask = format->HasB() ? Mask1(format->m_b_size) << format->m_b_offset : 0; - pf.dwABitMask = format->HasA() ? Mask1(format->m_a_size) << format->m_a_offset : 0; - - pf.dwFlags = 0; - if (format->HasA()) - pf.dwFlags |= DDPF_ALPHAPIXELS; - - if (format->HasR() && !format->HasG() && !format->HasB()) - pf.dwFlags |= DDPF_LUMINANCE; - else - pf.dwFlags |= DDPF_RGB; - } - - void PopulatePixelFormat(DDS_PIXELFORMAT& pf) - { - const auto* format = m_texture->GetFormat(); - - switch (format->GetType()) - { - case ImageFormatType::BLOCK_COMPRESSED: - PopulatePixelFormatBlockCompressed(pf, dynamic_cast(format)); - break; - case ImageFormatType::UNSIGNED: - PopulatePixelFormatUnsigned(pf, dynamic_cast(format)); - break; - default: - assert(false); - break; - } - } - - void PopulateDdsHeader(DDS_HEADER& header) - { - header.dwSize = sizeof(header); - header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; - - if (m_texture->HasMipMaps()) - header.dwFlags |= DDSD_MIPMAPCOUNT; - - if (m_texture->GetFormat()->GetType() == ImageFormatType::BLOCK_COMPRESSED) - header.dwFlags |= DDSD_LINEARSIZE; - else - header.dwFlags |= DDSD_PITCH; - - if (m_texture->GetDepth() > 1) - header.dwFlags |= DDSD_DEPTH; - - header.dwHeight = m_texture->GetHeight(); - header.dwWidth = m_texture->GetWidth(); - header.dwDepth = m_texture->GetDepth(); - header.dwPitchOrLinearSize = static_cast(m_texture->GetFormat()->GetPitch(0, m_texture->GetWidth())); - header.dwMipMapCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1; - - PopulatePixelFormat(header.ddspf); - - header.dwCaps = DDSCAPS_TEXTURE; - - if (m_texture->HasMipMaps()) - header.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; - - if (m_texture->GetTextureType() == TextureType::T_CUBE) - header.dwCaps |= DDSCAPS_COMPLEX; - - header.dwCaps2 = 0; - - if (m_texture->GetTextureType() == TextureType::T_CUBE) - { - header.dwCaps2 |= DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX | DDSCAPS2_CUBEMAP_POSITIVEY - | DDSCAPS2_CUBEMAP_NEGATIVEY | DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ; + return ".dds"; } - header.dwCaps3 = 0; - header.dwCaps4 = 0; - header.dwReserved2 = 0; - } - - void PopulateDxt10Header(DDS_HEADER_DXT10& header) const - { - header.dxgiFormat = m_texture->GetFormat()->GetDxgiFormat(); - header.miscFlag = 0; - header.miscFlags2 = 0; - - switch (m_texture->GetTextureType()) + DdsWriterInternal(std::ostream& stream, const Texture* texture) + : m_stream(stream), + m_texture(texture), + m_use_dx10_extension(false) { - case TextureType::T_2D: - header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; - header.arraySize = 1; - break; - case TextureType::T_CUBE: - header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; - header.arraySize = 6; - header.miscFlag |= DDS_RESOURCE_MISC_TEXTURECUBE; - break; - case TextureType::T_3D: - header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D; - header.arraySize = 1; - break; } - } - void ConvertTextureIfNecessary() - { - const auto entry = DDS_CONVERSION_TABLE.find(m_texture->GetFormat()->GetId()); - - if (entry != DDS_CONVERSION_TABLE.end()) + void DumpImage() { - TextureConverter converter(m_texture, ImageFormat::ALL_FORMATS[static_cast(entry->second)]); - m_converted_texture = converter.Convert(); - m_texture = m_converted_texture.get(); + ConvertTextureIfNecessary(); + + DDS_HEADER header{}; + PopulateDdsHeader(header); + + constexpr auto magic = MakeFourCc('D', 'D', 'S', ' '); + + m_stream.write(reinterpret_cast(&magic), sizeof(magic)); + m_stream.write(reinterpret_cast(&header), sizeof(header)); + + if (m_use_dx10_extension) + { + DDS_HEADER_DXT10 dxt10{}; + PopulateDxt10Header(dxt10); + m_stream.write(reinterpret_cast(&dxt10), sizeof(dxt10)); + } + + const auto mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1; + for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++) + { + const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel); + const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount(); + m_stream.write(reinterpret_cast(buffer), static_cast(mipLevelSize)); + } } - } - std::ostream& m_stream; - const Texture* m_texture; - std::unique_ptr m_converted_texture; - bool m_use_dx10_extension; -}; + static constexpr unsigned Mask1(const unsigned length) + { + if (length >= sizeof(unsigned) * 8) + return UINT32_MAX; -DdsWriter::~DdsWriter() = default; + return UINT32_MAX >> (sizeof(unsigned) * 8 - length); + } -bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat) + void PopulatePixelFormatBlockCompressed(DDS_PIXELFORMAT& pf, const ImageFormatBlockCompressed* format) + { + pf.dwSize = sizeof(DDS_PIXELFORMAT); + pf.dwFlags = DDPF_FOURCC; + pf.dwRGBBitCount = 0; + pf.dwRBitMask = 0; + pf.dwGBitMask = 0; + pf.dwBBitMask = 0; + pf.dwABitMask = 0; + + // Use standard pixel format for DXT1-5 for maximum compatibility and only otherwise use DX10 extension + switch (format->GetDxgiFormat()) + { + case oat::DXGI_FORMAT_BC1_UNORM: + pf.dwFourCC = MakeFourCc('D', 'X', 'T', '1'); + break; + case oat::DXGI_FORMAT_BC2_UNORM: + pf.dwFourCC = MakeFourCc('D', 'X', 'T', '3'); + break; + case oat::DXGI_FORMAT_BC3_UNORM: + pf.dwFourCC = MakeFourCc('D', 'X', 'T', '5'); + break; + default: + m_use_dx10_extension = true; + pf.dwFourCC = MakeFourCc('D', 'X', '1', '0'); + break; + } + } + + static void PopulatePixelFormatUnsigned(DDS_PIXELFORMAT& pf, const ImageFormatUnsigned* format) + { + pf.dwSize = sizeof(DDS_PIXELFORMAT); + pf.dwFourCC = 0; + pf.dwRGBBitCount = format->m_bits_per_pixel; + pf.dwRBitMask = format->HasR() ? Mask1(format->m_r_size) << format->m_r_offset : 0; + pf.dwGBitMask = format->HasG() ? Mask1(format->m_g_size) << format->m_g_offset : 0; + pf.dwBBitMask = format->HasB() ? Mask1(format->m_b_size) << format->m_b_offset : 0; + pf.dwABitMask = format->HasA() ? Mask1(format->m_a_size) << format->m_a_offset : 0; + + pf.dwFlags = 0; + if (format->HasA()) + pf.dwFlags |= DDPF_ALPHAPIXELS; + + if (format->HasR() && !format->HasG() && !format->HasB()) + pf.dwFlags |= DDPF_LUMINANCE; + else + pf.dwFlags |= DDPF_RGB; + } + + void PopulatePixelFormat(DDS_PIXELFORMAT& pf) + { + const auto* format = m_texture->GetFormat(); + + switch (format->GetType()) + { + case ImageFormatType::BLOCK_COMPRESSED: + PopulatePixelFormatBlockCompressed(pf, dynamic_cast(format)); + break; + case ImageFormatType::UNSIGNED: + PopulatePixelFormatUnsigned(pf, dynamic_cast(format)); + break; + default: + assert(false); + break; + } + } + + void PopulateDdsHeader(DDS_HEADER& header) + { + header.dwSize = sizeof(header); + header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + + if (m_texture->HasMipMaps()) + header.dwFlags |= DDSD_MIPMAPCOUNT; + + if (m_texture->GetFormat()->GetType() == ImageFormatType::BLOCK_COMPRESSED) + header.dwFlags |= DDSD_LINEARSIZE; + else + header.dwFlags |= DDSD_PITCH; + + if (m_texture->GetDepth() > 1) + header.dwFlags |= DDSD_DEPTH; + + header.dwHeight = m_texture->GetHeight(); + header.dwWidth = m_texture->GetWidth(); + header.dwDepth = m_texture->GetDepth(); + header.dwPitchOrLinearSize = static_cast(m_texture->GetFormat()->GetPitch(0, m_texture->GetWidth())); + header.dwMipMapCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1; + + PopulatePixelFormat(header.ddspf); + + header.dwCaps = DDSCAPS_TEXTURE; + + if (m_texture->HasMipMaps()) + header.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; + + if (m_texture->GetTextureType() == TextureType::T_CUBE) + header.dwCaps |= DDSCAPS_COMPLEX; + + header.dwCaps2 = 0; + + if (m_texture->GetTextureType() == TextureType::T_CUBE) + { + header.dwCaps2 |= DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX | DDSCAPS2_CUBEMAP_POSITIVEY + | DDSCAPS2_CUBEMAP_NEGATIVEY | DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ; + } + + header.dwCaps3 = 0; + header.dwCaps4 = 0; + header.dwReserved2 = 0; + } + + void PopulateDxt10Header(DDS_HEADER_DXT10& header) const + { + header.dxgiFormat = m_texture->GetFormat()->GetDxgiFormat(); + header.miscFlag = 0; + header.miscFlags2 = 0; + + switch (m_texture->GetTextureType()) + { + case TextureType::T_2D: + header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + header.arraySize = 1; + break; + case TextureType::T_CUBE: + header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + header.arraySize = 6; + header.miscFlag |= DDS_RESOURCE_MISC_TEXTURECUBE; + break; + case TextureType::T_3D: + header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D; + header.arraySize = 1; + break; + } + } + + void ConvertTextureIfNecessary() + { + const auto entry = DDS_CONVERSION_TABLE.find(m_texture->GetFormat()->GetId()); + + if (entry != DDS_CONVERSION_TABLE.end()) + { + TextureConverter converter(m_texture, ImageFormat::ALL_FORMATS[static_cast(entry->second)]); + m_converted_texture = converter.Convert(); + m_texture = m_converted_texture.get(); + } + } + + std::ostream& m_stream; + const Texture* m_texture; + std::unique_ptr m_converted_texture; + bool m_use_dx10_extension; + }; +} // namespace + +namespace image { - return DdsWriterInternal::SupportsImageFormat(imageFormat); -} + DdsWriter::~DdsWriter() = default; -std::string DdsWriter::GetFileExtension() -{ - return DdsWriterInternal::GetFileExtension(); -} + bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat) + { + return DdsWriterInternal::SupportsImageFormat(imageFormat); + } -void DdsWriter::DumpImage(std::ostream& stream, const Texture* texture) -{ - DdsWriterInternal internal(stream, texture); - internal.DumpImage(); -} + std::string DdsWriter::GetFileExtension() + { + return DdsWriterInternal::GetFileExtension(); + } + + void DdsWriter::DumpImage(std::ostream& stream, const Texture* texture) + { + DdsWriterInternal internal(stream, texture); + internal.DumpImage(); + } +} // namespace image diff --git a/src/ObjImage/Image/DdsWriter.h b/src/ObjImage/Image/DdsWriter.h index c6acbab4..771d4842 100644 --- a/src/ObjImage/Image/DdsWriter.h +++ b/src/ObjImage/Image/DdsWriter.h @@ -1,12 +1,16 @@ #pragma once -#include "IImageWriter.h" -class DdsWriter final : public IImageWriter +#include "ImageWriter.h" + +namespace image { -public: - ~DdsWriter() override; + class DdsWriter final : public ImageWriter + { + public: + ~DdsWriter() override; - bool SupportsImageFormat(const ImageFormat* imageFormat) override; - std::string GetFileExtension() override; - void DumpImage(std::ostream& stream, const Texture* texture) override; -}; + bool SupportsImageFormat(const ImageFormat* imageFormat) override; + std::string GetFileExtension() override; + void DumpImage(std::ostream& stream, const Texture* texture) override; + }; +} // namespace image diff --git a/src/ObjImage/Image/Dx12TextureLoader.cpp b/src/ObjImage/Image/Dx12TextureLoader.cpp index 4e1fe3c0..85b5d6fc 100644 --- a/src/ObjImage/Image/Dx12TextureLoader.cpp +++ b/src/ObjImage/Image/Dx12TextureLoader.cpp @@ -2,103 +2,106 @@ #include -Dx12TextureLoader::Dx12TextureLoader() - : m_format(oat::DXGI_FORMAT_UNKNOWN), - m_type(TextureType::T_2D), - m_has_mip_maps(false), - m_width(1u), - m_height(1u), - m_depth(1u) +namespace image { -} - -const ImageFormat* Dx12TextureLoader::GetFormatForDx12Format() const -{ - for (const auto* i : ImageFormat::ALL_FORMATS) + Dx12TextureLoader::Dx12TextureLoader() + : m_format(oat::DXGI_FORMAT_UNKNOWN), + m_type(TextureType::T_2D), + m_has_mip_maps(false), + m_width(1u), + m_height(1u), + m_depth(1u) { - if (i->GetDxgiFormat() == m_format) - return i; } - return nullptr; -} - -Dx12TextureLoader& Dx12TextureLoader::Format(const oat::DXGI_FORMAT format) -{ - m_format = format; - return *this; -} - -Dx12TextureLoader& Dx12TextureLoader::Type(const TextureType textureType) -{ - m_type = textureType; - return *this; -} - -Dx12TextureLoader& Dx12TextureLoader::HasMipMaps(const bool hasMipMaps) -{ - m_has_mip_maps = hasMipMaps; - return *this; -} - -Dx12TextureLoader& Dx12TextureLoader::Width(const unsigned width) -{ - m_width = width; - return *this; -} - -Dx12TextureLoader& Dx12TextureLoader::Height(const unsigned height) -{ - m_height = height; - return *this; -} - -Dx12TextureLoader& Dx12TextureLoader::Depth(const unsigned depth) -{ - m_depth = depth; - return *this; -} - -std::unique_ptr Dx12TextureLoader::LoadTexture(const void* data) -{ - const auto* format = GetFormatForDx12Format(); - - if (format == nullptr) - return nullptr; - - std::unique_ptr texture; - switch (m_type) + const ImageFormat* Dx12TextureLoader::GetFormatForDx12Format() const { - case TextureType::T_2D: - texture = std::make_unique(format, m_width, m_height, m_has_mip_maps); - break; - - case TextureType::T_3D: - texture = std::make_unique(format, m_width, m_height, m_depth, m_has_mip_maps); - break; - - case TextureType::T_CUBE: - texture = std::make_unique(format, m_width, m_width, m_has_mip_maps); - break; - - default: - return nullptr; - } - - texture->Allocate(); - const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1; - const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1; - const void* currentDataOffset = data; - - for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++) - { - for (auto currentFace = 0; currentFace < faceCount; currentFace++) + for (const auto* i : ImageFormat::ALL_FORMATS) { - const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel); - memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize); - currentDataOffset = reinterpret_cast(reinterpret_cast(currentDataOffset) + mipSize); + if (i->GetDxgiFormat() == m_format) + return i; } + + return nullptr; } - return texture; -} + Dx12TextureLoader& Dx12TextureLoader::Format(const oat::DXGI_FORMAT format) + { + m_format = format; + return *this; + } + + Dx12TextureLoader& Dx12TextureLoader::Type(const TextureType textureType) + { + m_type = textureType; + return *this; + } + + Dx12TextureLoader& Dx12TextureLoader::HasMipMaps(const bool hasMipMaps) + { + m_has_mip_maps = hasMipMaps; + return *this; + } + + Dx12TextureLoader& Dx12TextureLoader::Width(const unsigned width) + { + m_width = width; + return *this; + } + + Dx12TextureLoader& Dx12TextureLoader::Height(const unsigned height) + { + m_height = height; + return *this; + } + + Dx12TextureLoader& Dx12TextureLoader::Depth(const unsigned depth) + { + m_depth = depth; + return *this; + } + + std::unique_ptr Dx12TextureLoader::LoadTexture(const void* data) + { + const auto* format = GetFormatForDx12Format(); + + if (format == nullptr) + return nullptr; + + std::unique_ptr texture; + switch (m_type) + { + case TextureType::T_2D: + texture = std::make_unique(format, m_width, m_height, m_has_mip_maps); + break; + + case TextureType::T_3D: + texture = std::make_unique(format, m_width, m_height, m_depth, m_has_mip_maps); + break; + + case TextureType::T_CUBE: + texture = std::make_unique(format, m_width, m_width, m_has_mip_maps); + break; + + default: + return nullptr; + } + + texture->Allocate(); + const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1; + const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1; + const void* currentDataOffset = data; + + for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++) + { + for (auto currentFace = 0; currentFace < faceCount; currentFace++) + { + const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel); + memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize); + currentDataOffset = reinterpret_cast(reinterpret_cast(currentDataOffset) + mipSize); + } + } + + return texture; + } +} // namespace image diff --git a/src/ObjImage/Image/Dx12TextureLoader.h b/src/ObjImage/Image/Dx12TextureLoader.h index 128d2b69..c5ad4174 100644 --- a/src/ObjImage/Image/Dx12TextureLoader.h +++ b/src/ObjImage/Image/Dx12TextureLoader.h @@ -6,29 +6,32 @@ #include #include -class Dx12TextureLoader +namespace image { -public: - Dx12TextureLoader(); + class Dx12TextureLoader + { + public: + Dx12TextureLoader(); - Dx12TextureLoader& Format(oat::DXGI_FORMAT format); - Dx12TextureLoader& Type(TextureType textureType); - Dx12TextureLoader& HasMipMaps(bool hasMipMaps); - Dx12TextureLoader& Width(unsigned width); - Dx12TextureLoader& Height(unsigned height); - Dx12TextureLoader& Depth(unsigned depth); + Dx12TextureLoader& Format(oat::DXGI_FORMAT format); + Dx12TextureLoader& Type(TextureType textureType); + Dx12TextureLoader& HasMipMaps(bool hasMipMaps); + Dx12TextureLoader& Width(unsigned width); + Dx12TextureLoader& Height(unsigned height); + Dx12TextureLoader& Depth(unsigned depth); - std::unique_ptr LoadTexture(const void* data); + std::unique_ptr LoadTexture(const void* data); -private: - [[nodiscard]] const ImageFormat* GetFormatForDx12Format() const; + private: + [[nodiscard]] const ImageFormat* GetFormatForDx12Format() const; - static std::unordered_map m_conversion_table; + static std::unordered_map m_conversion_table; - oat::DXGI_FORMAT m_format; - TextureType m_type; - bool m_has_mip_maps; - unsigned m_width; - unsigned m_height; - unsigned m_depth; -}; + oat::DXGI_FORMAT m_format; + TextureType m_type; + bool m_has_mip_maps; + unsigned m_width; + unsigned m_height; + unsigned m_depth; + }; +} // namespace image diff --git a/src/ObjImage/Image/Dx9TextureLoader.cpp b/src/ObjImage/Image/Dx9TextureLoader.cpp index 9d319bd0..a4f0645e 100644 --- a/src/ObjImage/Image/Dx9TextureLoader.cpp +++ b/src/ObjImage/Image/Dx9TextureLoader.cpp @@ -2,103 +2,106 @@ #include -Dx9TextureLoader::Dx9TextureLoader() - : m_format(oat::D3DFMT_UNKNOWN), - m_type(TextureType::T_2D), - m_has_mip_maps(false), - m_width(1u), - m_height(1u), - m_depth(1u) +namespace image { -} - -const ImageFormat* Dx9TextureLoader::GetFormatForDx9Format() const -{ - for (const auto* i : ImageFormat::ALL_FORMATS) + Dx9TextureLoader::Dx9TextureLoader() + : m_format(oat::D3DFMT_UNKNOWN), + m_type(TextureType::T_2D), + m_has_mip_maps(false), + m_width(1u), + m_height(1u), + m_depth(1u) { - if (i->GetD3DFormat() == m_format) - return i; } - return nullptr; -} - -Dx9TextureLoader& Dx9TextureLoader::Format(const oat::D3DFORMAT format) -{ - m_format = format; - return *this; -} - -Dx9TextureLoader& Dx9TextureLoader::Type(const TextureType textureType) -{ - m_type = textureType; - return *this; -} - -Dx9TextureLoader& Dx9TextureLoader::HasMipMaps(const bool hasMipMaps) -{ - m_has_mip_maps = hasMipMaps; - return *this; -} - -Dx9TextureLoader& Dx9TextureLoader::Width(const unsigned width) -{ - m_width = width; - return *this; -} - -Dx9TextureLoader& Dx9TextureLoader::Height(const unsigned height) -{ - m_height = height; - return *this; -} - -Dx9TextureLoader& Dx9TextureLoader::Depth(const unsigned depth) -{ - m_depth = depth; - return *this; -} - -std::unique_ptr Dx9TextureLoader::LoadTexture(const void* data) -{ - const auto* format = GetFormatForDx9Format(); - - if (format == nullptr) - return nullptr; - - std::unique_ptr texture; - switch (m_type) + const ImageFormat* Dx9TextureLoader::GetFormatForDx9Format() const { - case TextureType::T_2D: - texture = std::make_unique(format, m_width, m_height, m_has_mip_maps); - break; - - case TextureType::T_3D: - texture = std::make_unique(format, m_width, m_height, m_depth, m_has_mip_maps); - break; - - case TextureType::T_CUBE: - texture = std::make_unique(format, m_width, m_width, m_has_mip_maps); - break; - - default: - return nullptr; - } - - texture->Allocate(); - const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1; - const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1; - const void* currentDataOffset = data; - - for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++) - { - for (auto currentFace = 0; currentFace < faceCount; currentFace++) + for (const auto* i : ImageFormat::ALL_FORMATS) { - const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel); - memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize); - currentDataOffset = reinterpret_cast(reinterpret_cast(currentDataOffset) + mipSize); + if (i->GetD3DFormat() == m_format) + return i; } + + return nullptr; } - return texture; -} + Dx9TextureLoader& Dx9TextureLoader::Format(const oat::D3DFORMAT format) + { + m_format = format; + return *this; + } + + Dx9TextureLoader& Dx9TextureLoader::Type(const TextureType textureType) + { + m_type = textureType; + return *this; + } + + Dx9TextureLoader& Dx9TextureLoader::HasMipMaps(const bool hasMipMaps) + { + m_has_mip_maps = hasMipMaps; + return *this; + } + + Dx9TextureLoader& Dx9TextureLoader::Width(const unsigned width) + { + m_width = width; + return *this; + } + + Dx9TextureLoader& Dx9TextureLoader::Height(const unsigned height) + { + m_height = height; + return *this; + } + + Dx9TextureLoader& Dx9TextureLoader::Depth(const unsigned depth) + { + m_depth = depth; + return *this; + } + + std::unique_ptr Dx9TextureLoader::LoadTexture(const void* data) + { + const auto* format = GetFormatForDx9Format(); + + if (format == nullptr) + return nullptr; + + std::unique_ptr texture; + switch (m_type) + { + case TextureType::T_2D: + texture = std::make_unique(format, m_width, m_height, m_has_mip_maps); + break; + + case TextureType::T_3D: + texture = std::make_unique(format, m_width, m_height, m_depth, m_has_mip_maps); + break; + + case TextureType::T_CUBE: + texture = std::make_unique(format, m_width, m_width, m_has_mip_maps); + break; + + default: + return nullptr; + } + + texture->Allocate(); + const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1; + const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1; + const void* currentDataOffset = data; + + for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++) + { + for (auto currentFace = 0; currentFace < faceCount; currentFace++) + { + const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel); + memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize); + currentDataOffset = reinterpret_cast(reinterpret_cast(currentDataOffset) + mipSize); + } + } + + return texture; + } +} // namespace image diff --git a/src/ObjImage/Image/Dx9TextureLoader.h b/src/ObjImage/Image/Dx9TextureLoader.h index 212714d4..48ff5e5c 100644 --- a/src/ObjImage/Image/Dx9TextureLoader.h +++ b/src/ObjImage/Image/Dx9TextureLoader.h @@ -5,27 +5,30 @@ #include -class Dx9TextureLoader +namespace image { -public: - Dx9TextureLoader(); + class Dx9TextureLoader + { + public: + Dx9TextureLoader(); - Dx9TextureLoader& Format(oat::D3DFORMAT format); - Dx9TextureLoader& Type(TextureType textureType); - Dx9TextureLoader& HasMipMaps(bool hasMipMaps); - Dx9TextureLoader& Width(unsigned width); - Dx9TextureLoader& Height(unsigned height); - Dx9TextureLoader& Depth(unsigned depth); + Dx9TextureLoader& Format(oat::D3DFORMAT format); + Dx9TextureLoader& Type(TextureType textureType); + Dx9TextureLoader& HasMipMaps(bool hasMipMaps); + Dx9TextureLoader& Width(unsigned width); + Dx9TextureLoader& Height(unsigned height); + Dx9TextureLoader& Depth(unsigned depth); - std::unique_ptr LoadTexture(const void* data); + std::unique_ptr LoadTexture(const void* data); -private: - [[nodiscard]] const ImageFormat* GetFormatForDx9Format() const; + private: + [[nodiscard]] const ImageFormat* GetFormatForDx9Format() const; - oat::D3DFORMAT m_format; - TextureType m_type; - bool m_has_mip_maps; - unsigned m_width; - unsigned m_height; - unsigned m_depth; -}; + oat::D3DFORMAT m_format; + TextureType m_type; + bool m_has_mip_maps; + unsigned m_width; + unsigned m_height; + unsigned m_depth; + }; +} // namespace image diff --git a/src/ObjImage/Image/IImageWriter.h b/src/ObjImage/Image/IImageWriter.h deleted file mode 100644 index ed116416..00000000 --- a/src/ObjImage/Image/IImageWriter.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "Image/Texture.h" - -#include -#include - -class IImageWriter -{ -public: - IImageWriter() = default; - virtual ~IImageWriter() = default; - IImageWriter(const IImageWriter& other) = default; - IImageWriter(IImageWriter&& other) noexcept = default; - IImageWriter& operator=(const IImageWriter& other) = default; - IImageWriter& operator=(IImageWriter&& other) noexcept = default; - - virtual bool SupportsImageFormat(const ImageFormat* imageFormat) = 0; - virtual std::string GetFileExtension() = 0; - virtual void DumpImage(std::ostream& stream, const Texture* texture) = 0; -}; diff --git a/src/ObjImage/Image/ImageFormat.cpp b/src/ObjImage/Image/ImageFormat.cpp index 7581d972..6f2ace41 100644 --- a/src/ObjImage/Image/ImageFormat.cpp +++ b/src/ObjImage/Image/ImageFormat.cpp @@ -1,175 +1,178 @@ #include "ImageFormat.h" -ImageFormat::ImageFormat(const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat) - : m_id(id), - m_d3d_format(d3dFormat), - m_dxgi_format(dxgiFormat) +namespace image { -} + ImageFormat::ImageFormat(const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat) + : m_id(id), + m_d3d_format(d3dFormat), + m_dxgi_format(dxgiFormat) + { + } -ImageFormatId ImageFormat::GetId() const -{ - return m_id; -} + ImageFormatId ImageFormat::GetId() const + { + return m_id; + } -oat::D3DFORMAT ImageFormat::GetD3DFormat() const -{ - return m_d3d_format; -} + oat::D3DFORMAT ImageFormat::GetD3DFormat() const + { + return m_d3d_format; + } -oat::DXGI_FORMAT ImageFormat::GetDxgiFormat() const -{ - return m_dxgi_format; -} + oat::DXGI_FORMAT ImageFormat::GetDxgiFormat() const + { + return m_dxgi_format; + } -ImageFormatUnsigned::ImageFormatUnsigned(const ImageFormatId id, - const oat::D3DFORMAT d3dFormat, - const oat::DXGI_FORMAT dxgiFormat, - const unsigned bitsPerPixel, - const unsigned rOffset, - const unsigned rSize, - const unsigned gOffset, - const unsigned gSize, - const unsigned bOffset, - const unsigned bSize, - const unsigned aOffset, - const unsigned aSize) - : ImageFormat(id, d3dFormat, dxgiFormat), - m_bits_per_pixel(bitsPerPixel), - m_r_offset(rOffset), - m_r_size(rSize), - m_g_offset(gOffset), - m_g_size(gSize), - m_b_offset(bOffset), - m_b_size(bSize), - m_a_offset(aOffset), - m_a_size(aSize) -{ -} + ImageFormatUnsigned::ImageFormatUnsigned(const ImageFormatId id, + const oat::D3DFORMAT d3dFormat, + const oat::DXGI_FORMAT dxgiFormat, + const unsigned bitsPerPixel, + const unsigned rOffset, + const unsigned rSize, + const unsigned gOffset, + const unsigned gSize, + const unsigned bOffset, + const unsigned bSize, + const unsigned aOffset, + const unsigned aSize) + : ImageFormat(id, d3dFormat, dxgiFormat), + m_bits_per_pixel(bitsPerPixel), + m_r_offset(rOffset), + m_r_size(rSize), + m_g_offset(gOffset), + m_g_size(gSize), + m_b_offset(bOffset), + m_b_size(bSize), + m_a_offset(aOffset), + m_a_size(aSize) + { + } -ImageFormatType ImageFormatUnsigned::GetType() const -{ - return ImageFormatType::UNSIGNED; -} + ImageFormatType ImageFormatUnsigned::GetType() const + { + return ImageFormatType::UNSIGNED; + } -size_t ImageFormatUnsigned::GetPitch(const unsigned mipLevel, const unsigned width) const -{ - unsigned mipWidth = width >> mipLevel; - if (mipWidth == 0) - mipWidth = 1; + size_t ImageFormatUnsigned::GetPitch(const unsigned mipLevel, const unsigned width) const + { + unsigned mipWidth = width >> mipLevel; + if (mipWidth == 0) + mipWidth = 1; - return mipWidth * m_bits_per_pixel / 8; -} + return mipWidth * m_bits_per_pixel / 8; + } -size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, const unsigned depth) const -{ - unsigned mipWidth = width >> mipLevel; - unsigned mipHeight = height >> mipLevel; - unsigned mipDepth = depth >> mipLevel; + size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, const unsigned depth) const + { + unsigned mipWidth = width >> mipLevel; + unsigned mipHeight = height >> mipLevel; + unsigned mipDepth = depth >> mipLevel; - if (mipWidth == 0) - mipWidth = 1; - if (mipHeight == 0) - mipHeight = 1; - if (mipDepth == 0) - mipDepth = 1; + if (mipWidth == 0) + mipWidth = 1; + if (mipHeight == 0) + mipHeight = 1; + if (mipDepth == 0) + mipDepth = 1; - return mipWidth * mipHeight * mipDepth * m_bits_per_pixel / 8; -} + return mipWidth * mipHeight * mipDepth * m_bits_per_pixel / 8; + } -ImageFormatBlockCompressed::ImageFormatBlockCompressed( - const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat, const unsigned blockSize, const unsigned bitsPerBlock) - : ImageFormat(id, d3dFormat, dxgiFormat), - m_block_size(blockSize), - m_bits_per_block(bitsPerBlock) -{ -} + ImageFormatBlockCompressed::ImageFormatBlockCompressed( + const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat, const unsigned blockSize, const unsigned bitsPerBlock) + : ImageFormat(id, d3dFormat, dxgiFormat), + m_block_size(blockSize), + m_bits_per_block(bitsPerBlock) + { + } -ImageFormatType ImageFormatBlockCompressed::GetType() const -{ - return ImageFormatType::BLOCK_COMPRESSED; -} + ImageFormatType ImageFormatBlockCompressed::GetType() const + { + return ImageFormatType::BLOCK_COMPRESSED; + } -size_t ImageFormatBlockCompressed::GetPitch(const unsigned mipLevel, const unsigned width) const -{ - unsigned mipWidth = width >> mipLevel; + size_t ImageFormatBlockCompressed::GetPitch(const unsigned mipLevel, const unsigned width) const + { + unsigned mipWidth = width >> mipLevel; - if (mipWidth == 0) - mipWidth = 1; + if (mipWidth == 0) + mipWidth = 1; - const unsigned blockCount = (mipWidth + m_block_size - 1) / m_block_size; + const unsigned blockCount = (mipWidth + m_block_size - 1) / m_block_size; - return blockCount * m_bits_per_block / 8; -} + return blockCount * m_bits_per_block / 8; + } -size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, const unsigned depth) const -{ - unsigned mipWidth = width >> mipLevel; - unsigned mipHeight = height >> mipLevel; - unsigned mipDepth = depth >> mipLevel; + size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, const unsigned depth) const + { + unsigned mipWidth = width >> mipLevel; + unsigned mipHeight = height >> mipLevel; + unsigned mipDepth = depth >> mipLevel; - if (mipWidth == 0) - mipWidth = 1; - if (mipHeight == 0) - mipHeight = 1; - if (mipDepth == 0) - mipDepth = 1; + if (mipWidth == 0) + mipWidth = 1; + if (mipHeight == 0) + mipHeight = 1; + if (mipDepth == 0) + mipDepth = 1; - const unsigned blockCount = ((mipWidth + m_block_size - 1) / m_block_size) * ((mipHeight + m_block_size - 1) / m_block_size) * mipDepth; + const unsigned blockCount = ((mipWidth + m_block_size - 1) / m_block_size) * ((mipHeight + m_block_size - 1) / m_block_size) * mipDepth; - return blockCount * m_bits_per_block / 8; -} + return blockCount * m_bits_per_block / 8; + } -bool ImageFormatUnsigned::HasR() const -{ - return m_r_size > 0; -} + bool ImageFormatUnsigned::HasR() const + { + return m_r_size > 0; + } -bool ImageFormatUnsigned::HasG() const -{ - return m_g_size > 0; -} + bool ImageFormatUnsigned::HasG() const + { + return m_g_size > 0; + } -bool ImageFormatUnsigned::HasB() const -{ - return m_b_size > 0; -} + bool ImageFormatUnsigned::HasB() const + { + return m_b_size > 0; + } -bool ImageFormatUnsigned::HasA() const -{ - return m_a_size > 0; -} + bool ImageFormatUnsigned::HasA() const + { + return m_a_size > 0; + } -const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8(ImageFormatId::R8_G8_B8, oat::D3DFMT_R8G8B8, oat::DXGI_FORMAT_UNKNOWN, 24, 0, 8, 8, 8, 16, 8, 0, 0); -const ImageFormatUnsigned - ImageFormat::FORMAT_B8_G8_R8_X8(ImageFormatId::B8_G8_R8_X8, oat::D3DFMT_X8R8G8B8, oat::DXGI_FORMAT_B8G8R8X8_UNORM, 32, 16, 8, 8, 8, 0, 8, 0, 0); -const ImageFormatUnsigned - ImageFormat::FORMAT_R8_G8_B8_A8(ImageFormatId::R8_G8_B8_A8, oat::D3DFMT_A8B8G8R8, oat::DXGI_FORMAT_R8G8B8A8_UNORM, 32, 0, 8, 8, 8, 16, 8, 24, 8); -const ImageFormatUnsigned - ImageFormat::FORMAT_B8_G8_R8_A8(ImageFormatId::B8_G8_R8_A8, oat::D3DFMT_A8R8G8B8, oat::DXGI_FORMAT_B8G8R8A8_UNORM, 32, 16, 8, 8, 8, 0, 8, 24, 8); -const ImageFormatUnsigned ImageFormat::FORMAT_A8(ImageFormatId::A8, oat::D3DFMT_A8, oat::DXGI_FORMAT_A8_UNORM, 8, 0, 0, 0, 0, 0, 0, 0, 8); -const ImageFormatUnsigned ImageFormat::FORMAT_R16_G16_B16_A16_FLOAT( - ImageFormatId::R16_G16_B16_A16_FLOAT, oat::D3DFMT_A16B16G16R16F, oat::DXGI_FORMAT_R16G16B16A16_FLOAT, 128, 0, 0, 0, 0, 0, 0, 0, 8); -const ImageFormatUnsigned ImageFormat::FORMAT_R8(ImageFormatId::R8, oat::D3DFMT_L8, oat::DXGI_FORMAT_R8_UNORM, 8, 0, 8, 0, 0, 0, 0, 0, 0); -const ImageFormatUnsigned ImageFormat::FORMAT_R8_A8(ImageFormatId::R8_A8, oat::D3DFMT_A8L8, oat::DXGI_FORMAT_UNKNOWN, 16, 0, 8, 0, 0, 0, 0, 8, 8); -const ImageFormatBlockCompressed ImageFormat::FORMAT_BC1(ImageFormatId::BC1, oat::D3DFMT_DXT1, oat::DXGI_FORMAT_BC1_UNORM, 4, 64); -const ImageFormatBlockCompressed ImageFormat::FORMAT_BC2(ImageFormatId::BC2, oat::D3DFMT_DXT3, oat::DXGI_FORMAT_BC2_UNORM, 4, 128); -const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(ImageFormatId::BC3, oat::D3DFMT_DXT5, oat::DXGI_FORMAT_BC3_UNORM, 4, 128); -const ImageFormatBlockCompressed ImageFormat::FORMAT_BC4(ImageFormatId::BC4, oat::D3DFMT_UNKNOWN, oat::DXGI_FORMAT_BC4_UNORM, 4, 64); -const ImageFormatBlockCompressed ImageFormat::FORMAT_BC5(ImageFormatId::BC5, oat::D3DFMT_UNKNOWN, oat::DXGI_FORMAT_BC5_UNORM, 4, 128); + const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8(ImageFormatId::R8_G8_B8, oat::D3DFMT_R8G8B8, oat::DXGI_FORMAT_UNKNOWN, 24, 0, 8, 8, 8, 16, 8, 0, 0); + const ImageFormatUnsigned + ImageFormat::FORMAT_B8_G8_R8_X8(ImageFormatId::B8_G8_R8_X8, oat::D3DFMT_X8R8G8B8, oat::DXGI_FORMAT_B8G8R8X8_UNORM, 32, 16, 8, 8, 8, 0, 8, 0, 0); + const ImageFormatUnsigned + ImageFormat::FORMAT_R8_G8_B8_A8(ImageFormatId::R8_G8_B8_A8, oat::D3DFMT_A8B8G8R8, oat::DXGI_FORMAT_R8G8B8A8_UNORM, 32, 0, 8, 8, 8, 16, 8, 24, 8); + const ImageFormatUnsigned + ImageFormat::FORMAT_B8_G8_R8_A8(ImageFormatId::B8_G8_R8_A8, oat::D3DFMT_A8R8G8B8, oat::DXGI_FORMAT_B8G8R8A8_UNORM, 32, 16, 8, 8, 8, 0, 8, 24, 8); + const ImageFormatUnsigned ImageFormat::FORMAT_A8(ImageFormatId::A8, oat::D3DFMT_A8, oat::DXGI_FORMAT_A8_UNORM, 8, 0, 0, 0, 0, 0, 0, 0, 8); + const ImageFormatUnsigned ImageFormat::FORMAT_R16_G16_B16_A16_FLOAT( + ImageFormatId::R16_G16_B16_A16_FLOAT, oat::D3DFMT_A16B16G16R16F, oat::DXGI_FORMAT_R16G16B16A16_FLOAT, 128, 0, 0, 0, 0, 0, 0, 0, 8); + const ImageFormatUnsigned ImageFormat::FORMAT_R8(ImageFormatId::R8, oat::D3DFMT_L8, oat::DXGI_FORMAT_R8_UNORM, 8, 0, 8, 0, 0, 0, 0, 0, 0); + const ImageFormatUnsigned ImageFormat::FORMAT_R8_A8(ImageFormatId::R8_A8, oat::D3DFMT_A8L8, oat::DXGI_FORMAT_UNKNOWN, 16, 0, 8, 0, 0, 0, 0, 8, 8); + const ImageFormatBlockCompressed ImageFormat::FORMAT_BC1(ImageFormatId::BC1, oat::D3DFMT_DXT1, oat::DXGI_FORMAT_BC1_UNORM, 4, 64); + const ImageFormatBlockCompressed ImageFormat::FORMAT_BC2(ImageFormatId::BC2, oat::D3DFMT_DXT3, oat::DXGI_FORMAT_BC2_UNORM, 4, 128); + const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(ImageFormatId::BC3, oat::D3DFMT_DXT5, oat::DXGI_FORMAT_BC3_UNORM, 4, 128); + const ImageFormatBlockCompressed ImageFormat::FORMAT_BC4(ImageFormatId::BC4, oat::D3DFMT_UNKNOWN, oat::DXGI_FORMAT_BC4_UNORM, 4, 64); + const ImageFormatBlockCompressed ImageFormat::FORMAT_BC5(ImageFormatId::BC5, oat::D3DFMT_UNKNOWN, oat::DXGI_FORMAT_BC5_UNORM, 4, 128); -const ImageFormat* const ImageFormat::ALL_FORMATS[static_cast(ImageFormatId::MAX)]{ - &FORMAT_R8_G8_B8, - &FORMAT_B8_G8_R8_X8, - &FORMAT_R8_G8_B8_A8, - &FORMAT_B8_G8_R8_A8, - &FORMAT_A8, - &FORMAT_R16_G16_B16_A16_FLOAT, - &FORMAT_R8, - &FORMAT_R8_A8, - &FORMAT_BC1, - &FORMAT_BC2, - &FORMAT_BC3, - &FORMAT_BC4, - &FORMAT_BC5, -}; + const ImageFormat* const ImageFormat::ALL_FORMATS[static_cast(ImageFormatId::MAX)]{ + &FORMAT_R8_G8_B8, + &FORMAT_B8_G8_R8_X8, + &FORMAT_R8_G8_B8_A8, + &FORMAT_B8_G8_R8_A8, + &FORMAT_A8, + &FORMAT_R16_G16_B16_A16_FLOAT, + &FORMAT_R8, + &FORMAT_R8_A8, + &FORMAT_BC1, + &FORMAT_BC2, + &FORMAT_BC3, + &FORMAT_BC4, + &FORMAT_BC5, + }; +} // namespace image diff --git a/src/ObjImage/Image/ImageFormat.h b/src/ObjImage/Image/ImageFormat.h index b87f6ac5..57de0b5b 100644 --- a/src/ObjImage/Image/ImageFormat.h +++ b/src/ObjImage/Image/ImageFormat.h @@ -6,117 +6,120 @@ #include #include -enum class ImageFormatId +namespace image { - UNKNOWN = -1, - R8_G8_B8, - B8_G8_R8_X8, - R8_G8_B8_A8, - B8_G8_R8_A8, - A8, - R16_G16_B16_A16_FLOAT, - R8, - R8_A8, - BC1, - BC2, - BC3, - BC4, - BC5, + enum class ImageFormatId + { + UNKNOWN = -1, + R8_G8_B8, + B8_G8_R8_X8, + R8_G8_B8_A8, + B8_G8_R8_A8, + A8, + R16_G16_B16_A16_FLOAT, + R8, + R8_A8, + BC1, + BC2, + BC3, + BC4, + BC5, - MAX -}; + MAX + }; -enum class ImageFormatType -{ - UNKNOWN, - UNSIGNED, - BLOCK_COMPRESSED -}; + enum class ImageFormatType + { + UNKNOWN, + UNSIGNED, + BLOCK_COMPRESSED + }; -class ImageFormatUnsigned; -class ImageFormatBlockCompressed; + class ImageFormatUnsigned; + class ImageFormatBlockCompressed; -class ImageFormat -{ - ImageFormatId m_id; - oat::D3DFORMAT m_d3d_format; - oat::DXGI_FORMAT m_dxgi_format; + class ImageFormat + { + ImageFormatId m_id; + oat::D3DFORMAT m_d3d_format; + oat::DXGI_FORMAT m_dxgi_format; -protected: - ImageFormat(ImageFormatId id, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat); + protected: + ImageFormat(ImageFormatId id, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat); -public: - virtual ~ImageFormat() = default; + public: + virtual ~ImageFormat() = default; - [[nodiscard]] ImageFormatId GetId() const; - [[nodiscard]] oat::D3DFORMAT GetD3DFormat() const; - [[nodiscard]] oat::DXGI_FORMAT GetDxgiFormat() const; + [[nodiscard]] ImageFormatId GetId() const; + [[nodiscard]] oat::D3DFORMAT GetD3DFormat() const; + [[nodiscard]] oat::DXGI_FORMAT GetDxgiFormat() const; - [[nodiscard]] virtual ImageFormatType GetType() const = 0; - [[nodiscard]] virtual size_t GetPitch(unsigned mipLevel, unsigned width) const = 0; - [[nodiscard]] virtual size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const = 0; + [[nodiscard]] virtual ImageFormatType GetType() const = 0; + [[nodiscard]] virtual size_t GetPitch(unsigned mipLevel, unsigned width) const = 0; + [[nodiscard]] virtual size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const = 0; - static const ImageFormatUnsigned FORMAT_R8_G8_B8; - static const ImageFormatUnsigned FORMAT_B8_G8_R8_X8; - static const ImageFormatUnsigned FORMAT_R8_G8_B8_A8; - static const ImageFormatUnsigned FORMAT_B8_G8_R8_A8; - static const ImageFormatUnsigned FORMAT_A8; - static const ImageFormatUnsigned FORMAT_R16_G16_B16_A16_FLOAT; // TODO: Float not unsigned - static const ImageFormatUnsigned FORMAT_R8; - static const ImageFormatUnsigned FORMAT_R8_A8; - static const ImageFormatBlockCompressed FORMAT_BC1; - static const ImageFormatBlockCompressed FORMAT_BC2; - static const ImageFormatBlockCompressed FORMAT_BC3; - static const ImageFormatBlockCompressed FORMAT_BC4; - static const ImageFormatBlockCompressed FORMAT_BC5; - static const ImageFormat* const ALL_FORMATS[static_cast(ImageFormatId::MAX)]; -}; + static const ImageFormatUnsigned FORMAT_R8_G8_B8; + static const ImageFormatUnsigned FORMAT_B8_G8_R8_X8; + static const ImageFormatUnsigned FORMAT_R8_G8_B8_A8; + static const ImageFormatUnsigned FORMAT_B8_G8_R8_A8; + static const ImageFormatUnsigned FORMAT_A8; + static const ImageFormatUnsigned FORMAT_R16_G16_B16_A16_FLOAT; // TODO: Float not unsigned + static const ImageFormatUnsigned FORMAT_R8; + static const ImageFormatUnsigned FORMAT_R8_A8; + static const ImageFormatBlockCompressed FORMAT_BC1; + static const ImageFormatBlockCompressed FORMAT_BC2; + static const ImageFormatBlockCompressed FORMAT_BC3; + static const ImageFormatBlockCompressed FORMAT_BC4; + static const ImageFormatBlockCompressed FORMAT_BC5; + static const ImageFormat* const ALL_FORMATS[static_cast(ImageFormatId::MAX)]; + }; -class ImageFormatUnsigned final : public ImageFormat -{ -public: - unsigned m_bits_per_pixel; - unsigned m_r_offset; - unsigned m_r_size; - unsigned m_g_offset; - unsigned m_g_size; - unsigned m_b_offset; - unsigned m_b_size; - unsigned m_a_offset; - unsigned m_a_size; + class ImageFormatUnsigned final : public ImageFormat + { + public: + unsigned m_bits_per_pixel; + unsigned m_r_offset; + unsigned m_r_size; + unsigned m_g_offset; + unsigned m_g_size; + unsigned m_b_offset; + unsigned m_b_size; + unsigned m_a_offset; + unsigned m_a_size; - ImageFormatUnsigned(ImageFormatId id, - oat::D3DFORMAT d3dFormat, - oat::DXGI_FORMAT dxgiFormat, - unsigned bitsPerPixel, - unsigned rOffset, - unsigned rSize, - unsigned gOffset, - unsigned gSize, - unsigned bOffset, - unsigned bSize, - unsigned aOffset, - unsigned aSize); + ImageFormatUnsigned(ImageFormatId id, + oat::D3DFORMAT d3dFormat, + oat::DXGI_FORMAT dxgiFormat, + unsigned bitsPerPixel, + unsigned rOffset, + unsigned rSize, + unsigned gOffset, + unsigned gSize, + unsigned bOffset, + unsigned bSize, + unsigned aOffset, + unsigned aSize); - [[nodiscard]] ImageFormatType GetType() const override; - [[nodiscard]] size_t GetPitch(unsigned mipLevel, unsigned width) const override; - [[nodiscard]] size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override; + [[nodiscard]] ImageFormatType GetType() const override; + [[nodiscard]] size_t GetPitch(unsigned mipLevel, unsigned width) const override; + [[nodiscard]] size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override; - [[nodiscard]] bool HasR() const; - [[nodiscard]] bool HasG() const; - [[nodiscard]] bool HasB() const; - [[nodiscard]] bool HasA() const; -}; + [[nodiscard]] bool HasR() const; + [[nodiscard]] bool HasG() const; + [[nodiscard]] bool HasB() const; + [[nodiscard]] bool HasA() const; + }; -class ImageFormatBlockCompressed final : public ImageFormat -{ -public: - unsigned m_block_size; - unsigned m_bits_per_block; + class ImageFormatBlockCompressed final : public ImageFormat + { + public: + unsigned m_block_size; + unsigned m_bits_per_block; - ImageFormatBlockCompressed(ImageFormatId id, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat, unsigned blockSize, unsigned bitsPerBlock); + ImageFormatBlockCompressed(ImageFormatId id, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat, unsigned blockSize, unsigned bitsPerBlock); - [[nodiscard]] ImageFormatType GetType() const override; - [[nodiscard]] size_t GetPitch(unsigned mipLevel, unsigned width) const override; - [[nodiscard]] size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override; -}; + [[nodiscard]] ImageFormatType GetType() const override; + [[nodiscard]] size_t GetPitch(unsigned mipLevel, unsigned width) const override; + [[nodiscard]] size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override; + }; +} // namespace image diff --git a/src/ObjImage/Image/ImageWriter.h b/src/ObjImage/Image/ImageWriter.h new file mode 100644 index 00000000..4ab90250 --- /dev/null +++ b/src/ObjImage/Image/ImageWriter.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Image/Texture.h" + +#include +#include + +namespace image +{ + class ImageWriter + { + public: + ImageWriter() = default; + virtual ~ImageWriter() = default; + ImageWriter(const ImageWriter& other) = default; + ImageWriter(ImageWriter&& other) noexcept = default; + ImageWriter& operator=(const ImageWriter& other) = default; + ImageWriter& operator=(ImageWriter&& other) noexcept = default; + + virtual bool SupportsImageFormat(const ImageFormat* imageFormat) = 0; + virtual std::string GetFileExtension() = 0; + virtual void DumpImage(std::ostream& stream, const Texture* texture) = 0; + }; +} // namespace image diff --git a/src/ObjImage/Image/IwiLoader.cpp b/src/ObjImage/Image/IwiLoader.cpp index 4f0e5df5..1893904a 100644 --- a/src/ObjImage/Image/IwiLoader.cpp +++ b/src/ObjImage/Image/IwiLoader.cpp @@ -8,7 +8,9 @@ #include #include -namespace iwi +using namespace image; + +namespace { const ImageFormat* GetFormat6(int8_t format) { @@ -74,7 +76,7 @@ namespace iwi texture->Allocate(); - auto currentFileSize = sizeof(iwi6::IwiHeader) + sizeof(IwiVersion); + auto currentFileSize = sizeof(iwi6::IwiHeader) + sizeof(IwiVersionHeader); const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) @@ -188,7 +190,7 @@ namespace iwi texture->Allocate(); - auto currentFileSize = sizeof(iwi8::IwiHeader) + sizeof(IwiVersion); + auto currentFileSize = sizeof(iwi8::IwiHeader) + sizeof(IwiVersionHeader); const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) @@ -283,7 +285,7 @@ namespace iwi texture->Allocate(); - auto currentFileSize = sizeof(iwi13::IwiHeader) + sizeof(IwiVersion); + auto currentFileSize = sizeof(iwi13::IwiHeader) + sizeof(IwiVersionHeader); const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) @@ -380,7 +382,7 @@ namespace iwi texture->Allocate(); - auto currentFileSize = sizeof(iwi27::IwiHeader) + sizeof(IwiVersion); + auto currentFileSize = sizeof(iwi27::IwiHeader) + sizeof(IwiVersionHeader); const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) @@ -405,22 +407,25 @@ namespace iwi return texture; } +} // namespace +namespace image +{ std::unique_ptr LoadIwi(std::istream& stream) { - IwiVersion iwiVersion{}; + IwiVersionHeader iwiVersionHeader{}; - stream.read(reinterpret_cast(&iwiVersion), sizeof(iwiVersion)); - if (stream.gcount() != sizeof(iwiVersion)) + stream.read(reinterpret_cast(&iwiVersionHeader), sizeof(iwiVersionHeader)); + if (stream.gcount() != sizeof(iwiVersionHeader)) return nullptr; - if (iwiVersion.tag[0] != 'I' || iwiVersion.tag[1] != 'W' || iwiVersion.tag[2] != 'i') + if (iwiVersionHeader.tag[0] != 'I' || iwiVersionHeader.tag[1] != 'W' || iwiVersionHeader.tag[2] != 'i') { con::error("Invalid IWI magic"); return nullptr; } - switch (iwiVersion.version) + switch (iwiVersionHeader.version) { case 6: return LoadIwi6(stream); @@ -438,7 +443,7 @@ namespace iwi break; } - con::error("Unknown IWI version {}", iwiVersion.version); + con::error("Unknown IWI version {}", iwiVersionHeader.version); return nullptr; } -} // namespace iwi +} // namespace image diff --git a/src/ObjImage/Image/IwiLoader.h b/src/ObjImage/Image/IwiLoader.h index a1f65c65..29aaeb61 100644 --- a/src/ObjImage/Image/IwiLoader.h +++ b/src/ObjImage/Image/IwiLoader.h @@ -5,7 +5,7 @@ #include #include -namespace iwi +namespace image { std::unique_ptr LoadIwi(std::istream& stream); -}; // namespace iwi +}; // namespace image diff --git a/src/ObjImage/Image/IwiTypes.h b/src/ObjImage/Image/IwiTypes.h index 545861ca..37eb04e9 100644 --- a/src/ObjImage/Image/IwiTypes.h +++ b/src/ObjImage/Image/IwiTypes.h @@ -2,234 +2,245 @@ #include -struct IwiVersion +namespace image { - char tag[3]; - char version; -}; - -// IW3 -namespace iwi6 -{ - struct IwiHeader + enum class IwiVersion : std::uint8_t { - int8_t format; - int8_t flags; - uint16_t dimensions[3]; - uint32_t fileSizeForPicmip[4]; + // IW3 + IWI_6 = 6, + // IW4, IW5 + IWI_8 = 8, + // T5 + IWI_13 = 13, + // T6 + IWI_27 = 27 }; - enum class IwiFormat + struct IwiVersionHeader { - IMG_FORMAT_INVALID = 0x0, - IMG_FORMAT_BITMAP_RGBA = 0x1, - IMG_FORMAT_BITMAP_RGB = 0x2, - IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, - IMG_FORMAT_BITMAP_LUMINANCE = 0x4, - IMG_FORMAT_BITMAP_ALPHA = 0x5, - IMG_FORMAT_WAVELET_RGBA = 0x6, - IMG_FORMAT_WAVELET_RGB = 0x7, - IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, - IMG_FORMAT_WAVELET_LUMINANCE = 0x9, - IMG_FORMAT_WAVELET_ALPHA = 0xA, - IMG_FORMAT_DXT1 = 0xB, - IMG_FORMAT_DXT3 = 0xC, - IMG_FORMAT_DXT5 = 0xD, - IMG_FORMAT_DXN = 0xE, - - IMG_FORMAT_COUNT + char tag[3]; + char version; }; - enum IwiFlags + namespace iwi6 { - IMG_FLAG_NOPICMIP = 1 << 0, - IMG_FLAG_NOMIPMAPS = 1 << 1, - IMG_FLAG_CUBEMAP = 1 << 2, - IMG_FLAG_VOLMAP = 1 << 3, - IMG_FLAG_STREAMING = 1 << 4, - IMG_FLAG_LEGACY_NORMALS = 1 << 5, - IMG_FLAG_CLAMP_U = 1 << 6, - IMG_FLAG_CLAMP_V = 1 << 7, - IMG_FLAG_DYNAMIC = 1 << 16, - IMG_FLAG_RENDER_TARGET = 1 << 17, - IMG_FLAG_SYSTEMMEM = 1 << 18 - }; -} // namespace iwi6 + struct IwiHeader + { + int8_t format; + int8_t flags; + uint16_t dimensions[3]; + uint32_t fileSizeForPicmip[4]; + }; -// IW4 -namespace iwi8 -{ - struct IwiHeader + enum class IwiFormat + { + IMG_FORMAT_INVALID = 0x0, + IMG_FORMAT_BITMAP_RGBA = 0x1, + IMG_FORMAT_BITMAP_RGB = 0x2, + IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, + IMG_FORMAT_BITMAP_LUMINANCE = 0x4, + IMG_FORMAT_BITMAP_ALPHA = 0x5, + IMG_FORMAT_WAVELET_RGBA = 0x6, + IMG_FORMAT_WAVELET_RGB = 0x7, + IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, + IMG_FORMAT_WAVELET_LUMINANCE = 0x9, + IMG_FORMAT_WAVELET_ALPHA = 0xA, + IMG_FORMAT_DXT1 = 0xB, + IMG_FORMAT_DXT3 = 0xC, + IMG_FORMAT_DXT5 = 0xD, + IMG_FORMAT_DXN = 0xE, + + IMG_FORMAT_COUNT + }; + + enum IwiFlags + { + IMG_FLAG_NOPICMIP = 1 << 0, + IMG_FLAG_NOMIPMAPS = 1 << 1, + IMG_FLAG_CUBEMAP = 1 << 2, + IMG_FLAG_VOLMAP = 1 << 3, + IMG_FLAG_STREAMING = 1 << 4, + IMG_FLAG_LEGACY_NORMALS = 1 << 5, + IMG_FLAG_CLAMP_U = 1 << 6, + IMG_FLAG_CLAMP_V = 1 << 7, + IMG_FLAG_DYNAMIC = 1 << 16, + IMG_FLAG_RENDER_TARGET = 1 << 17, + IMG_FLAG_SYSTEMMEM = 1 << 18 + }; + } // namespace iwi6 + + namespace iwi8 { - uint32_t flags; - int8_t format; - int8_t unused; - uint16_t dimensions[3]; - uint32_t fileSizeForPicmip[4]; - }; + struct IwiHeader + { + uint32_t flags; + int8_t format; + int8_t unused; + uint16_t dimensions[3]; + uint32_t fileSizeForPicmip[4]; + }; - enum class IwiFormat + enum class IwiFormat + { + IMG_FORMAT_INVALID = 0x0, + IMG_FORMAT_BITMAP_RGBA = 0x1, + IMG_FORMAT_BITMAP_RGB = 0x2, + IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, + IMG_FORMAT_BITMAP_LUMINANCE = 0x4, + IMG_FORMAT_BITMAP_ALPHA = 0x5, + IMG_FORMAT_WAVELET_RGBA = 0x6, + IMG_FORMAT_WAVELET_RGB = 0x7, + IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, + IMG_FORMAT_WAVELET_LUMINANCE = 0x9, + IMG_FORMAT_WAVELET_ALPHA = 0xA, + IMG_FORMAT_DXT1 = 0xB, + IMG_FORMAT_DXT3 = 0xC, + IMG_FORMAT_DXT5 = 0xD, + IMG_FORMAT_DXN = 0xE, + IMG_FORMAT_DXT3A_AS_LUMINANCE = 0xF, + IMG_FORMAT_DXT5A_AS_LUMINANCE = 0x10, + IMG_FORMAT_DXT3A_AS_ALPHA = 0x11, + IMG_FORMAT_DXT5A_AS_ALPHA = 0x12, + IMG_FORMAT_DXT1_AS_LUMINANCE_ALPHA = 0x13, + IMG_FORMAT_DXN_AS_LUMINANCE_ALPHA = 0x14, + IMG_FORMAT_DXT1_AS_LUMINANCE = 0x15, + IMG_FORMAT_DXT1_AS_ALPHA = 0x16, + + IMG_FORMAT_COUNT + }; + + enum IwiFlags + { + IMG_FLAG_NOPICMIP = 1 << 0, + IMG_FLAG_NOMIPMAPS = 1 << 1, + IMG_FLAG_STREAMING = 1 << 2, + IMG_FLAG_LEGACY_NORMALS = 1 << 3, + IMG_FLAG_CLAMP_U = 1 << 4, + IMG_FLAG_CLAMP_V = 1 << 5, + IMG_FLAG_ALPHA_WEIGHTED_COLORS = 1 << 6, + IMG_FLAG_DXTC_APPROX_WEIGHTS = 1 << 7, + IMG_FLAG_GAMMA_NONE = 0, + IMG_FLAG_GAMMA_SRGB = 1 << 8, + IMG_FLAG_GAMMA_PWL = 1 << 9, + IMG_FLAG_GAMMA_2 = IMG_FLAG_GAMMA_SRGB | IMG_FLAG_GAMMA_PWL, + IMG_FLAG_MAPTYPE_2D = 0, + IMG_FLAG_MAPTYPE_CUBE = 1 << 16, + IMG_FLAG_MAPTYPE_3D = 1 << 17, + IMG_FLAG_MAPTYPE_1D = IMG_FLAG_MAPTYPE_CUBE | IMG_FLAG_MAPTYPE_3D, + IMG_FLAG_MAPTYPE_MASK = IMG_FLAG_MAPTYPE_2D | IMG_FLAG_MAPTYPE_CUBE | IMG_FLAG_MAPTYPE_3D | IMG_FLAG_MAPTYPE_1D, + IMG_FLAG_NORMALMAP = 1 << 18, + IMG_FLAG_INTENSITY_TO_ALPHA = 1 << 19, + IMG_FLAG_DYNAMIC = 1 << 24, + IMG_FLAG_RENDER_TARGET = 1 << 25, + IMG_FLAG_SYSTEMMEM = 1 << 26 + }; + } // namespace iwi8 + + namespace iwi13 { - IMG_FORMAT_INVALID = 0x0, - IMG_FORMAT_BITMAP_RGBA = 0x1, - IMG_FORMAT_BITMAP_RGB = 0x2, - IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, - IMG_FORMAT_BITMAP_LUMINANCE = 0x4, - IMG_FORMAT_BITMAP_ALPHA = 0x5, - IMG_FORMAT_WAVELET_RGBA = 0x6, - IMG_FORMAT_WAVELET_RGB = 0x7, - IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, - IMG_FORMAT_WAVELET_LUMINANCE = 0x9, - IMG_FORMAT_WAVELET_ALPHA = 0xA, - IMG_FORMAT_DXT1 = 0xB, - IMG_FORMAT_DXT3 = 0xC, - IMG_FORMAT_DXT5 = 0xD, - IMG_FORMAT_DXN = 0xE, - IMG_FORMAT_DXT3A_AS_LUMINANCE = 0xF, - IMG_FORMAT_DXT5A_AS_LUMINANCE = 0x10, - IMG_FORMAT_DXT3A_AS_ALPHA = 0x11, - IMG_FORMAT_DXT5A_AS_ALPHA = 0x12, - IMG_FORMAT_DXT1_AS_LUMINANCE_ALPHA = 0x13, - IMG_FORMAT_DXN_AS_LUMINANCE_ALPHA = 0x14, - IMG_FORMAT_DXT1_AS_LUMINANCE = 0x15, - IMG_FORMAT_DXT1_AS_ALPHA = 0x16, + struct IwiHeader + { + int8_t format; + int8_t flags; + uint16_t dimensions[3]; + float gamma; + uint32_t fileSizeForPicmip[8]; + }; - IMG_FORMAT_COUNT - }; + enum class IwiFormat + { + IMG_FORMAT_INVALID = 0x0, + IMG_FORMAT_BITMAP_RGBA = 0x1, + IMG_FORMAT_BITMAP_RGB = 0x2, + IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, + IMG_FORMAT_BITMAP_LUMINANCE = 0x4, + IMG_FORMAT_BITMAP_ALPHA = 0x5, + IMG_FORMAT_WAVELET_RGBA = 0x6, + IMG_FORMAT_WAVELET_RGB = 0x7, + IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, + IMG_FORMAT_WAVELET_LUMINANCE = 0x9, + IMG_FORMAT_WAVELET_ALPHA = 0xA, + IMG_FORMAT_DXT1 = 0xB, + IMG_FORMAT_DXT3 = 0xC, + IMG_FORMAT_DXT5 = 0xD, + IMG_FORMAT_DXN = 0xE, + IMG_FORMAT_BITMAP_RGB565 = 0xF, + IMG_FORMAT_BITMAP_RGB5A3 = 0x10, + IMG_FORMAT_BITMAP_C8 = 0x11, + IMG_FORMAT_BITMAP_RGBA8 = 0x12, + IMG_FORMAT_A16B16G16R16F = 0x13, + IMG_FORMAT_COUNT = 0x14, + }; - enum IwiFlags + enum IwiFlags + { + IMG_FLAG_NOPICMIP = 1 << 0, + IMG_FLAG_NOMIPMAPS = 1 << 1, + IMG_FLAG_CUBEMAP = 1 << 2, + IMG_FLAG_VOLMAP = 1 << 3, + IMG_FLAG_STREAMING = 1 << 4, + IMG_FLAG_LEGACY_NORMALS = 1 << 5, + IMG_FLAG_CLAMP_U = 1 << 6, + IMG_FLAG_CLAMP_V = 1 << 7, + IMG_FLAG_FORCE_SYSTEM = 1 << 8, + IMG_FLAG_DYNAMIC = 1 << 16, + IMG_FLAG_RENDER_TARGET = 1 << 17, + IMG_FLAG_SYSTEMMEM = 1 << 18, + }; + + } // namespace iwi13 + + namespace iwi27 { - IMG_FLAG_NOPICMIP = 1 << 0, - IMG_FLAG_NOMIPMAPS = 1 << 1, - IMG_FLAG_STREAMING = 1 << 2, - IMG_FLAG_LEGACY_NORMALS = 1 << 3, - IMG_FLAG_CLAMP_U = 1 << 4, - IMG_FLAG_CLAMP_V = 1 << 5, - IMG_FLAG_ALPHA_WEIGHTED_COLORS = 1 << 6, - IMG_FLAG_DXTC_APPROX_WEIGHTS = 1 << 7, - IMG_FLAG_GAMMA_NONE = 0, - IMG_FLAG_GAMMA_SRGB = 1 << 8, - IMG_FLAG_GAMMA_PWL = 1 << 9, - IMG_FLAG_GAMMA_2 = IMG_FLAG_GAMMA_SRGB | IMG_FLAG_GAMMA_PWL, - IMG_FLAG_MAPTYPE_2D = 0, - IMG_FLAG_MAPTYPE_CUBE = 1 << 16, - IMG_FLAG_MAPTYPE_3D = 1 << 17, - IMG_FLAG_MAPTYPE_1D = IMG_FLAG_MAPTYPE_CUBE | IMG_FLAG_MAPTYPE_3D, - IMG_FLAG_MAPTYPE_MASK = IMG_FLAG_MAPTYPE_2D | IMG_FLAG_MAPTYPE_CUBE | IMG_FLAG_MAPTYPE_3D | IMG_FLAG_MAPTYPE_1D, - IMG_FLAG_NORMALMAP = 1 << 18, - IMG_FLAG_INTENSITY_TO_ALPHA = 1 << 19, - IMG_FLAG_DYNAMIC = 1 << 24, - IMG_FLAG_RENDER_TARGET = 1 << 25, - IMG_FLAG_SYSTEMMEM = 1 << 26 - }; -} // namespace iwi8 + struct IwiHeader + { + int8_t format; + int8_t flags; + uint16_t dimensions[3]; + float gamma; + int8_t maxGlossForMip[16]; + uint32_t fileSizeForPicmip[8]; + }; -// T5 -namespace iwi13 -{ - struct IwiHeader - { - int8_t format; - int8_t flags; - uint16_t dimensions[3]; - float gamma; - uint32_t fileSizeForPicmip[8]; - }; + enum class IwiFormat + { + IMG_FORMAT_INVALID = 0x0, + IMG_FORMAT_BITMAP_RGBA = 0x1, + IMG_FORMAT_BITMAP_RGB = 0x2, + IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, + IMG_FORMAT_BITMAP_LUMINANCE = 0x4, + IMG_FORMAT_BITMAP_ALPHA = 0x5, + IMG_FORMAT_WAVELET_RGBA = 0x6, + IMG_FORMAT_WAVELET_RGB = 0x7, + IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, + IMG_FORMAT_WAVELET_LUMINANCE = 0x9, + IMG_FORMAT_WAVELET_ALPHA = 0xA, + IMG_FORMAT_DXT1 = 0xB, + IMG_FORMAT_DXT3 = 0xC, + IMG_FORMAT_DXT5 = 0xD, + IMG_FORMAT_DXN = 0xE, + IMG_FORMAT_BITMAP_RGB565 = 0xF, + IMG_FORMAT_BITMAP_RGB5A3 = 0x10, + IMG_FORMAT_BITMAP_C8 = 0x11, + IMG_FORMAT_BITMAP_RGBA8 = 0x12, + IMG_FORMAT_A16B16G16R16F = 0x13, + IMG_FORMAT_COUNT, + }; - enum class IwiFormat - { - IMG_FORMAT_INVALID = 0x0, - IMG_FORMAT_BITMAP_RGBA = 0x1, - IMG_FORMAT_BITMAP_RGB = 0x2, - IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, - IMG_FORMAT_BITMAP_LUMINANCE = 0x4, - IMG_FORMAT_BITMAP_ALPHA = 0x5, - IMG_FORMAT_WAVELET_RGBA = 0x6, - IMG_FORMAT_WAVELET_RGB = 0x7, - IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, - IMG_FORMAT_WAVELET_LUMINANCE = 0x9, - IMG_FORMAT_WAVELET_ALPHA = 0xA, - IMG_FORMAT_DXT1 = 0xB, - IMG_FORMAT_DXT3 = 0xC, - IMG_FORMAT_DXT5 = 0xD, - IMG_FORMAT_DXN = 0xE, - IMG_FORMAT_BITMAP_RGB565 = 0xF, - IMG_FORMAT_BITMAP_RGB5A3 = 0x10, - IMG_FORMAT_BITMAP_C8 = 0x11, - IMG_FORMAT_BITMAP_RGBA8 = 0x12, - IMG_FORMAT_A16B16G16R16F = 0x13, - IMG_FORMAT_COUNT = 0x14, - }; + enum IwiFlags + { + IMG_FLAG_NOPICMIP = 1 << 0, + IMG_FLAG_NOMIPMAPS = 1 << 1, + IMG_FLAG_CUBEMAP = 1 << 2, + IMG_FLAG_VOLMAP = 1 << 3, + IMG_FLAG_STREAMING = 1 << 4, + IMG_FLAG_CLAMP_U = 1 << 6, + IMG_FLAG_CLAMP_V = 1 << 7, + IMG_FLAG_FORCE_SYSTEM = 1 << 8, + IMG_FLAG_DYNAMIC = 1 << 16, + IMG_FLAG_RENDER_TARGET = 1 << 17, + IMG_FLAG_MULTISAMPLE = 1 << 18, + }; - enum IwiFlags - { - IMG_FLAG_NOPICMIP = 1 << 0, - IMG_FLAG_NOMIPMAPS = 1 << 1, - IMG_FLAG_CUBEMAP = 1 << 2, - IMG_FLAG_VOLMAP = 1 << 3, - IMG_FLAG_STREAMING = 1 << 4, - IMG_FLAG_LEGACY_NORMALS = 1 << 5, - IMG_FLAG_CLAMP_U = 1 << 6, - IMG_FLAG_CLAMP_V = 1 << 7, - IMG_FLAG_FORCE_SYSTEM = 1 << 8, - IMG_FLAG_DYNAMIC = 1 << 16, - IMG_FLAG_RENDER_TARGET = 1 << 17, - IMG_FLAG_SYSTEMMEM = 1 << 18, - }; - -} // namespace iwi13 - -// T6 -namespace iwi27 -{ - struct IwiHeader - { - int8_t format; - int8_t flags; - uint16_t dimensions[3]; - float gamma; - int8_t maxGlossForMip[16]; - uint32_t fileSizeForPicmip[8]; - }; - - enum class IwiFormat - { - IMG_FORMAT_INVALID = 0x0, - IMG_FORMAT_BITMAP_RGBA = 0x1, - IMG_FORMAT_BITMAP_RGB = 0x2, - IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3, - IMG_FORMAT_BITMAP_LUMINANCE = 0x4, - IMG_FORMAT_BITMAP_ALPHA = 0x5, - IMG_FORMAT_WAVELET_RGBA = 0x6, - IMG_FORMAT_WAVELET_RGB = 0x7, - IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8, - IMG_FORMAT_WAVELET_LUMINANCE = 0x9, - IMG_FORMAT_WAVELET_ALPHA = 0xA, - IMG_FORMAT_DXT1 = 0xB, - IMG_FORMAT_DXT3 = 0xC, - IMG_FORMAT_DXT5 = 0xD, - IMG_FORMAT_DXN = 0xE, - IMG_FORMAT_BITMAP_RGB565 = 0xF, - IMG_FORMAT_BITMAP_RGB5A3 = 0x10, - IMG_FORMAT_BITMAP_C8 = 0x11, - IMG_FORMAT_BITMAP_RGBA8 = 0x12, - IMG_FORMAT_A16B16G16R16F = 0x13, - IMG_FORMAT_COUNT, - }; - - enum IwiFlags - { - IMG_FLAG_NOPICMIP = 1 << 0, - IMG_FLAG_NOMIPMAPS = 1 << 1, - IMG_FLAG_CUBEMAP = 1 << 2, - IMG_FLAG_VOLMAP = 1 << 3, - IMG_FLAG_STREAMING = 1 << 4, - IMG_FLAG_CLAMP_U = 1 << 6, - IMG_FLAG_CLAMP_V = 1 << 7, - IMG_FLAG_FORCE_SYSTEM = 1 << 8, - IMG_FLAG_DYNAMIC = 1 << 16, - IMG_FLAG_RENDER_TARGET = 1 << 17, - IMG_FLAG_MULTISAMPLE = 1 << 18, - }; - -} // namespace iwi27 + } // namespace iwi27 +} // namespace image diff --git a/src/ObjImage/Image/IwiWriter13.cpp b/src/ObjImage/Image/IwiWriter13.cpp index 0ffc7953..05282d0b 100644 --- a/src/ObjImage/Image/IwiWriter13.cpp +++ b/src/ObjImage/Image/IwiWriter13.cpp @@ -3,7 +3,7 @@ #include #include -using namespace iwi13; +using namespace image::iwi13; IwiWriter::IwiWriter() = default; @@ -54,13 +54,13 @@ std::string IwiWriter::GetFileExtension() void IwiWriter::WriteVersion(std::ostream& stream) { - IwiVersion version{}; + IwiVersionHeader version{}; version.tag[0] = 'I'; version.tag[1] = 'W'; version.tag[2] = 'i'; version.version = 13; - stream.write(reinterpret_cast(&version), sizeof(IwiVersion)); + stream.write(reinterpret_cast(&version), sizeof(IwiVersionHeader)); } void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture) @@ -101,7 +101,7 @@ void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture) if (!texture->HasMipMaps()) header.flags |= IMG_FLAG_NOMIPMAPS; - auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader); + auto currentFileSize = sizeof(IwiVersionHeader) + sizeof(IwiHeader); const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1; for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) diff --git a/src/ObjImage/Image/IwiWriter13.h b/src/ObjImage/Image/IwiWriter13.h index 4b8109b6..155393b6 100644 --- a/src/ObjImage/Image/IwiWriter13.h +++ b/src/ObjImage/Image/IwiWriter13.h @@ -1,11 +1,11 @@ #pragma once -#include "IImageWriter.h" #include "Image/IwiTypes.h" +#include "ImageWriter.h" -namespace iwi13 +namespace image::iwi13 { - class IwiWriter final : public IImageWriter + class IwiWriter final : public ImageWriter { static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); @@ -27,4 +27,4 @@ namespace iwi13 std::string GetFileExtension() override; void DumpImage(std::ostream& stream, const Texture* texture) override; }; -} // namespace iwi13 +} // namespace image::iwi13 diff --git a/src/ObjImage/Image/IwiWriter27.cpp b/src/ObjImage/Image/IwiWriter27.cpp index bc31b97c..6f9a868e 100644 --- a/src/ObjImage/Image/IwiWriter27.cpp +++ b/src/ObjImage/Image/IwiWriter27.cpp @@ -3,7 +3,7 @@ #include #include -using namespace iwi27; +using namespace image::iwi27; IwiWriter::IwiWriter() = default; @@ -54,13 +54,13 @@ std::string IwiWriter::GetFileExtension() void IwiWriter::WriteVersion(std::ostream& stream) { - IwiVersion version{}; + IwiVersionHeader version{}; version.tag[0] = 'I'; version.tag[1] = 'W'; version.tag[2] = 'i'; version.version = 27; - stream.write(reinterpret_cast(&version), sizeof(IwiVersion)); + stream.write(reinterpret_cast(&version), sizeof(IwiVersionHeader)); } void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture) @@ -104,7 +104,7 @@ void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture) for (auto& i : header.maxGlossForMip) i = 0; - auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader); + auto currentFileSize = sizeof(IwiVersionHeader) + sizeof(IwiHeader); const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1; for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) diff --git a/src/ObjImage/Image/IwiWriter27.h b/src/ObjImage/Image/IwiWriter27.h index 4f47dd1a..71facafc 100644 --- a/src/ObjImage/Image/IwiWriter27.h +++ b/src/ObjImage/Image/IwiWriter27.h @@ -1,11 +1,11 @@ #pragma once -#include "IImageWriter.h" #include "Image/IwiTypes.h" +#include "ImageWriter.h" -namespace iwi27 +namespace image::iwi27 { - class IwiWriter final : public IImageWriter + class IwiWriter final : public ImageWriter { static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); @@ -27,4 +27,4 @@ namespace iwi27 std::string GetFileExtension() override; void DumpImage(std::ostream& stream, const Texture* texture) override; }; -} // namespace iwi27 +} // namespace image::iwi27 diff --git a/src/ObjImage/Image/IwiWriter6.cpp b/src/ObjImage/Image/IwiWriter6.cpp index 39f66f61..40d8a315 100644 --- a/src/ObjImage/Image/IwiWriter6.cpp +++ b/src/ObjImage/Image/IwiWriter6.cpp @@ -2,7 +2,7 @@ #include -using namespace iwi6; +using namespace image::iwi6; IwiWriter::IwiWriter() = default; @@ -40,13 +40,13 @@ IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat) void IwiWriter::WriteVersion(std::ostream& stream) { - IwiVersion version{}; + IwiVersionHeader version{}; version.tag[0] = 'I'; version.tag[1] = 'W'; version.tag[2] = 'i'; version.version = 6; - stream.write(reinterpret_cast(&version), sizeof(IwiVersion)); + stream.write(reinterpret_cast(&version), sizeof(IwiVersionHeader)); } void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture) @@ -96,7 +96,7 @@ void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture) if (!texture->HasMipMaps()) header.flags |= IMG_FLAG_NOMIPMAPS; - auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader); + auto currentFileSize = sizeof(IwiVersionHeader) + sizeof(IwiHeader); const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1; for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) diff --git a/src/ObjImage/Image/IwiWriter6.h b/src/ObjImage/Image/IwiWriter6.h index 79f414dd..bc178eae 100644 --- a/src/ObjImage/Image/IwiWriter6.h +++ b/src/ObjImage/Image/IwiWriter6.h @@ -1,11 +1,11 @@ #pragma once -#include "IImageWriter.h" #include "Image/IwiTypes.h" +#include "ImageWriter.h" -namespace iwi6 +namespace image::iwi6 { - class IwiWriter final : public IImageWriter + class IwiWriter final : public ImageWriter { static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); @@ -27,4 +27,4 @@ namespace iwi6 std::string GetFileExtension() override; void DumpImage(std::ostream& stream, const Texture* texture) override; }; -} // namespace iwi6 +} // namespace image::iwi6 diff --git a/src/ObjImage/Image/IwiWriter8.cpp b/src/ObjImage/Image/IwiWriter8.cpp index ea28f193..4b25a488 100644 --- a/src/ObjImage/Image/IwiWriter8.cpp +++ b/src/ObjImage/Image/IwiWriter8.cpp @@ -2,7 +2,7 @@ #include -using namespace iwi8; +using namespace image::iwi8; IwiWriter::IwiWriter() = default; @@ -40,13 +40,13 @@ IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat) void IwiWriter::WriteVersion(std::ostream& stream) { - IwiVersion version{}; + IwiVersionHeader version{}; version.tag[0] = 'I'; version.tag[1] = 'W'; version.tag[2] = 'i'; version.version = 8; - stream.write(reinterpret_cast(&version), sizeof(IwiVersion)); + stream.write(reinterpret_cast(&version), sizeof(IwiVersionHeader)); } void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture) @@ -96,7 +96,7 @@ void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture) if (!texture->HasMipMaps()) header.flags |= IMG_FLAG_NOMIPMAPS; - auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader); + auto currentFileSize = sizeof(IwiVersionHeader) + sizeof(IwiHeader); const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1; for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) diff --git a/src/ObjImage/Image/IwiWriter8.h b/src/ObjImage/Image/IwiWriter8.h index 01892670..ed13f7bc 100644 --- a/src/ObjImage/Image/IwiWriter8.h +++ b/src/ObjImage/Image/IwiWriter8.h @@ -1,11 +1,11 @@ #pragma once -#include "IImageWriter.h" #include "Image/IwiTypes.h" +#include "ImageWriter.h" -namespace iwi8 +namespace image::iwi8 { - class IwiWriter final : public IImageWriter + class IwiWriter final : public ImageWriter { static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); @@ -27,4 +27,4 @@ namespace iwi8 std::string GetFileExtension() override; void DumpImage(std::ostream& stream, const Texture* texture) override; }; -} // namespace iwi8 +} // namespace image::iwi8 diff --git a/src/ObjImage/Image/Texture.cpp b/src/ObjImage/Image/Texture.cpp index c9e76372..2b82fa9b 100644 --- a/src/ObjImage/Image/Texture.cpp +++ b/src/ObjImage/Image/Texture.cpp @@ -4,440 +4,443 @@ #include #include -// ============================================== -// ================= Texture ==================== -// ============================================== -Texture::Texture(const ImageFormat* format, const bool mipMaps) +namespace image { - m_format = format; - m_has_mip_maps = mipMaps; - m_data = nullptr; -} - -Texture::Texture(Texture&& other) noexcept -{ - m_format = other.m_format; - m_has_mip_maps = other.m_has_mip_maps; - m_data = other.m_data; - - other.m_data = nullptr; -} - -Texture& Texture::operator=(Texture&& other) noexcept -{ - m_format = other.m_format; - m_has_mip_maps = other.m_has_mip_maps; - m_data = other.m_data; - - other.m_data = nullptr; - - return *this; -} - -Texture::~Texture() -{ - delete[] m_data; - m_data = nullptr; -} - -const ImageFormat* Texture::GetFormat() const -{ - return m_format; -} - -void Texture::Allocate() -{ - size_t storageRequirement = 0; - const int mipLevelCount = m_has_mip_maps ? GetMipMapCount() : 1; - - for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) + // ============================================== + // ================= Texture ==================== + // ============================================== + Texture::Texture(const ImageFormat* format, const bool mipMaps) { - storageRequirement += GetSizeOfMipLevel(currentMipLevel) * GetFaceCount(); + m_format = format; + m_has_mip_maps = mipMaps; + m_data = nullptr; } - if (storageRequirement > 0) + Texture::Texture(Texture&& other) noexcept { - m_data = new uint8_t[storageRequirement]; - memset(m_data, 0, storageRequirement); + m_format = other.m_format; + m_has_mip_maps = other.m_has_mip_maps; + m_data = other.m_data; + + other.m_data = nullptr; } -} -bool Texture::Empty() const -{ - return m_data == nullptr; -} + Texture& Texture::operator=(Texture&& other) noexcept + { + m_format = other.m_format; + m_has_mip_maps = other.m_has_mip_maps; + m_data = other.m_data; -bool Texture::HasMipMaps() const -{ - return m_has_mip_maps; -} + other.m_data = nullptr; -uint8_t* Texture::GetBufferForMipLevel(const int mipLevel) -{ - return GetBufferForMipLevel(mipLevel, 0); -} - -const uint8_t* Texture::GetBufferForMipLevel(const int mipLevel) const -{ - return GetBufferForMipLevel(mipLevel, 0); -} - -// ============================================== -// ================ Texture2D =================== -// ============================================== -Texture2D::Texture2D(const ImageFormat* format, const unsigned width, const unsigned height) - : Texture2D(format, width, height, false) -{ -} - -Texture2D::Texture2D(const ImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps) - : Texture(format, mipMaps) -{ - m_width = width; - m_height = height; -} - -Texture2D::Texture2D(Texture2D&& other) noexcept - : Texture(std::move(other)), - m_width(other.m_width), - m_height(other.m_height) -{ -} - -Texture2D::~Texture2D() = default; - -Texture2D& Texture2D::operator=(Texture2D&& other) noexcept -{ - if (this == &other) return *this; - - Texture::operator=(std::move(other)); - m_width = other.m_width; - m_height = other.m_height; - - return *this; -} - -TextureType Texture2D::GetTextureType() const -{ - return TextureType::T_2D; -} - -unsigned Texture2D::GetWidth() const -{ - return m_width; -} - -unsigned Texture2D::GetHeight() const -{ - return m_height; -} - -unsigned Texture2D::GetDepth() const -{ - return 1; -} - -int Texture2D::GetFaceCount() const -{ - return 1; -} - -size_t Texture2D::GetSizeOfMipLevel(const int mipLevel) const -{ - return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, 1); -} - -int Texture2D::GetMipMapCount() const -{ - unsigned maxDimension = std::max(m_width, m_height); - - int mipMapCount = 0; - - while (maxDimension != 0) - { - maxDimension >>= 1; - mipMapCount++; } - return mipMapCount; -} - -uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face) -{ - assert(mipLevel >= 0); - assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); - assert(face == 0); - assert(m_data); - - if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) - return nullptr; - - if (face != 0) - return nullptr; - - if (!m_data) - return nullptr; - - size_t bufferOffset = 0; - for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + Texture::~Texture() { - bufferOffset += GetSizeOfMipLevel(previousMipLevel); + delete[] m_data; + m_data = nullptr; } - return &m_data[bufferOffset]; -} - -const uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face) const -{ - assert(mipLevel >= 0); - assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); - assert(face == 0); - assert(m_data); - - if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) - return nullptr; - - if (face != 0) - return nullptr; - - if (!m_data) - return nullptr; - - size_t bufferOffset = 0; - for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + const ImageFormat* Texture::GetFormat() const { - bufferOffset += GetSizeOfMipLevel(previousMipLevel); + return m_format; } - return &m_data[bufferOffset]; -} + void Texture::Allocate() + { + size_t storageRequirement = 0; + const int mipLevelCount = m_has_mip_maps ? GetMipMapCount() : 1; -// ============================================== -// =============== TextureCube ================== -// ============================================== -const int TextureCube::FACE_COUNT = 6; + for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) + { + storageRequirement += GetSizeOfMipLevel(currentMipLevel) * GetFaceCount(); + } -TextureCube::TextureCube(const ImageFormat* format, const unsigned width, const unsigned height) - : Texture2D(format, width, height) -{ -} + if (storageRequirement > 0) + { + m_data = new uint8_t[storageRequirement]; + memset(m_data, 0, storageRequirement); + } + } -TextureCube::TextureCube(const ImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps) - : Texture2D(format, width, height, mipMaps) -{ -} + bool Texture::Empty() const + { + return m_data == nullptr; + } -TextureCube::TextureCube(TextureCube&& other) noexcept - : Texture2D(std::move(other)) -{ -} + bool Texture::HasMipMaps() const + { + return m_has_mip_maps; + } -TextureCube::~TextureCube() = default; + uint8_t* Texture::GetBufferForMipLevel(const int mipLevel) + { + return GetBufferForMipLevel(mipLevel, 0); + } + + const uint8_t* Texture::GetBufferForMipLevel(const int mipLevel) const + { + return GetBufferForMipLevel(mipLevel, 0); + } + + // ============================================== + // ================ Texture2D =================== + // ============================================== + Texture2D::Texture2D(const ImageFormat* format, const unsigned width, const unsigned height) + : Texture2D(format, width, height, false) + { + } + + Texture2D::Texture2D(const ImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps) + : Texture(format, mipMaps) + { + m_width = width; + m_height = height; + } + + Texture2D::Texture2D(Texture2D&& other) noexcept + : Texture(std::move(other)), + m_width(other.m_width), + m_height(other.m_height) + { + } + + Texture2D::~Texture2D() = default; + + Texture2D& Texture2D::operator=(Texture2D&& other) noexcept + { + if (this == &other) + return *this; + + Texture::operator=(std::move(other)); + m_width = other.m_width; + m_height = other.m_height; -TextureCube& TextureCube::operator=(TextureCube&& other) noexcept -{ - if (this == &other) return *this; - - Texture2D::operator=(std::move(other)); - - return *this; -} - -TextureType TextureCube::GetTextureType() const -{ - return TextureType::T_CUBE; -} - -int TextureCube::GetFaceCount() const -{ - return FACE_COUNT; -} - -uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face) -{ - assert(mipLevel >= 0); - assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); - assert(face >= 0); - assert(face < FACE_COUNT); - assert(m_data); - - if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) - return nullptr; - - if (face < 0 || face >= FACE_COUNT) - return nullptr; - - if (!m_data) - return nullptr; - - size_t bufferOffset = 0; - for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) - { - bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT; } - return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face]; -} - -const uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face) const -{ - assert(mipLevel >= 0); - assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); - assert(face >= 0); - assert(face < FACE_COUNT); - assert(m_data); - - if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) - return nullptr; - - if (face < 0 || face >= FACE_COUNT) - return nullptr; - - if (!m_data) - return nullptr; - - size_t bufferOffset = 0; - for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + TextureType Texture2D::GetTextureType() const { - bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT; + return TextureType::T_2D; } - return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face]; -} + unsigned Texture2D::GetWidth() const + { + return m_width; + } -// ============================================== -// ================ Texture3D =================== -// ============================================== + unsigned Texture2D::GetHeight() const + { + return m_height; + } -Texture3D::Texture3D(const ImageFormat* format, const unsigned width, const unsigned height, const unsigned depth) - : Texture3D(format, width, height, depth, false) -{ -} + unsigned Texture2D::GetDepth() const + { + return 1; + } -Texture3D::Texture3D(const ImageFormat* format, const unsigned width, const unsigned height, const unsigned depth, const bool mipMaps) - : Texture(format, mipMaps) -{ - m_width = width; - m_height = height; - m_depth = depth; -} + int Texture2D::GetFaceCount() const + { + return 1; + } -Texture3D::Texture3D(Texture3D&& other) noexcept - : Texture(std::move(other)), - m_width(other.m_width), - m_height(other.m_height), - m_depth(other.m_depth) -{ -} + size_t Texture2D::GetSizeOfMipLevel(const int mipLevel) const + { + return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, 1); + } -Texture3D::~Texture3D() = default; + int Texture2D::GetMipMapCount() const + { + unsigned maxDimension = std::max(m_width, m_height); + + int mipMapCount = 0; + + while (maxDimension != 0) + { + maxDimension >>= 1; + mipMapCount++; + } + + return mipMapCount; + } + + uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face) + { + assert(mipLevel >= 0); + assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); + assert(face == 0); + assert(m_data); + + if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) + return nullptr; + + if (face != 0) + return nullptr; + + if (!m_data) + return nullptr; + + size_t bufferOffset = 0; + for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + { + bufferOffset += GetSizeOfMipLevel(previousMipLevel); + } + + return &m_data[bufferOffset]; + } + + const uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face) const + { + assert(mipLevel >= 0); + assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); + assert(face == 0); + assert(m_data); + + if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) + return nullptr; + + if (face != 0) + return nullptr; + + if (!m_data) + return nullptr; + + size_t bufferOffset = 0; + for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + { + bufferOffset += GetSizeOfMipLevel(previousMipLevel); + } + + return &m_data[bufferOffset]; + } + + // ============================================== + // =============== TextureCube ================== + // ============================================== + const int TextureCube::FACE_COUNT = 6; + + TextureCube::TextureCube(const ImageFormat* format, const unsigned width, const unsigned height) + : Texture2D(format, width, height) + { + } + + TextureCube::TextureCube(const ImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps) + : Texture2D(format, width, height, mipMaps) + { + } + + TextureCube::TextureCube(TextureCube&& other) noexcept + : Texture2D(std::move(other)) + { + } + + TextureCube::~TextureCube() = default; + + TextureCube& TextureCube::operator=(TextureCube&& other) noexcept + { + if (this == &other) + return *this; + + Texture2D::operator=(std::move(other)); -Texture3D& Texture3D::operator=(Texture3D&& other) noexcept -{ - if (this == &other) return *this; - - Texture::operator=(std::move(other)); - m_width = other.m_width; - m_height = other.m_height; - m_depth = other.m_depth; - - return *this; -} - -TextureType Texture3D::GetTextureType() const -{ - return TextureType::T_3D; -} - -unsigned Texture3D::GetWidth() const -{ - return m_width; -} - -unsigned Texture3D::GetHeight() const -{ - return m_height; -} - -unsigned Texture3D::GetDepth() const -{ - return m_depth; -} - -int Texture3D::GetFaceCount() const -{ - return 1; -} - -size_t Texture3D::GetSizeOfMipLevel(const int mipLevel) const -{ - return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, m_depth); -} - -int Texture3D::GetMipMapCount() const -{ - unsigned maxDimension = std::max(std::max(m_width, m_height), m_depth); - - int mipMapCount = 0; - - while (maxDimension != 0) - { - maxDimension >>= 1; - mipMapCount++; } - return mipMapCount; -} - -uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face) -{ - assert(mipLevel >= 0); - assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); - assert(face == 0); - assert(m_data); - - if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) - return nullptr; - - if (face != 0) - return nullptr; - - if (!m_data) - return nullptr; - - size_t bufferOffset = 0; - for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + TextureType TextureCube::GetTextureType() const { - bufferOffset += GetSizeOfMipLevel(previousMipLevel); + return TextureType::T_CUBE; } - return &m_data[bufferOffset]; -} - -const uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face) const -{ - assert(mipLevel >= 0); - assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); - assert(face == 0); - assert(m_data); - - if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) - return nullptr; - - if (face != 0) - return nullptr; - - if (!m_data) - return nullptr; - - size_t bufferOffset = 0; - for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + int TextureCube::GetFaceCount() const { - bufferOffset += GetSizeOfMipLevel(previousMipLevel); + return FACE_COUNT; } - return &m_data[bufferOffset]; -} + uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face) + { + assert(mipLevel >= 0); + assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); + assert(face >= 0); + assert(face < FACE_COUNT); + assert(m_data); + + if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) + return nullptr; + + if (face < 0 || face >= FACE_COUNT) + return nullptr; + + if (!m_data) + return nullptr; + + size_t bufferOffset = 0; + for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + { + bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT; + } + + return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face]; + } + + const uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face) const + { + assert(mipLevel >= 0); + assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); + assert(face >= 0); + assert(face < FACE_COUNT); + assert(m_data); + + if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) + return nullptr; + + if (face < 0 || face >= FACE_COUNT) + return nullptr; + + if (!m_data) + return nullptr; + + size_t bufferOffset = 0; + for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + { + bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT; + } + + return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face]; + } + + // ============================================== + // ================ Texture3D =================== + // ============================================== + + Texture3D::Texture3D(const ImageFormat* format, const unsigned width, const unsigned height, const unsigned depth) + : Texture3D(format, width, height, depth, false) + { + } + + Texture3D::Texture3D(const ImageFormat* format, const unsigned width, const unsigned height, const unsigned depth, const bool mipMaps) + : Texture(format, mipMaps) + { + m_width = width; + m_height = height; + m_depth = depth; + } + + Texture3D::Texture3D(Texture3D&& other) noexcept + : Texture(std::move(other)), + m_width(other.m_width), + m_height(other.m_height), + m_depth(other.m_depth) + { + } + + Texture3D::~Texture3D() = default; + + Texture3D& Texture3D::operator=(Texture3D&& other) noexcept + { + if (this == &other) + return *this; + + Texture::operator=(std::move(other)); + m_width = other.m_width; + m_height = other.m_height; + m_depth = other.m_depth; + + return *this; + } + + TextureType Texture3D::GetTextureType() const + { + return TextureType::T_3D; + } + + unsigned Texture3D::GetWidth() const + { + return m_width; + } + + unsigned Texture3D::GetHeight() const + { + return m_height; + } + + unsigned Texture3D::GetDepth() const + { + return m_depth; + } + + int Texture3D::GetFaceCount() const + { + return 1; + } + + size_t Texture3D::GetSizeOfMipLevel(const int mipLevel) const + { + return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, m_depth); + } + + int Texture3D::GetMipMapCount() const + { + unsigned maxDimension = std::max(std::max(m_width, m_height), m_depth); + + int mipMapCount = 0; + + while (maxDimension != 0) + { + maxDimension >>= 1; + mipMapCount++; + } + + return mipMapCount; + } + + uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face) + { + assert(mipLevel >= 0); + assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); + assert(face == 0); + assert(m_data); + + if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) + return nullptr; + + if (face != 0) + return nullptr; + + if (!m_data) + return nullptr; + + size_t bufferOffset = 0; + for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + { + bufferOffset += GetSizeOfMipLevel(previousMipLevel); + } + + return &m_data[bufferOffset]; + } + + const uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face) const + { + assert(mipLevel >= 0); + assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1)); + assert(face == 0); + assert(m_data); + + if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1)) + return nullptr; + + if (face != 0) + return nullptr; + + if (!m_data) + return nullptr; + + size_t bufferOffset = 0; + for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++) + { + bufferOffset += GetSizeOfMipLevel(previousMipLevel); + } + + return &m_data[bufferOffset]; + } +} // namespace image diff --git a/src/ObjImage/Image/Texture.h b/src/ObjImage/Image/Texture.h index 6f518551..3ce0b9f6 100644 --- a/src/ObjImage/Image/Texture.h +++ b/src/ObjImage/Image/Texture.h @@ -3,130 +3,133 @@ #include -enum class TextureType : std::uint8_t +namespace image { - T_2D, - T_CUBE, - T_3D -}; + enum class TextureType : std::uint8_t + { + T_2D, + T_CUBE, + T_3D + }; -class Texture -{ -protected: - const ImageFormat* m_format; - bool m_has_mip_maps; - uint8_t* m_data; + class Texture + { + protected: + const ImageFormat* m_format; + bool m_has_mip_maps; + uint8_t* m_data; - Texture(const ImageFormat* format, bool mipMaps); - Texture(Texture&& other) noexcept; + Texture(const ImageFormat* format, bool mipMaps); + Texture(Texture&& other) noexcept; - Texture& operator=(Texture&& other) noexcept; + Texture& operator=(Texture&& other) noexcept; -public: - Texture(const Texture& other) = delete; - virtual ~Texture(); + public: + Texture(const Texture& other) = delete; + virtual ~Texture(); - Texture& operator=(const Texture& other) = delete; + Texture& operator=(const Texture& other) = delete; - [[nodiscard]] virtual TextureType GetTextureType() const = 0; - [[nodiscard]] const ImageFormat* GetFormat() const; + [[nodiscard]] virtual TextureType GetTextureType() const = 0; + [[nodiscard]] const ImageFormat* GetFormat() const; - [[nodiscard]] virtual unsigned GetWidth() const = 0; - [[nodiscard]] virtual unsigned GetHeight() const = 0; - [[nodiscard]] virtual unsigned GetDepth() const = 0; - [[nodiscard]] virtual int GetFaceCount() const = 0; + [[nodiscard]] virtual unsigned GetWidth() const = 0; + [[nodiscard]] virtual unsigned GetHeight() const = 0; + [[nodiscard]] virtual unsigned GetDepth() const = 0; + [[nodiscard]] virtual int GetFaceCount() const = 0; - void Allocate(); - [[nodiscard]] bool Empty() const; + void Allocate(); + [[nodiscard]] bool Empty() const; - [[nodiscard]] virtual size_t GetSizeOfMipLevel(int mipLevel) const = 0; - [[nodiscard]] virtual uint8_t* GetBufferForMipLevel(int mipLevel, int face) = 0; - [[nodiscard]] virtual const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const = 0; - [[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel); - [[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel) const; + [[nodiscard]] virtual size_t GetSizeOfMipLevel(int mipLevel) const = 0; + [[nodiscard]] virtual uint8_t* GetBufferForMipLevel(int mipLevel, int face) = 0; + [[nodiscard]] virtual const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const = 0; + [[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel); + [[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel) const; - [[nodiscard]] bool HasMipMaps() const; - [[nodiscard]] virtual int GetMipMapCount() const = 0; -}; + [[nodiscard]] bool HasMipMaps() const; + [[nodiscard]] virtual int GetMipMapCount() const = 0; + }; -class Texture2D : public Texture -{ -protected: - unsigned m_width; - unsigned m_height; + class Texture2D : public Texture + { + protected: + unsigned m_width; + unsigned m_height; -public: - Texture2D(const ImageFormat* format, unsigned width, unsigned height); - Texture2D(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps); - Texture2D(const Texture2D& other) = delete; - Texture2D(Texture2D&& other) noexcept; - ~Texture2D() override; + public: + Texture2D(const ImageFormat* format, unsigned width, unsigned height); + Texture2D(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps); + Texture2D(const Texture2D& other) = delete; + Texture2D(Texture2D&& other) noexcept; + ~Texture2D() override; - Texture2D& operator=(const Texture2D& other) = delete; - Texture2D& operator=(Texture2D&& other) noexcept; + Texture2D& operator=(const Texture2D& other) = delete; + Texture2D& operator=(Texture2D&& other) noexcept; - [[nodiscard]] TextureType GetTextureType() const override; + [[nodiscard]] TextureType GetTextureType() const override; - [[nodiscard]] unsigned GetWidth() const override; - [[nodiscard]] unsigned GetHeight() const override; - [[nodiscard]] unsigned GetDepth() const override; - [[nodiscard]] int GetFaceCount() const override; + [[nodiscard]] unsigned GetWidth() const override; + [[nodiscard]] unsigned GetHeight() const override; + [[nodiscard]] unsigned GetDepth() const override; + [[nodiscard]] int GetFaceCount() const override; - [[nodiscard]] size_t GetSizeOfMipLevel(int mipLevel) const override; - [[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; - [[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override; + [[nodiscard]] size_t GetSizeOfMipLevel(int mipLevel) const override; + [[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; + [[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override; - [[nodiscard]] int GetMipMapCount() const override; -}; + [[nodiscard]] int GetMipMapCount() const override; + }; -class TextureCube final : public Texture2D -{ - static const int FACE_COUNT; + class TextureCube final : public Texture2D + { + static const int FACE_COUNT; -public: - TextureCube(const ImageFormat* format, unsigned width, unsigned height); - TextureCube(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps); - TextureCube(const TextureCube& other) = delete; - TextureCube(TextureCube&& other) noexcept; - ~TextureCube() override; + public: + TextureCube(const ImageFormat* format, unsigned width, unsigned height); + TextureCube(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps); + TextureCube(const TextureCube& other) = delete; + TextureCube(TextureCube&& other) noexcept; + ~TextureCube() override; - TextureCube& operator=(const TextureCube& other) = delete; - TextureCube& operator=(TextureCube&& other) noexcept; + TextureCube& operator=(const TextureCube& other) = delete; + TextureCube& operator=(TextureCube&& other) noexcept; - [[nodiscard]] TextureType GetTextureType() const override; + [[nodiscard]] TextureType GetTextureType() const override; - [[nodiscard]] int GetFaceCount() const override; + [[nodiscard]] int GetFaceCount() const override; - [[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; - [[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override; -}; + [[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; + [[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override; + }; -class Texture3D final : public Texture -{ - unsigned m_width; - unsigned m_height; - unsigned m_depth; + class Texture3D final : public Texture + { + unsigned m_width; + unsigned m_height; + unsigned m_depth; -public: - Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth); - Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth, bool mipMaps); - Texture3D(const Texture3D& other) = delete; - Texture3D(Texture3D&& other) noexcept; - ~Texture3D() override; + public: + Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth); + Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth, bool mipMaps); + Texture3D(const Texture3D& other) = delete; + Texture3D(Texture3D&& other) noexcept; + ~Texture3D() override; - Texture3D& operator=(const Texture3D& other) = delete; - Texture3D& operator=(Texture3D&& other) noexcept; + Texture3D& operator=(const Texture3D& other) = delete; + Texture3D& operator=(Texture3D&& other) noexcept; - [[nodiscard]] TextureType GetTextureType() const override; + [[nodiscard]] TextureType GetTextureType() const override; - [[nodiscard]] unsigned GetWidth() const override; - [[nodiscard]] unsigned GetHeight() const override; - [[nodiscard]] unsigned GetDepth() const override; - [[nodiscard]] int GetFaceCount() const override; + [[nodiscard]] unsigned GetWidth() const override; + [[nodiscard]] unsigned GetHeight() const override; + [[nodiscard]] unsigned GetDepth() const override; + [[nodiscard]] int GetFaceCount() const override; - [[nodiscard]] size_t GetSizeOfMipLevel(int mipLevel) const override; - [[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; - [[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override; + [[nodiscard]] size_t GetSizeOfMipLevel(int mipLevel) const override; + [[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; + [[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override; - [[nodiscard]] int GetMipMapCount() const override; -}; + [[nodiscard]] int GetMipMapCount() const override; + }; +} // namespace image diff --git a/src/ObjImage/Image/TextureConverter.cpp b/src/ObjImage/Image/TextureConverter.cpp index 109aaf73..b848be0a 100644 --- a/src/ObjImage/Image/TextureConverter.cpp +++ b/src/ObjImage/Image/TextureConverter.cpp @@ -2,221 +2,224 @@ #include -constexpr uint64_t TextureConverter::Mask1(const unsigned length) +namespace image { - if (length >= sizeof(uint64_t) * 8) - return UINT64_MAX; - - return UINT64_MAX >> (sizeof(uint64_t) * 8 - length); -} - -void TextureConverter::SetPixelFunctions(const unsigned inBitCount, const unsigned outBitCount) -{ - switch (inBitCount) + constexpr uint64_t TextureConverter::Mask1(const unsigned length) { - case 16: - m_read_pixel_func = [](const void* offset, unsigned bitCount) - { - return static_cast(*static_cast(offset)); - }; - break; + if (length >= sizeof(uint64_t) * 8) + return UINT64_MAX; - case 32: - m_read_pixel_func = [](const void* offset, unsigned bitCount) - { - return static_cast(*static_cast(offset)); - }; - break; + return UINT64_MAX >> (sizeof(uint64_t) * 8 - length); + } - case 64: - m_read_pixel_func = [](const void* offset, unsigned bitCount) + void TextureConverter::SetPixelFunctions(const unsigned inBitCount, const unsigned outBitCount) + { + switch (inBitCount) { - return *static_cast(offset); - }; - break; - - default: - if (inBitCount <= 64) - { - m_read_pixel_func = [](const void* offset, const unsigned bitCount) - { - uint64_t result = 0; - - for (auto pixelOffset = 0u; pixelOffset < bitCount; pixelOffset += 8) - { - result |= (static_cast(*(static_cast(offset) + (pixelOffset / 8))) << pixelOffset); - } - - return result; - }; - } - else - { - assert(false); + case 16: m_read_pixel_func = [](const void* offset, unsigned bitCount) { - return 0ull; + return static_cast(*static_cast(offset)); }; + break; + + case 32: + m_read_pixel_func = [](const void* offset, unsigned bitCount) + { + return static_cast(*static_cast(offset)); + }; + break; + + case 64: + m_read_pixel_func = [](const void* offset, unsigned bitCount) + { + return *static_cast(offset); + }; + break; + + default: + if (inBitCount <= 64) + { + m_read_pixel_func = [](const void* offset, const unsigned bitCount) + { + uint64_t result = 0; + + for (auto pixelOffset = 0u; pixelOffset < bitCount; pixelOffset += 8) + { + result |= (static_cast(*(static_cast(offset) + (pixelOffset / 8))) << pixelOffset); + } + + return result; + }; + } + else + { + assert(false); + m_read_pixel_func = [](const void* offset, unsigned bitCount) + { + return 0ull; + }; + } + break; + } + + switch (outBitCount) + { + case 16: + m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount) + { + *static_cast(offset) = static_cast(pixel); + }; + break; + + case 32: + m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount) + { + *static_cast(offset) = static_cast(pixel); + }; + break; + + case 64: + m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount) + { + *static_cast(offset) = pixel; + }; + break; + + default: + if (inBitCount <= 64) + { + m_write_pixel_func = [](void* offset, const uint64_t pixel, const unsigned bitCount) + { + for (auto pixelOffset = 0u; pixelOffset < bitCount; pixelOffset += 8) + { + *(static_cast(offset) + (pixelOffset / 8)) = static_cast(pixel >> pixelOffset); + } + }; + } + else + { + assert(false); + m_write_pixel_func = [](void* offset, uint64_t pixel, unsigned bitCount) {}; + } + break; } - break; } - switch (outBitCount) + TextureConverter::TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat) + : m_input_texture(inputTexture), + m_output_texture(nullptr), + m_input_format(inputTexture->GetFormat()), + m_output_format(targetFormat) { - case 16: - m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount) - { - *static_cast(offset) = static_cast(pixel); - }; - break; + } - case 32: - m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount) + void TextureConverter::CreateOutputTexture() + { + switch (m_input_texture->GetTextureType()) { - *static_cast(offset) = static_cast(pixel); - }; - break; + case TextureType::T_2D: + m_output_texture = + std::make_unique(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps()); + break; - case 64: - m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount) - { - *static_cast(offset) = pixel; - }; - break; + case TextureType::T_CUBE: + m_output_texture = + std::make_unique(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps()); + break; - default: - if (inBitCount <= 64) + case TextureType::T_3D: + m_output_texture = std::make_unique( + m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->GetDepth(), m_input_texture->HasMipMaps()); + break; + default: + assert(false); + break; + } + + m_output_texture->Allocate(); + } + + void TextureConverter::ReorderUnsignedToUnsigned() const + { + const auto* inputFormat = dynamic_cast(m_input_format); + const auto* outputFormat = dynamic_cast(m_output_format); + const auto mipCount = m_input_texture->HasMipMaps() ? m_input_texture->GetMipMapCount() : 1; + + const auto rInputMask = inputFormat->HasR() ? Mask1(inputFormat->m_r_size) << inputFormat->m_r_offset : 0; + const auto gInputMask = inputFormat->HasG() ? Mask1(inputFormat->m_g_size) << inputFormat->m_g_offset : 0; + const auto bInputMask = inputFormat->HasB() ? Mask1(inputFormat->m_b_size) << inputFormat->m_b_offset : 0; + const auto aInputMask = inputFormat->HasA() ? Mask1(inputFormat->m_a_size) << inputFormat->m_a_offset : 0; + const bool rConvert = rInputMask != 0 && outputFormat->m_r_size > 0; + const bool gConvert = gInputMask != 0 && outputFormat->m_g_size > 0; + const bool bConvert = bInputMask != 0 && outputFormat->m_b_size > 0; + const bool aConvert = aInputMask != 0 && outputFormat->m_a_size > 0; + + for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++) { - m_write_pixel_func = [](void* offset, const uint64_t pixel, const unsigned bitCount) + const auto mipLevelSize = m_input_texture->GetSizeOfMipLevel(mipLevel) * m_input_texture->GetFaceCount(); + const auto* inputBuffer = m_input_texture->GetBufferForMipLevel(mipLevel); + auto* outputBuffer = m_output_texture->GetBufferForMipLevel(mipLevel); + + const auto inputBytePerPixel = inputFormat->m_bits_per_pixel / 8; + const auto outputBytePerPixel = outputFormat->m_bits_per_pixel / 8; + + auto outputOffset = 0u; + for (auto inputOffset = 0u; inputOffset < mipLevelSize; inputOffset += inputBytePerPixel, outputOffset += outputBytePerPixel) { - for (auto pixelOffset = 0u; pixelOffset < bitCount; pixelOffset += 8) - { - *(static_cast(offset) + (pixelOffset / 8)) = static_cast(pixel >> pixelOffset); - } - }; + uint64_t outPixel = 0; + const auto inPixel = m_read_pixel_func(&inputBuffer[inputOffset], inputFormat->m_bits_per_pixel); + + if (rConvert) + outPixel |= (inPixel & rInputMask) >> inputFormat->m_r_offset << outputFormat->m_r_offset; + if (gConvert) + outPixel |= (inPixel & gInputMask) >> inputFormat->m_g_offset << outputFormat->m_g_offset; + if (bConvert) + outPixel |= (inPixel & bInputMask) >> inputFormat->m_b_offset << outputFormat->m_b_offset; + if (aConvert) + outPixel |= (inPixel & aInputMask) >> inputFormat->m_a_offset << outputFormat->m_a_offset; + + m_write_pixel_func(&outputBuffer[outputOffset], outPixel, outputFormat->m_bits_per_pixel); + } + } + } + + void TextureConverter::ConvertUnsignedToUnsigned() + { + const auto* inputFormat = dynamic_cast(m_input_format); + const auto* outputFormat = dynamic_cast(m_output_format); + + assert(inputFormat->m_bits_per_pixel <= 64); + assert(outputFormat->m_bits_per_pixel <= 64); + + SetPixelFunctions(inputFormat->m_bits_per_pixel, outputFormat->m_bits_per_pixel); + + if (inputFormat->m_r_size == outputFormat->m_r_size && inputFormat->m_g_size == outputFormat->m_g_size + && inputFormat->m_b_size == outputFormat->m_b_size && inputFormat->m_a_size == outputFormat->m_a_size) + { + ReorderUnsignedToUnsigned(); } else { + // Unsupported as of now assert(false); - m_write_pixel_func = [](void* offset, uint64_t pixel, unsigned bitCount) {}; } - break; - } -} - -TextureConverter::TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat) - : m_input_texture(inputTexture), - m_output_texture(nullptr), - m_input_format(inputTexture->GetFormat()), - m_output_format(targetFormat) -{ -} - -void TextureConverter::CreateOutputTexture() -{ - switch (m_input_texture->GetTextureType()) - { - case TextureType::T_2D: - m_output_texture = - std::make_unique(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps()); - break; - - case TextureType::T_CUBE: - m_output_texture = - std::make_unique(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps()); - break; - - case TextureType::T_3D: - m_output_texture = std::make_unique( - m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->GetDepth(), m_input_texture->HasMipMaps()); - break; - default: - assert(false); - break; } - m_output_texture->Allocate(); -} - -void TextureConverter::ReorderUnsignedToUnsigned() const -{ - const auto* inputFormat = dynamic_cast(m_input_format); - const auto* outputFormat = dynamic_cast(m_output_format); - const auto mipCount = m_input_texture->HasMipMaps() ? m_input_texture->GetMipMapCount() : 1; - - const auto rInputMask = inputFormat->HasR() ? Mask1(inputFormat->m_r_size) << inputFormat->m_r_offset : 0; - const auto gInputMask = inputFormat->HasG() ? Mask1(inputFormat->m_g_size) << inputFormat->m_g_offset : 0; - const auto bInputMask = inputFormat->HasB() ? Mask1(inputFormat->m_b_size) << inputFormat->m_b_offset : 0; - const auto aInputMask = inputFormat->HasA() ? Mask1(inputFormat->m_a_size) << inputFormat->m_a_offset : 0; - const bool rConvert = rInputMask != 0 && outputFormat->m_r_size > 0; - const bool gConvert = gInputMask != 0 && outputFormat->m_g_size > 0; - const bool bConvert = bInputMask != 0 && outputFormat->m_b_size > 0; - const bool aConvert = aInputMask != 0 && outputFormat->m_a_size > 0; - - for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++) + std::unique_ptr TextureConverter::Convert() { - const auto mipLevelSize = m_input_texture->GetSizeOfMipLevel(mipLevel) * m_input_texture->GetFaceCount(); - const auto* inputBuffer = m_input_texture->GetBufferForMipLevel(mipLevel); - auto* outputBuffer = m_output_texture->GetBufferForMipLevel(mipLevel); + CreateOutputTexture(); - const auto inputBytePerPixel = inputFormat->m_bits_per_pixel / 8; - const auto outputBytePerPixel = outputFormat->m_bits_per_pixel / 8; - - auto outputOffset = 0u; - for (auto inputOffset = 0u; inputOffset < mipLevelSize; inputOffset += inputBytePerPixel, outputOffset += outputBytePerPixel) + if (m_input_format->GetType() == ImageFormatType::UNSIGNED && m_output_format->GetType() == ImageFormatType::UNSIGNED) { - uint64_t outPixel = 0; - const auto inPixel = m_read_pixel_func(&inputBuffer[inputOffset], inputFormat->m_bits_per_pixel); - - if (rConvert) - outPixel |= (inPixel & rInputMask) >> inputFormat->m_r_offset << outputFormat->m_r_offset; - if (gConvert) - outPixel |= (inPixel & gInputMask) >> inputFormat->m_g_offset << outputFormat->m_g_offset; - if (bConvert) - outPixel |= (inPixel & bInputMask) >> inputFormat->m_b_offset << outputFormat->m_b_offset; - if (aConvert) - outPixel |= (inPixel & aInputMask) >> inputFormat->m_a_offset << outputFormat->m_a_offset; - - m_write_pixel_func(&outputBuffer[outputOffset], outPixel, outputFormat->m_bits_per_pixel); + ConvertUnsignedToUnsigned(); } + else + { + // Unsupported as of now + assert(false); + } + + return std::move(m_output_texture); } -} - -void TextureConverter::ConvertUnsignedToUnsigned() -{ - const auto* inputFormat = dynamic_cast(m_input_format); - const auto* outputFormat = dynamic_cast(m_output_format); - - assert(inputFormat->m_bits_per_pixel <= 64); - assert(outputFormat->m_bits_per_pixel <= 64); - - SetPixelFunctions(inputFormat->m_bits_per_pixel, outputFormat->m_bits_per_pixel); - - if (inputFormat->m_r_size == outputFormat->m_r_size && inputFormat->m_g_size == outputFormat->m_g_size && inputFormat->m_b_size == outputFormat->m_b_size - && inputFormat->m_a_size == outputFormat->m_a_size) - { - ReorderUnsignedToUnsigned(); - } - else - { - // Unsupported as of now - assert(false); - } -} - -std::unique_ptr TextureConverter::Convert() -{ - CreateOutputTexture(); - - if (m_input_format->GetType() == ImageFormatType::UNSIGNED && m_output_format->GetType() == ImageFormatType::UNSIGNED) - { - ConvertUnsignedToUnsigned(); - } - else - { - // Unsupported as of now - assert(false); - } - - return std::move(m_output_texture); -} +} // namespace image diff --git a/src/ObjImage/Image/TextureConverter.h b/src/ObjImage/Image/TextureConverter.h index 30bc382d..eefc9ae6 100644 --- a/src/ObjImage/Image/TextureConverter.h +++ b/src/ObjImage/Image/TextureConverter.h @@ -5,27 +5,30 @@ #include #include -class TextureConverter +namespace image { -public: - TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat); + class TextureConverter + { + public: + TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat); - std::unique_ptr Convert(); + std::unique_ptr Convert(); -private: - static constexpr uint64_t Mask1(unsigned length); - void SetPixelFunctions(unsigned inBitCount, unsigned outBitCount); + private: + static constexpr uint64_t Mask1(unsigned length); + void SetPixelFunctions(unsigned inBitCount, unsigned outBitCount); - void CreateOutputTexture(); + void CreateOutputTexture(); - void ReorderUnsignedToUnsigned() const; - void ConvertUnsignedToUnsigned(); + void ReorderUnsignedToUnsigned() const; + void ConvertUnsignedToUnsigned(); - std::function m_read_pixel_func; - std::function m_write_pixel_func; + std::function m_read_pixel_func; + std::function m_write_pixel_func; - const Texture* m_input_texture; - std::unique_ptr m_output_texture; - const ImageFormat* m_input_format; - const ImageFormat* m_output_format; -}; + const Texture* m_input_texture; + std::unique_ptr m_output_texture; + const ImageFormat* m_input_format; + const ImageFormat* m_output_format; + }; +} // namespace image diff --git a/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp b/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp index 8e876432..d8ceb88f 100644 --- a/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp +++ b/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp @@ -12,6 +12,7 @@ #include using namespace IW3; +using namespace image; namespace { @@ -38,7 +39,7 @@ namespace if (!file.IsOpen()) return AssetCreationResult::NoAction(); - const auto texture = dds::LoadDds(*file.m_stream); + const auto texture = image::LoadDds(*file.m_stream); if (!texture) { con::error("Failed to load dds file for image asset \"{}\"", assetName); @@ -91,11 +92,11 @@ namespace loadDef->levelCount = static_cast(mipCount); loadDef->flags = 0; if (!texture->HasMipMaps()) - loadDef->flags |= iwi6::IMG_FLAG_NOMIPMAPS; + loadDef->flags |= image::iwi6::IMG_FLAG_NOMIPMAPS; if (texture->GetTextureType() == TextureType::T_CUBE) - loadDef->flags |= iwi6::IMG_FLAG_CUBEMAP; + loadDef->flags |= image::iwi6::IMG_FLAG_CUBEMAP; if (texture->GetTextureType() == TextureType::T_3D) - loadDef->flags |= iwi6::IMG_FLAG_VOLMAP; + loadDef->flags |= image::iwi6::IMG_FLAG_VOLMAP; loadDef->dimensions[0] = image->width; loadDef->dimensions[1] = image->height; loadDef->dimensions[2] = image->depth; diff --git a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp b/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp index a7f68cf4..d51d670b 100644 --- a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp +++ b/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp @@ -37,7 +37,7 @@ namespace file.m_stream->read(fileData.get(), fileSize); std::istringstream ss(std::string(fileData.get(), fileSize)); - const auto texture = iwi::LoadIwi(ss); + const auto texture = image::LoadIwi(ss); if (!texture) { con::error("Failed to load texture from: {}", fileName); diff --git a/src/ObjLoading/Game/T6/Image/LoaderImageT6.cpp b/src/ObjLoading/Game/T6/Image/LoaderImageT6.cpp index e870761c..81ffbf7c 100644 --- a/src/ObjLoading/Game/T6/Image/LoaderImageT6.cpp +++ b/src/ObjLoading/Game/T6/Image/LoaderImageT6.cpp @@ -38,7 +38,7 @@ namespace const auto dataHash = static_cast(crc32(0u, reinterpret_cast(fileData.get()), static_cast(fileSize))); std::istringstream ss(std::string(fileData.get(), fileSize)); - const auto texture = iwi::LoadIwi(ss); + const auto texture = image::LoadIwi(ss); if (!texture) { con::error("Failed to load texture from: {}", fileName); diff --git a/src/ObjLoading/Image/ImageLoaderCommon.cpp b/src/ObjLoading/Image/ImageLoaderCommon.cpp new file mode 100644 index 00000000..6f0c3339 --- /dev/null +++ b/src/ObjLoading/Image/ImageLoaderCommon.cpp @@ -0,0 +1,15 @@ +#include "ImageLoaderCommon.h" + +namespace image +{ + std::optional CommonImageLoaderResult::GetResultIfCancelled() const + { + if (m_failure) + return AssetCreationResult::Failure(); + + if (!m_texture) + return AssetCreationResult::NoAction(); + + return std::nullopt; + } +} // namespace image diff --git a/src/ObjLoading/Image/ImageLoaderCommon.h b/src/ObjLoading/Image/ImageLoaderCommon.h new file mode 100644 index 00000000..57744ae2 --- /dev/null +++ b/src/ObjLoading/Image/ImageLoaderCommon.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Asset/AssetCreationResult.h" +#include "Image/IwiTypes.h" +#include "Image/Texture.h" + +#include +#include +#include + +namespace image +{ + struct CommonImageLoaderResult + { + std::optional GetResultIfCancelled() const; + + bool m_failure; + std::string m_iwi_path; + std::unique_ptr m_texture; + }; + + CommonImageLoaderResult LoadImageCommon(); +} // namespace image diff --git a/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.cpp b/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.cpp index 06d0b422..3e9d81f9 100644 --- a/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.cpp +++ b/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.cpp @@ -16,6 +16,7 @@ #include using namespace IW3; +using namespace image; namespace { @@ -26,15 +27,15 @@ namespace const auto& loadDef = *image.texture.loadDef; textureLoader.Width(loadDef.dimensions[0]).Height(loadDef.dimensions[1]).Depth(loadDef.dimensions[2]); - if (loadDef.flags & iwi6::IMG_FLAG_VOLMAP) + if (loadDef.flags & image::iwi6::IMG_FLAG_VOLMAP) textureLoader.Type(TextureType::T_3D); - else if (loadDef.flags & iwi6::IMG_FLAG_CUBEMAP) + else if (loadDef.flags & image::iwi6::IMG_FLAG_CUBEMAP) textureLoader.Type(TextureType::T_CUBE); else textureLoader.Type(TextureType::T_2D); textureLoader.Format(static_cast(loadDef.format)); - textureLoader.HasMipMaps(!(loadDef.flags & iwi6::IMG_FLAG_NOMIPMAPS)); + textureLoader.HasMipMaps(!(loadDef.flags & image::iwi6::IMG_FLAG_NOMIPMAPS)); return textureLoader.LoadTexture(loadDef.data); } @@ -48,7 +49,7 @@ namespace return nullptr; } - return iwi::LoadIwi(*filePathImage.m_stream); + return image::LoadIwi(*filePathImage.m_stream); } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.h b/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.h index 32fdf23e..e8c9665c 100644 --- a/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.h +++ b/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.h @@ -2,7 +2,7 @@ #include "Dumping/AbstractAssetDumper.h" #include "Game/IW3/IW3.h" -#include "Image/IImageWriter.h" +#include "Image/ImageWriter.h" #include @@ -17,6 +17,6 @@ namespace image void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; private: - std::unique_ptr m_writer; + std::unique_ptr m_writer; }; } // namespace image diff --git a/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.cpp b/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.cpp index d921581c..1327e43a 100644 --- a/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.cpp +++ b/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.cpp @@ -13,6 +13,7 @@ #include using namespace IW4; +using namespace image; namespace { @@ -23,15 +24,15 @@ namespace const auto& loadDef = *image.texture.loadDef; textureLoader.Width(image.width).Height(image.height).Depth(image.depth); - if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_3D) + if ((loadDef.flags & image::iwi8::IMG_FLAG_MAPTYPE_MASK) == image::iwi8::IMG_FLAG_MAPTYPE_3D) textureLoader.Type(TextureType::T_3D); - else if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_CUBE) + else if ((loadDef.flags & image::iwi8::IMG_FLAG_MAPTYPE_MASK) == image::iwi8::IMG_FLAG_MAPTYPE_CUBE) textureLoader.Type(TextureType::T_CUBE); else textureLoader.Type(TextureType::T_2D); textureLoader.Format(static_cast(loadDef.format)); - textureLoader.HasMipMaps(!(loadDef.flags & iwi8::IMG_FLAG_NOMIPMAPS)); + textureLoader.HasMipMaps(!(loadDef.flags & image::iwi8::IMG_FLAG_NOMIPMAPS)); return textureLoader.LoadTexture(loadDef.data); } @@ -45,7 +46,7 @@ namespace return nullptr; } - return iwi::LoadIwi(*filePathImage.m_stream); + return image::LoadIwi(*filePathImage.m_stream); } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.h b/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.h index e87e71a9..80239cbc 100644 --- a/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.h +++ b/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.h @@ -2,7 +2,7 @@ #include "Dumping/AbstractAssetDumper.h" #include "Game/IW4/IW4.h" -#include "Image/IImageWriter.h" +#include "Image/ImageWriter.h" #include @@ -17,6 +17,6 @@ namespace image void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; private: - std::unique_ptr m_writer; + std::unique_ptr m_writer; }; } // namespace image diff --git a/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.cpp b/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.cpp index 6a219864..71f2f69e 100644 --- a/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.cpp +++ b/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.cpp @@ -13,6 +13,7 @@ #include using namespace IW5; +using namespace image; namespace { @@ -24,15 +25,15 @@ namespace textureLoader.Width(image.width).Height(image.height).Depth(image.depth); - if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_3D) + if ((loadDef.flags & image::iwi8::IMG_FLAG_MAPTYPE_MASK) == image::iwi8::IMG_FLAG_MAPTYPE_3D) textureLoader.Type(TextureType::T_3D); - else if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_CUBE) + else if ((loadDef.flags & image::iwi8::IMG_FLAG_MAPTYPE_MASK) == image::iwi8::IMG_FLAG_MAPTYPE_CUBE) textureLoader.Type(TextureType::T_CUBE); else textureLoader.Type(TextureType::T_2D); textureLoader.Format(static_cast(loadDef.format)); - textureLoader.HasMipMaps(!(loadDef.flags & iwi8::IMG_FLAG_NOMIPMAPS)); + textureLoader.HasMipMaps(!(loadDef.flags & image::iwi8::IMG_FLAG_NOMIPMAPS)); return textureLoader.LoadTexture(loadDef.data); } @@ -46,7 +47,7 @@ namespace return nullptr; } - return iwi::LoadIwi(*filePathImage.m_stream); + return image::LoadIwi(*filePathImage.m_stream); } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.h b/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.h index 7c4f8200..064991cc 100644 --- a/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.h +++ b/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.h @@ -2,7 +2,7 @@ #include "Dumping/AbstractAssetDumper.h" #include "Game/IW5/IW5.h" -#include "Image/IImageWriter.h" +#include "Image/ImageWriter.h" #include @@ -17,6 +17,6 @@ namespace image void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; private: - std::unique_ptr m_writer; + std::unique_ptr m_writer; }; } // namespace image diff --git a/src/ObjWriting/Game/T5/Image/ImageDumperT5.cpp b/src/ObjWriting/Game/T5/Image/ImageDumperT5.cpp index 27fe8f03..88a9cdd8 100644 --- a/src/ObjWriting/Game/T5/Image/ImageDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Image/ImageDumperT5.cpp @@ -13,6 +13,7 @@ #include using namespace T5; +using namespace image; namespace { @@ -23,15 +24,15 @@ namespace const auto& loadDef = *image.texture.loadDef; textureLoader.Width(image.width).Height(image.height).Depth(image.depth); - if (loadDef.flags & iwi13::IMG_FLAG_VOLMAP) + if (loadDef.flags & image::iwi13::IMG_FLAG_VOLMAP) textureLoader.Type(TextureType::T_3D); - else if (loadDef.flags & iwi13::IMG_FLAG_CUBEMAP) + else if (loadDef.flags & image::iwi13::IMG_FLAG_CUBEMAP) textureLoader.Type(TextureType::T_CUBE); else textureLoader.Type(TextureType::T_2D); textureLoader.Format(static_cast(loadDef.format)); - textureLoader.HasMipMaps(!(loadDef.flags & iwi13::IMG_FLAG_NOMIPMAPS)); + textureLoader.HasMipMaps(!(loadDef.flags & image::iwi13::IMG_FLAG_NOMIPMAPS)); return textureLoader.LoadTexture(loadDef.data); } @@ -45,7 +46,7 @@ namespace return nullptr; } - return iwi::LoadIwi(*filePathImage.m_stream); + return image::LoadIwi(*filePathImage.m_stream); } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/T5/Image/ImageDumperT5.h b/src/ObjWriting/Game/T5/Image/ImageDumperT5.h index 109758e5..43cb41df 100644 --- a/src/ObjWriting/Game/T5/Image/ImageDumperT5.h +++ b/src/ObjWriting/Game/T5/Image/ImageDumperT5.h @@ -2,7 +2,7 @@ #include "Dumping/AbstractAssetDumper.h" #include "Game/T5/T5.h" -#include "Image/IImageWriter.h" +#include "Image/ImageWriter.h" #include @@ -17,6 +17,6 @@ namespace image void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; private: - std::unique_ptr m_writer; + std::unique_ptr m_writer; }; } // namespace image diff --git a/src/ObjWriting/Game/T6/Image/ImageDumperT6.cpp b/src/ObjWriting/Game/T6/Image/ImageDumperT6.cpp index 3566f780..29b64061 100644 --- a/src/ObjWriting/Game/T6/Image/ImageDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Image/ImageDumperT6.cpp @@ -14,6 +14,7 @@ #include using namespace T6; +using namespace image; namespace { @@ -24,15 +25,15 @@ namespace const auto& loadDef = *image.texture.loadDef; textureLoader.Width(image.width).Height(image.height).Depth(image.depth); - if (loadDef.flags & iwi27::IMG_FLAG_VOLMAP) + if (loadDef.flags & image::iwi27::IMG_FLAG_VOLMAP) textureLoader.Type(TextureType::T_3D); - else if (loadDef.flags & iwi27::IMG_FLAG_CUBEMAP) + else if (loadDef.flags & image::iwi27::IMG_FLAG_CUBEMAP) textureLoader.Type(TextureType::T_CUBE); else textureLoader.Type(TextureType::T_2D); textureLoader.Format(static_cast(loadDef.format)); - textureLoader.HasMipMaps(!(loadDef.flags & iwi27::IMG_FLAG_NOMIPMAPS)); + textureLoader.HasMipMaps(!(loadDef.flags & image::iwi27::IMG_FLAG_NOMIPMAPS)); return textureLoader.LoadTexture(loadDef.data); } @@ -46,7 +47,7 @@ namespace if (ipakStream) { - auto loadedTexture = iwi::LoadIwi(*ipakStream); + auto loadedTexture = image::LoadIwi(*ipakStream); ipakStream->close(); if (loadedTexture != nullptr) @@ -63,7 +64,7 @@ namespace return nullptr; } - return iwi::LoadIwi(*filePathImage.m_stream); + return image::LoadIwi(*filePathImage.m_stream); } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/T6/Image/ImageDumperT6.h b/src/ObjWriting/Game/T6/Image/ImageDumperT6.h index 81dc2e93..a52d497d 100644 --- a/src/ObjWriting/Game/T6/Image/ImageDumperT6.h +++ b/src/ObjWriting/Game/T6/Image/ImageDumperT6.h @@ -2,7 +2,7 @@ #include "Dumping/AbstractAssetDumper.h" #include "Game/T6/T6.h" -#include "Image/IImageWriter.h" +#include "Image/ImageWriter.h" #include @@ -17,6 +17,6 @@ namespace image void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; private: - std::unique_ptr m_writer; + std::unique_ptr m_writer; }; } // namespace image From 33584f6f7be4e3787d787aa21e1420f0807da345 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 2 Jan 2026 19:51:44 +0100 Subject: [PATCH 2/5] feat: add external image loader for every supported game --- src/ImageConverter/ImageConverter.cpp | 6 +- src/ObjImage/Image/IwiLoader.cpp | 125 +++++++++++++----- src/ObjImage/Image/IwiLoader.h | 11 +- src/ObjImage/Image/IwiTypes.h | 12 ++ src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp | 4 +- src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp | 3 +- .../Game/IW5/Image/LoaderImageIW5.cpp | 71 ---------- .../Game/IW5/Image/LoaderImageIW5.h | 13 -- src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp | 4 +- src/ObjLoading/Game/T5/ObjLoaderT5.cpp | 3 +- .../Game/T6/Image/LoaderImageT6.cpp | 79 ----------- src/ObjLoading/Game/T6/Image/LoaderImageT6.h | 13 -- src/ObjLoading/Game/T6/ObjLoaderT6.cpp | 4 +- src/ObjLoading/Image/ImageLoaderCommon.cpp | 74 +++++++++++ src/ObjLoading/Image/ImageLoaderCommon.h | 20 ++- .../Image/ImageLoaderExternal.cpp.template | 111 ++++++++++++++++ .../Image/ImageLoaderExternal.h.template | 23 ++++ .../Game/IW3/Image/ImageDumperIW3.cpp | 3 +- .../Game/IW4/Image/ImageDumperIW4.cpp | 3 +- .../Game/IW5/Image/ImageDumperIW5.cpp | 3 +- .../Game/T5/Image/ImageDumperT5.cpp | 3 +- .../Game/T6/Image/ImageDumperT6.cpp | 9 +- 22 files changed, 369 insertions(+), 228 deletions(-) delete mode 100644 src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp delete mode 100644 src/ObjLoading/Game/IW5/Image/LoaderImageIW5.h delete mode 100644 src/ObjLoading/Game/T6/Image/LoaderImageT6.cpp delete mode 100644 src/ObjLoading/Game/T6/Image/LoaderImageT6.h create mode 100644 src/ObjLoading/Image/ImageLoaderExternal.cpp.template create mode 100644 src/ObjLoading/Image/ImageLoaderExternal.h.template diff --git a/src/ImageConverter/ImageConverter.cpp b/src/ImageConverter/ImageConverter.cpp index bdca8853..89cde7f4 100644 --- a/src/ImageConverter/ImageConverter.cpp +++ b/src/ImageConverter/ImageConverter.cpp @@ -79,8 +79,8 @@ namespace return false; } - const auto texture = image::LoadIwi(file); - if (!texture) + const auto loadResult = image::LoadIwi(file); + if (!loadResult) return false; auto outPath = iwiPath; @@ -93,7 +93,7 @@ namespace return false; } - m_dds_writer.DumpImage(outFile, texture.get()); + m_dds_writer.DumpImage(outFile, loadResult->m_texture.get()); return true; } diff --git a/src/ObjImage/Image/IwiLoader.cpp b/src/ObjImage/Image/IwiLoader.cpp index 1893904a..503c804f 100644 --- a/src/ObjImage/Image/IwiLoader.cpp +++ b/src/ObjImage/Image/IwiLoader.cpp @@ -49,17 +49,20 @@ namespace return nullptr; } - std::unique_ptr LoadIwi6(std::istream& stream) + std::optional LoadIwi6(std::istream& stream) { iwi6::IwiHeader header{}; stream.read(reinterpret_cast(&header), sizeof(header)); if (stream.gcount() != sizeof(header)) - return nullptr; + { + con::error("IWI header corrupted"); + return std::nullopt; + } const auto* format = GetFormat6(header.format); if (format == nullptr) - return nullptr; + return std::nullopt; auto width = header.dimensions[0]; auto height = header.dimensions[1]; @@ -88,18 +91,30 @@ namespace && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) { con::error("Iwi has invalid file size for picmip {}", currentMipLevel); - return nullptr; + return std::nullopt; } stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); if (stream.gcount() != sizeOfMipLevel) { con::error("Unexpected eof of iwi in mip level {}", currentMipLevel); - return nullptr; + return std::nullopt; } } - return texture; + CommonIwiMetaData meta{ + .m_no_picmip = (header.flags & iwi6::IwiFlags::IMG_FLAG_NOPICMIP) != 0, + .m_streaming = (header.flags & iwi6::IwiFlags::IMG_FLAG_STREAMING) != 0, + .m_clamp_u = (header.flags & iwi6::IwiFlags::IMG_FLAG_CLAMP_U) != 0, + .m_clamp_v = (header.flags & iwi6::IwiFlags::IMG_FLAG_CLAMP_V) != 0, + .m_dynamic = (header.flags & iwi6::IwiFlags::IMG_FLAG_DYNAMIC) != 0, + }; + + return IwiLoaderResult{ + .m_version = IwiVersion::IWI_6, + .m_meta = meta, + .m_texture = std::move(texture), + }; } const ImageFormat* GetFormat8(int8_t format) @@ -147,17 +162,20 @@ namespace return nullptr; } - std::unique_ptr LoadIwi8(std::istream& stream) + std::optional LoadIwi8(std::istream& stream) { iwi8::IwiHeader header{}; stream.read(reinterpret_cast(&header), sizeof(header)); if (stream.gcount() != sizeof(header)) - return nullptr; + { + con::error("IWI header corrupted"); + return std::nullopt; + } const auto* format = GetFormat8(header.format); if (format == nullptr) - return nullptr; + return std::nullopt; auto width = header.dimensions[0]; auto height = header.dimensions[1]; @@ -180,12 +198,12 @@ namespace else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_1D) { con::error("Iwi has unsupported map type 1D"); - return nullptr; + return std::nullopt; } else { con::error("Iwi has unsupported map type"); - return nullptr; + return std::nullopt; } texture->Allocate(); @@ -202,18 +220,30 @@ namespace && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) { con::error("Iwi has invalid file size for picmip {}", currentMipLevel); - return nullptr; + return std::nullopt; } stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); if (stream.gcount() != sizeOfMipLevel) { con::error("Unexpected eof of iwi in mip level {}", currentMipLevel); - return nullptr; + return std::nullopt; } } - return texture; + CommonIwiMetaData meta{ + .m_no_picmip = (header.flags & iwi8::IwiFlags::IMG_FLAG_NOPICMIP) != 0, + .m_streaming = (header.flags & iwi8::IwiFlags::IMG_FLAG_STREAMING) != 0, + .m_clamp_u = (header.flags & iwi8::IwiFlags::IMG_FLAG_CLAMP_U) != 0, + .m_clamp_v = (header.flags & iwi8::IwiFlags::IMG_FLAG_CLAMP_V) != 0, + .m_dynamic = (header.flags & iwi8::IwiFlags::IMG_FLAG_DYNAMIC) != 0, + }; + + return IwiLoaderResult{ + .m_version = IwiVersion::IWI_8, + .m_meta = meta, + .m_texture = std::move(texture), + }; } const ImageFormat* GetFormat13(int8_t format) @@ -258,17 +288,20 @@ namespace return nullptr; } - std::unique_ptr LoadIwi13(std::istream& stream) + std::optional LoadIwi13(std::istream& stream) { iwi13::IwiHeader header{}; stream.read(reinterpret_cast(&header), sizeof(header)); if (stream.gcount() != sizeof(header)) - return nullptr; + { + con::error("IWI header corrupted"); + return std::nullopt; + } const auto* format = GetFormat6(header.format); if (format == nullptr) - return nullptr; + return std::nullopt; auto width = header.dimensions[0]; auto height = header.dimensions[1]; @@ -297,18 +330,31 @@ namespace && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) { con::error("Iwi has invalid file size for picmip {}", currentMipLevel); - return nullptr; + return std::nullopt; } stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); if (stream.gcount() != sizeOfMipLevel) { con::error("Unexpected eof of iwi in mip level {}", currentMipLevel); - return nullptr; + return std::nullopt; } } - return texture; + CommonIwiMetaData meta{ + .m_no_picmip = (header.flags & iwi13::IwiFlags::IMG_FLAG_NOPICMIP) != 0, + .m_streaming = (header.flags & iwi13::IwiFlags::IMG_FLAG_STREAMING) != 0, + .m_clamp_u = (header.flags & iwi13::IwiFlags::IMG_FLAG_CLAMP_U) != 0, + .m_clamp_v = (header.flags & iwi13::IwiFlags::IMG_FLAG_CLAMP_V) != 0, + .m_dynamic = (header.flags & iwi13::IwiFlags::IMG_FLAG_DYNAMIC) != 0, + .m_gamma = header.gamma, + }; + + return IwiLoaderResult{ + .m_version = IwiVersion::IWI_13, + .m_meta = meta, + .m_texture = std::move(texture), + }; } const ImageFormat* GetFormat27(int8_t format) @@ -355,17 +401,20 @@ namespace return nullptr; } - std::unique_ptr LoadIwi27(std::istream& stream) + std::optional LoadIwi27(std::istream& stream) { iwi27::IwiHeader header{}; stream.read(reinterpret_cast(&header), sizeof(header)); if (stream.gcount() != sizeof(header)) - return nullptr; + { + con::error("IWI header corrupted"); + return std::nullopt; + } const auto* format = GetFormat27(header.format); if (format == nullptr) - return nullptr; + return std::nullopt; auto width = header.dimensions[0]; auto height = header.dimensions[1]; @@ -394,35 +443,51 @@ namespace && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) { con::error("Iwi has invalid file size for picmip {}", currentMipLevel); - return nullptr; + return std::nullopt; } stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); if (stream.gcount() != sizeOfMipLevel) { con::error("Unexpected eof of iwi in mip level {}", currentMipLevel); - return nullptr; + return std::nullopt; } } - return texture; + CommonIwiMetaData meta{ + .m_no_picmip = (header.flags & iwi27::IwiFlags::IMG_FLAG_NOPICMIP) != 0, + .m_streaming = (header.flags & iwi27::IwiFlags::IMG_FLAG_STREAMING) != 0, + .m_clamp_u = (header.flags & iwi27::IwiFlags::IMG_FLAG_CLAMP_U) != 0, + .m_clamp_v = (header.flags & iwi27::IwiFlags::IMG_FLAG_CLAMP_V) != 0, + .m_dynamic = (header.flags & iwi27::IwiFlags::IMG_FLAG_DYNAMIC) != 0, + .m_gamma = header.gamma, + }; + + return IwiLoaderResult{ + .m_version = IwiVersion::IWI_27, + .m_meta = meta, + .m_texture = std::move(texture), + }; } } // namespace namespace image { - std::unique_ptr LoadIwi(std::istream& stream) + std::optional LoadIwi(std::istream& stream) { IwiVersionHeader iwiVersionHeader{}; stream.read(reinterpret_cast(&iwiVersionHeader), sizeof(iwiVersionHeader)); if (stream.gcount() != sizeof(iwiVersionHeader)) - return nullptr; + { + con::error("IWI version header corrupted"); + return std::nullopt; + } if (iwiVersionHeader.tag[0] != 'I' || iwiVersionHeader.tag[1] != 'W' || iwiVersionHeader.tag[2] != 'i') { con::error("Invalid IWI magic"); - return nullptr; + return std::nullopt; } switch (iwiVersionHeader.version) @@ -444,6 +509,6 @@ namespace image } con::error("Unknown IWI version {}", iwiVersionHeader.version); - return nullptr; + return std::nullopt; } } // namespace image diff --git a/src/ObjImage/Image/IwiLoader.h b/src/ObjImage/Image/IwiLoader.h index 29aaeb61..66b42fd1 100644 --- a/src/ObjImage/Image/IwiLoader.h +++ b/src/ObjImage/Image/IwiLoader.h @@ -1,11 +1,20 @@ #pragma once +#include "Image/IwiTypes.h" #include "Image/Texture.h" #include #include +#include namespace image { - std::unique_ptr LoadIwi(std::istream& stream); + struct IwiLoaderResult + { + IwiVersion m_version; + CommonIwiMetaData m_meta; + std::unique_ptr m_texture; + }; + + std::optional LoadIwi(std::istream& stream); }; // namespace image diff --git a/src/ObjImage/Image/IwiTypes.h b/src/ObjImage/Image/IwiTypes.h index 37eb04e9..2a26974f 100644 --- a/src/ObjImage/Image/IwiTypes.h +++ b/src/ObjImage/Image/IwiTypes.h @@ -16,6 +16,18 @@ namespace image IWI_27 = 27 }; + struct CommonIwiMetaData + { + // Always high resolution + bool m_no_picmip; + bool m_streaming; + bool m_clamp_u; + bool m_clamp_v; + bool m_dynamic; + + float m_gamma; + }; + struct IwiVersionHeader { char tag[3]; diff --git a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp index 4052f23c..913d7d3b 100644 --- a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp +++ b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp @@ -4,8 +4,8 @@ #include "Game/IW3/AssetMarkerIW3.h" #include "Game/IW3/GameIW3.h" #include "Game/IW3/IW3.h" +#include "Game/IW3/Image/ImageLoaderExternalIW3.h" #include "Game/IW3/XModel/LoaderXModelIW3.h" -#include "Image/AssetLoaderImageIW3.h" #include "Localize/AssetLoaderLocalizeIW3.h" #include "Material/LoaderMaterialIW3.h" #include "ObjLoading.h" @@ -95,7 +95,7 @@ namespace collection.AddAssetCreator(xmodel::CreateLoaderIW3(memory, searchPath, zone)); collection.AddAssetCreator(material::CreateLoaderIW3(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); - collection.AddAssetCreator(image::CreateLoaderIW3(memory, searchPath)); + collection.AddAssetCreator(image::CreateLoaderExternalIW3(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp index 5558b40a..c4b6e94b 100644 --- a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp +++ b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp @@ -4,6 +4,7 @@ #include "Game/IW4/AssetMarkerIW4.h" #include "Game/IW4/GameIW4.h" #include "Game/IW4/IW4.h" +#include "Game/IW4/Image/ImageLoaderExternalIW4.h" #include "Game/IW4/XModel/LoaderXModelIW4.h" #include "Leaderboard/LoaderLeaderboardIW4.h" #include "LightDef/LightDefLoaderIW4.h" @@ -130,7 +131,7 @@ namespace collection.AddAssetCreator(shader::CreatePixelShaderLoaderIW4(memory, searchPath)); collection.AddAssetCreator(shader::CreateVertexShaderLoaderIW4(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); - // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(image::CreateLoaderExternalIW4(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(sound_curve::CreateLoaderIW4(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp b/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp deleted file mode 100644 index d51d670b..00000000 --- a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "LoaderImageIW5.h" - -#include "Game/IW5/IW5.h" -#include "Image/ImageCommon.h" -#include "Image/IwiLoader.h" -#include "Utils/Logging/Log.h" - -#include -#include -#include -#include - -using namespace IW5; - -namespace -{ - constexpr auto MAX_IMAGE_NAME_SIZE = 0x800; - - class ImageLoader final : public AssetCreator - { - public: - ImageLoader(MemoryManager& memory, ISearchPath& searchPath) - : m_memory(memory), - m_search_path(searchPath) - { - } - - AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override - { - const auto fileName = image::GetFileNameForAsset(assetName, ".iwi"); - const auto file = m_search_path.Open(fileName); - if (!file.IsOpen()) - return AssetCreationResult::NoAction(); - - const auto fileSize = static_cast(file.m_length); - const auto fileData = std::make_unique(fileSize); - file.m_stream->read(fileData.get(), fileSize); - - std::istringstream ss(std::string(fileData.get(), fileSize)); - const auto texture = image::LoadIwi(ss); - if (!texture) - { - con::error("Failed to load texture from: {}", fileName); - return AssetCreationResult::Failure(); - } - - auto* image = m_memory.Alloc(); - image->name = m_memory.Dup(assetName.c_str()); - image->noPicmip = !texture->HasMipMaps(); - image->width = static_cast(texture->GetWidth()); - image->height = static_cast(texture->GetHeight()); - image->depth = static_cast(texture->GetDepth()); - - image->texture.loadDef = m_memory.Alloc(); - - return AssetCreationResult::Success(context.AddAsset(assetName, image)); - } - - private: - MemoryManager& m_memory; - ISearchPath& m_search_path; - }; -} // namespace - -namespace image -{ - std::unique_ptr> CreateLoaderIW5(MemoryManager& memory, ISearchPath& searchPath) - { - return std::make_unique(memory, searchPath); - } -} // namespace image diff --git a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.h b/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.h deleted file mode 100644 index b95a8f23..00000000 --- a/src/ObjLoading/Game/IW5/Image/LoaderImageIW5.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Game/IW5/IW5.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace image -{ - std::unique_ptr> CreateLoaderIW5(MemoryManager& memory, ISearchPath& searchPath); -} // namespace image diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp index 70079f7b..55b1f684 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -4,8 +4,8 @@ #include "Game/IW5/AssetMarkerIW5.h" #include "Game/IW5/GameIW5.h" #include "Game/IW5/IW5.h" +#include "Game/IW5/Image/ImageLoaderExternalIW5.h" #include "Game/IW5/XModel/LoaderXModelIW5.h" -#include "Image/LoaderImageIW5.h" #include "Leaderboard/LoaderLeaderboardIW5.h" #include "Localize/LoaderLocalizeIW5.h" #include "Material/LoaderMaterialIW5.h" @@ -132,7 +132,7 @@ namespace // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); - collection.AddAssetCreator(image::CreateLoaderIW5(memory, searchPath)); + collection.AddAssetCreator(image::CreateLoaderExternalIW5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp index e8cff138..b897b567 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp @@ -3,6 +3,7 @@ #include "Asset/GlobalAssetPoolsLoader.h" #include "Game/T5/AssetMarkerT5.h" #include "Game/T5/GameT5.h" +#include "Game/T5/Image/ImageLoaderExternalT5.h" #include "Game/T5/T5.h" #include "Game/T5/XModel/LoaderXModelT5.h" #include "Localize/LoaderLocalizeT5.h" @@ -108,7 +109,7 @@ namespace collection.AddAssetCreator(xmodel::CreateLoaderT5(memory, searchPath, zone)); collection.AddAssetCreator(material::CreateLoaderT5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); - // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(image::CreateLoaderExternalT5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/T6/Image/LoaderImageT6.cpp b/src/ObjLoading/Game/T6/Image/LoaderImageT6.cpp deleted file mode 100644 index 81ffbf7c..00000000 --- a/src/ObjLoading/Game/T6/Image/LoaderImageT6.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "LoaderImageT6.h" - -#include "Game/T6/CommonT6.h" -#include "Game/T6/T6.h" -#include "Image/ImageCommon.h" -#include "Image/IwiLoader.h" -#include "Utils/Logging/Log.h" - -#include -#include -#include -#include -#include - -using namespace T6; - -namespace -{ - class ImageLoader final : public AssetCreator - { - public: - ImageLoader(MemoryManager& memory, ISearchPath& searchPath) - : m_memory(memory), - m_search_path(searchPath) - { - } - - AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override - { - const auto fileName = image::GetFileNameForAsset(assetName, ".iwi"); - const auto file = m_search_path.Open(fileName); - if (!file.IsOpen()) - return AssetCreationResult::NoAction(); - - const auto fileSize = static_cast(file.m_length); - const auto fileData = std::make_unique(fileSize); - file.m_stream->read(fileData.get(), static_cast(fileSize)); - const auto dataHash = static_cast(crc32(0u, reinterpret_cast(fileData.get()), static_cast(fileSize))); - - std::istringstream ss(std::string(fileData.get(), fileSize)); - const auto texture = image::LoadIwi(ss); - if (!texture) - { - con::error("Failed to load texture from: {}", fileName); - return AssetCreationResult::Failure(); - } - - auto* image = m_memory.Alloc(); - image->name = m_memory.Dup(assetName.c_str()); - image->hash = Common::R_HashString(image->name, 0); - image->delayLoadPixels = true; - - image->noPicmip = !texture->HasMipMaps(); - image->width = static_cast(texture->GetWidth()); - image->height = static_cast(texture->GetHeight()); - image->depth = static_cast(texture->GetDepth()); - - image->streaming = 1; - image->streamedParts[0].levelCount = 1; - image->streamedParts[0].levelSize = static_cast(fileSize); - image->streamedParts[0].hash = dataHash & 0x1FFFFFFF; - image->streamedPartCount = 1; - - return AssetCreationResult::Success(context.AddAsset(assetName, image)); - } - - private: - MemoryManager& m_memory; - ISearchPath& m_search_path; - }; -} // namespace - -namespace image -{ - std::unique_ptr> CreateLoaderT6(MemoryManager& memory, ISearchPath& searchPath) - { - return std::make_unique(memory, searchPath); - } -} // namespace image diff --git a/src/ObjLoading/Game/T6/Image/LoaderImageT6.h b/src/ObjLoading/Game/T6/Image/LoaderImageT6.h deleted file mode 100644 index 610af102..00000000 --- a/src/ObjLoading/Game/T6/Image/LoaderImageT6.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Game/T6/T6.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace image -{ - std::unique_ptr> CreateLoaderT6(MemoryManager& memory, ISearchPath& searchPath); -} // namespace image diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index a7df0b3f..716f5406 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -7,12 +7,12 @@ #include "Game/T6/CommonT6.h" #include "Game/T6/GameAssetPoolT6.h" #include "Game/T6/GameT6.h" +#include "Game/T6/Image/ImageLoaderExternalT6.h" #include "Game/T6/T6.h" #include "Game/T6/XModel/LoaderXModelT6.h" #include "Image/Dx12TextureLoader.h" #include "Image/IwiLoader.h" #include "Image/IwiTypes.h" -#include "Image/LoaderImageT6.h" #include "Image/Texture.h" #include "Leaderboard/JsonLoaderLeaderboardT6.h" #include "Localize/LocalizeLoaderT6.h" @@ -394,7 +394,7 @@ namespace T6 collection.AddAssetCreator(xmodel::CreateLoaderT6(memory, searchPath, zone)); collection.AddAssetCreator(material::CreateLoaderT6(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); - collection.AddAssetCreator(image::CreateLoaderT6(memory, searchPath)); + collection.AddAssetCreator(image::CreateLoaderExternalT6(memory, searchPath)); collection.AddAssetCreator(sound::CreateSoundBankLoaderT6(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Image/ImageLoaderCommon.cpp b/src/ObjLoading/Image/ImageLoaderCommon.cpp index 6f0c3339..569b964b 100644 --- a/src/ObjLoading/Image/ImageLoaderCommon.cpp +++ b/src/ObjLoading/Image/ImageLoaderCommon.cpp @@ -1,5 +1,43 @@ #include "ImageLoaderCommon.h" +#include "Image/ImageCommon.h" +#include "Image/IwiLoader.h" +#include "Image/Texture.h" +#include "Utils/Logging/Log.h" + +#include +#include + +using namespace image; + +namespace +{ + CommonImageLoaderResult Success(size_t iwiSize, CommonIwiMetaData meta, std::unique_ptr texture, CommonImageLoaderHash hash) + { + return CommonImageLoaderResult{ + .m_failure = false, + .m_iwi_size = iwiSize, + .m_meta = meta, + .m_texture = std::move(texture), + .m_hash = hash, + }; + } + + CommonImageLoaderResult NoAction() + { + return CommonImageLoaderResult{ + .m_failure = false, + }; + } + + CommonImageLoaderResult Failure() + { + return CommonImageLoaderResult{ + .m_failure = true, + }; + } +} // namespace + namespace image { std::optional CommonImageLoaderResult::GetResultIfCancelled() const @@ -12,4 +50,40 @@ namespace image return std::nullopt; } + + CommonImageLoaderResult + LoadImageCommon(const std::string& imageName, ISearchPath& searchPath, IwiVersion expectedIwiVersion, CommonImageLoaderHashType hashType) + { + const auto fileName = image::GetFileNameForAsset(imageName, ".iwi"); + const auto file = searchPath.Open(fileName); + if (!file.IsOpen()) + return NoAction(); + + const auto fileSize = static_cast(file.m_length); + + std::optional loaderResult; + CommonImageLoaderHash hash{}; + if (hashType == CommonImageLoaderHashType::NONE) + { + loaderResult = image::LoadIwi(*file.m_stream); + } + else + { + const auto fileData = std::make_unique(fileSize); + file.m_stream->read(fileData.get(), static_cast(fileSize)); + + hash.crc32 = static_cast(crc32(0u, reinterpret_cast(fileData.get()), static_cast(fileSize))); + + std::istringstream inMemory(std::string(fileData.get(), fileSize)); + loaderResult = image::LoadIwi(inMemory); + } + + if (!loaderResult) + { + con::error("Failed to load texture from: {}", fileName); + return Failure(); + } + + return Success(fileSize, loaderResult->m_meta, std::move(loaderResult->m_texture), hash); + } } // namespace image diff --git a/src/ObjLoading/Image/ImageLoaderCommon.h b/src/ObjLoading/Image/ImageLoaderCommon.h index 57744ae2..a4214603 100644 --- a/src/ObjLoading/Image/ImageLoaderCommon.h +++ b/src/ObjLoading/Image/ImageLoaderCommon.h @@ -3,21 +3,37 @@ #include "Asset/AssetCreationResult.h" #include "Image/IwiTypes.h" #include "Image/Texture.h" +#include "SearchPath/ISearchPath.h" +#include #include #include #include namespace image { + enum class CommonImageLoaderHashType + { + NONE, + CRC32 + }; + + union CommonImageLoaderHash + { + uint32_t crc32; + }; + struct CommonImageLoaderResult { std::optional GetResultIfCancelled() const; bool m_failure; - std::string m_iwi_path; + size_t m_iwi_size; + CommonIwiMetaData m_meta; std::unique_ptr m_texture; + CommonImageLoaderHash m_hash; }; - CommonImageLoaderResult LoadImageCommon(); + CommonImageLoaderResult + LoadImageCommon(const std::string& imageName, ISearchPath& searchPath, IwiVersion expectedIwiVersion, CommonImageLoaderHashType hashType); } // namespace image diff --git a/src/ObjLoading/Image/ImageLoaderExternal.cpp.template b/src/ObjLoading/Image/ImageLoaderExternal.cpp.template new file mode 100644 index 00000000..81321baf --- /dev/null +++ b/src/ObjLoading/Image/ImageLoaderExternal.cpp.template @@ -0,0 +1,111 @@ +#options GAME (IW3, IW4, IW5, T5, T6) + +#filename "Game/" + GAME + "/Image/ImageLoaderExternal" + GAME + ".cpp" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +#if defined(FEATURE_IW3) +#define IWI_VERSION IWI_6 +#elif defined(FEATURE_IW4) || defined(FEATURE_IW5) +#define IWI_VERSION IWI_8 +#elif defined(FEATURE_T5) +#define IWI_VERSION IWI_13 +#elif defined(FEATURE_T6) +#define IWI_VERSION IWI_27 +#endif + +#if defined(FEATURE_T6) +#define HASH_TYPE CRC32 +#else +#define HASH_TYPE NONE +#endif + + +// This file was templated. +// See ImageLoaderExternal.cpp.template. +// Do not modify, changes will be lost. + +#set LOADER_HEADER "\"ImageLoaderExternal" + GAME + ".h\"" +#include LOADER_HEADER + +#set COMMON_HEADER "\"Game/" + GAME + "/Common" + GAME + ".h\"" +#include COMMON_HEADER +#include "Image/ImageLoaderCommon.h" +#include "Utils/Logging/Log.h" + +#include + +using namespace GAME; +using namespace image; + +namespace +{ +#set LOADER_CLASS "ImageLoader" + GAME + class LOADER_CLASS final : public AssetCreator + { + public: + LOADER_CLASS(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto loadingResult = LoadImageCommon(assetName, m_search_path, IwiVersion::IWI_VERSION, CommonImageLoaderHashType::HASH_TYPE); + const auto earlyReturn = loadingResult.GetResultIfCancelled(); + if (earlyReturn) + return *earlyReturn; + + const auto* texture = loadingResult.m_texture.get(); + + auto* image = m_memory.Alloc(); + image->name = m_memory.Dup(assetName.c_str()); +#ifdef FEATURE_t6 + image->hash = Common::R_HashString(image->name, 0); +#endif +#ifndef FEATURE_IW5 + image->delayLoadPixels = true; +#endif + + image->noPicmip = loadingResult.m_meta.m_no_picmip; + image->width = static_cast(texture->GetWidth()); + image->height = static_cast(texture->GetHeight()); + image->depth = static_cast(texture->GetDepth()); + +#ifdef FEATURE_T6 + image->streaming = 1; + image->streamedParts[0].levelCount = 1; + image->streamedParts[0].levelSize = static_cast(loadingResult.m_iwi_size); + image->streamedParts[0].hash = loadingResult.m_hash.crc32 & 0x1FFFFFFF; + image->streamedPartCount = 1; +#endif + + image->texture.loadDef = m_memory.Alloc(); + + return AssetCreationResult::Success(context.AddAsset(assetName, image)); + } + + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace image +{ +#set LOADER_METHOD "CreateLoaderExternal" + GAME + std::unique_ptr> LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace image diff --git a/src/ObjLoading/Image/ImageLoaderExternal.h.template b/src/ObjLoading/Image/ImageLoaderExternal.h.template new file mode 100644 index 00000000..860619bd --- /dev/null +++ b/src/ObjLoading/Image/ImageLoaderExternal.h.template @@ -0,0 +1,23 @@ +#options GAME (IW3, IW4, IW5, T5, T6) + +#filename "Game/" + GAME + "/Image/ImageLoaderExternal" + GAME + ".h" + +// This file was templated. +// See ImageLoaderExternal.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Asset/IAssetCreator.h" +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" +#include GAME_HEADER +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace image +{ +#set LOADER_METHOD "CreateLoaderExternal" + GAME + std::unique_ptr> LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath); +} // namespace image diff --git a/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.cpp b/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.cpp index 3e9d81f9..f73d88d7 100644 --- a/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.cpp +++ b/src/ObjWriting/Game/IW3/Image/ImageDumperIW3.cpp @@ -49,7 +49,8 @@ namespace return nullptr; } - return image::LoadIwi(*filePathImage.m_stream); + auto loadResult = image::LoadIwi(*filePathImage.m_stream); + return loadResult ? std::move(loadResult->m_texture) : nullptr; } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.cpp b/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.cpp index 1327e43a..e52aacd3 100644 --- a/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.cpp +++ b/src/ObjWriting/Game/IW4/Image/ImageDumperIW4.cpp @@ -46,7 +46,8 @@ namespace return nullptr; } - return image::LoadIwi(*filePathImage.m_stream); + auto loadResult = image::LoadIwi(*filePathImage.m_stream); + return loadResult ? std::move(loadResult->m_texture) : nullptr; } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.cpp b/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.cpp index 71f2f69e..74995f30 100644 --- a/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.cpp +++ b/src/ObjWriting/Game/IW5/Image/ImageDumperIW5.cpp @@ -47,7 +47,8 @@ namespace return nullptr; } - return image::LoadIwi(*filePathImage.m_stream); + auto loadResult = image::LoadIwi(*filePathImage.m_stream); + return loadResult ? std::move(loadResult->m_texture) : nullptr; } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/T5/Image/ImageDumperT5.cpp b/src/ObjWriting/Game/T5/Image/ImageDumperT5.cpp index 88a9cdd8..2f0e0649 100644 --- a/src/ObjWriting/Game/T5/Image/ImageDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Image/ImageDumperT5.cpp @@ -46,7 +46,8 @@ namespace return nullptr; } - return image::LoadIwi(*filePathImage.m_stream); + auto loadResult = image::LoadIwi(*filePathImage.m_stream); + return loadResult ? std::move(loadResult->m_texture) : nullptr; } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) diff --git a/src/ObjWriting/Game/T6/Image/ImageDumperT6.cpp b/src/ObjWriting/Game/T6/Image/ImageDumperT6.cpp index 29b64061..61914b4a 100644 --- a/src/ObjWriting/Game/T6/Image/ImageDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Image/ImageDumperT6.cpp @@ -47,11 +47,11 @@ namespace if (ipakStream) { - auto loadedTexture = image::LoadIwi(*ipakStream); + auto loadResult = image::LoadIwi(*ipakStream); ipakStream->close(); - if (loadedTexture != nullptr) - return loadedTexture; + if (loadResult) + return std::move(loadResult->m_texture); } } } @@ -64,7 +64,8 @@ namespace return nullptr; } - return image::LoadIwi(*filePathImage.m_stream); + auto loadResult = image::LoadIwi(*filePathImage.m_stream); + return loadResult ? std::move(loadResult->m_texture) : nullptr; } std::unique_ptr LoadImageData(ISearchPath& searchPath, const GfxImage& image) From 4cdccba01607314d63b4fb375b622096f9477891 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 4 Jan 2026 13:43:29 +0100 Subject: [PATCH 3/5] feat: add embedded image loader for every supported game --- src/Common/Game/IW3/IW3_Assets.h | 3 +- src/Common/Game/IW4/IW4_Assets.h | 25 ++++++ src/Common/Game/IW5/IW5_Assets.h | 59 +++++++++---- src/Common/Game/T5/T5_Assets.h | 12 +++ src/Common/Game/T6/T6_Assets.h | 12 +++ .../Game/IW3/Image/AssetLoaderImageIW3.h | 13 --- src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp | 2 + src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp | 2 + src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp | 2 + src/ObjLoading/Game/T5/ObjLoaderT5.cpp | 2 + src/ObjLoading/Game/T6/ObjLoaderT6.cpp | 2 + .../ImageLoaderEmbedded.cpp.template} | 84 ++++++++++++++----- .../Image/ImageLoaderEmbedded.h.template | 23 +++++ 13 files changed, 191 insertions(+), 50 deletions(-) delete mode 100644 src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.h rename src/ObjLoading/{Game/IW3/Image/AssetLoaderImageIW3.cpp => Image/ImageLoaderEmbedded.cpp.template} (66%) create mode 100644 src/ObjLoading/Image/ImageLoaderEmbedded.h.template diff --git a/src/Common/Game/IW3/IW3_Assets.h b/src/Common/Game/IW3/IW3_Assets.h index eb25545d..596ed16c 100644 --- a/src/Common/Game/IW3/IW3_Assets.h +++ b/src/Common/Game/IW3/IW3_Assets.h @@ -1515,7 +1515,8 @@ namespace IW3 MAPTYPE_2D = 0x3, MAPTYPE_3D = 0x4, MAPTYPE_CUBE = 0x5, - MAPTYPE_COUNT = 0x6, + + MAPTYPE_COUNT }; enum TextureSemantic diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index 398f0f77..c06c59f7 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -1181,6 +1181,18 @@ namespace IW4 int platform[2]; }; + enum MapType + { + MAPTYPE_NONE = 0x0, + MAPTYPE_INVALID1 = 0x1, + MAPTYPE_1D = 0x2, + MAPTYPE_2D = 0x3, + MAPTYPE_3D = 0x4, + MAPTYPE_CUBE = 0x5, + + MAPTYPE_COUNT + }; + enum TextureSemantic { TS_2D = 0x0, @@ -1197,6 +1209,19 @@ namespace IW4 TS_WATER_MAP = 0xB, }; + enum ImageCategory + { + IMG_CATEGORY_UNKNOWN = 0x0, + IMG_CATEGORY_AUTO_GENERATED = 0x1, + IMG_CATEGORY_LIGHTMAP = 0x2, + IMG_CATEGORY_LOAD_FROM_FILE = 0x3, + IMG_CATEGORY_RAW = 0x4, + IMG_CATEGORY_FIRST_UNMANAGED = 0x5, + IMG_CATEGORY_WATER = 0x5, + IMG_CATEGORY_RENDERTARGET = 0x6, + IMG_CATEGORY_TEMP = 0x7, + }; + struct GfxImage { GfxTexture texture; diff --git a/src/Common/Game/IW5/IW5_Assets.h b/src/Common/Game/IW5/IW5_Assets.h index cab9ab4f..befefc05 100644 --- a/src/Common/Game/IW5/IW5_Assets.h +++ b/src/Common/Game/IW5/IW5_Assets.h @@ -732,23 +732,6 @@ namespace IW5 GfxImage* image; }; - enum TextureSemantic - { - TS_2D = 0x0, - TS_FUNCTION = 0x1, - TS_COLOR_MAP = 0x2, - TS_DETAIL_MAP = 0x3, - TS_UNUSED_2 = 0x4, - TS_NORMAL_MAP = 0x5, - TS_UNUSED_3 = 0x6, - TS_UNUSED_4 = 0x7, - TS_SPECULAR_MAP = 0x8, - TS_UNUSED_5 = 0x9, - TS_UNUSED_6 = 0xA, - TS_WATER_MAP = 0xB, - TS_DISPLACEMENT_MAP = 0xC - }; - union MaterialTextureDefInfo { GfxImage* image; @@ -1157,6 +1140,48 @@ namespace IW5 int platform[2]; }; + enum MapType + { + MAPTYPE_NONE = 0x0, + MAPTYPE_INVALID1 = 0x1, + MAPTYPE_1D = 0x2, + MAPTYPE_2D = 0x3, + MAPTYPE_3D = 0x4, + MAPTYPE_CUBE = 0x5, + + MAPTYPE_COUNT + }; + + enum TextureSemantic + { + TS_2D = 0x0, + TS_FUNCTION = 0x1, + TS_COLOR_MAP = 0x2, + TS_DETAIL_MAP = 0x3, + TS_UNUSED_2 = 0x4, + TS_NORMAL_MAP = 0x5, + TS_UNUSED_3 = 0x6, + TS_UNUSED_4 = 0x7, + TS_SPECULAR_MAP = 0x8, + TS_UNUSED_5 = 0x9, + TS_UNUSED_6 = 0xA, + TS_WATER_MAP = 0xB, + TS_DISPLACEMENT_MAP = 0xC + }; + + enum ImageCategory + { + IMG_CATEGORY_UNKNOWN = 0x0, + IMG_CATEGORY_AUTO_GENERATED = 0x1, + IMG_CATEGORY_LIGHTMAP = 0x2, + IMG_CATEGORY_LOAD_FROM_FILE = 0x3, + IMG_CATEGORY_RAW = 0x4, + IMG_CATEGORY_FIRST_UNMANAGED = 0x5, + IMG_CATEGORY_WATER = 0x5, + IMG_CATEGORY_RENDERTARGET = 0x6, + IMG_CATEGORY_TEMP = 0x7, + }; + struct GfxImage { GfxTexture texture; diff --git a/src/Common/Game/T5/T5_Assets.h b/src/Common/Game/T5/T5_Assets.h index d06015db..d6c01e01 100644 --- a/src/Common/Game/T5/T5_Assets.h +++ b/src/Common/Game/T5/T5_Assets.h @@ -1242,6 +1242,18 @@ namespace T5 int platform[2]; }; + enum MapType + { + MAPTYPE_NONE = 0x0, + MAPTYPE_INVALID1 = 0x1, + MAPTYPE_INVALID2 = 0x2, + MAPTYPE_2D = 0x3, + MAPTYPE_3D = 0x4, + MAPTYPE_CUBE = 0x5, + + MAPTYPE_COUNT + }; + enum TextureSemantic { TS_2D = 0x0, diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 6368cf98..9b0a102d 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -879,6 +879,18 @@ namespace T6 uint32_t valid : 1; }; + enum MapType + { + MAPTYPE_NONE = 0x0, + MAPTYPE_INVALID1 = 0x1, + MAPTYPE_INVALID2 = 0x2, + MAPTYPE_2D = 0x3, + MAPTYPE_3D = 0x4, + MAPTYPE_CUBE = 0x5, + + MAPTYPE_COUNT + }; + enum TextureSemantic { TS_2D = 0x0, diff --git a/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.h b/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.h deleted file mode 100644 index b8d60124..00000000 --- a/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Game/IW3/IW3.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace image -{ - std::unique_ptr> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath); -} // namespace image diff --git a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp index 913d7d3b..3d77d604 100644 --- a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp +++ b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp @@ -4,6 +4,7 @@ #include "Game/IW3/AssetMarkerIW3.h" #include "Game/IW3/GameIW3.h" #include "Game/IW3/IW3.h" +#include "Game/IW3/Image/ImageLoaderEmbeddedIW3.h" #include "Game/IW3/Image/ImageLoaderExternalIW3.h" #include "Game/IW3/XModel/LoaderXModelIW3.h" #include "Localize/AssetLoaderLocalizeIW3.h" @@ -95,6 +96,7 @@ namespace collection.AddAssetCreator(xmodel::CreateLoaderIW3(memory, searchPath, zone)); collection.AddAssetCreator(material::CreateLoaderIW3(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(image::CreateLoaderEmbeddedIW3(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalIW3(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp index c4b6e94b..8d5899a2 100644 --- a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp +++ b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp @@ -4,6 +4,7 @@ #include "Game/IW4/AssetMarkerIW4.h" #include "Game/IW4/GameIW4.h" #include "Game/IW4/IW4.h" +#include "Game/IW4/Image/ImageLoaderEmbeddedIW4.h" #include "Game/IW4/Image/ImageLoaderExternalIW4.h" #include "Game/IW4/XModel/LoaderXModelIW4.h" #include "Leaderboard/LoaderLeaderboardIW4.h" @@ -131,6 +132,7 @@ namespace collection.AddAssetCreator(shader::CreatePixelShaderLoaderIW4(memory, searchPath)); collection.AddAssetCreator(shader::CreateVertexShaderLoaderIW4(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(image::CreateLoaderEmbeddedIW4(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalIW4(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(sound_curve::CreateLoaderIW4(memory, searchPath)); diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp index 55b1f684..439d1b0c 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -4,6 +4,7 @@ #include "Game/IW5/AssetMarkerIW5.h" #include "Game/IW5/GameIW5.h" #include "Game/IW5/IW5.h" +#include "Game/IW5/Image/ImageLoaderEmbeddedIW5.h" #include "Game/IW5/Image/ImageLoaderExternalIW5.h" #include "Game/IW5/XModel/LoaderXModelIW5.h" #include "Leaderboard/LoaderLeaderboardIW5.h" @@ -132,6 +133,7 @@ namespace // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(image::CreateLoaderEmbeddedIW5(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalIW5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp index b897b567..01d22d5f 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp @@ -3,6 +3,7 @@ #include "Asset/GlobalAssetPoolsLoader.h" #include "Game/T5/AssetMarkerT5.h" #include "Game/T5/GameT5.h" +#include "Game/T5/Image/ImageLoaderEmbeddedT5.h" #include "Game/T5/Image/ImageLoaderExternalT5.h" #include "Game/T5/T5.h" #include "Game/T5/XModel/LoaderXModelT5.h" @@ -109,6 +110,7 @@ namespace collection.AddAssetCreator(xmodel::CreateLoaderT5(memory, searchPath, zone)); collection.AddAssetCreator(material::CreateLoaderT5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(image::CreateLoaderEmbeddedT5(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalT5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 716f5406..b9747017 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -7,6 +7,7 @@ #include "Game/T6/CommonT6.h" #include "Game/T6/GameAssetPoolT6.h" #include "Game/T6/GameT6.h" +#include "Game/T6/Image/ImageLoaderEmbeddedT6.h" #include "Game/T6/Image/ImageLoaderExternalT6.h" #include "Game/T6/T6.h" #include "Game/T6/XModel/LoaderXModelT6.h" @@ -394,6 +395,7 @@ namespace T6 collection.AddAssetCreator(xmodel::CreateLoaderT6(memory, searchPath, zone)); collection.AddAssetCreator(material::CreateLoaderT6(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(image::CreateLoaderEmbeddedT6(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalT6(memory, searchPath)); collection.AddAssetCreator(sound::CreateSoundBankLoaderT6(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp b/src/ObjLoading/Image/ImageLoaderEmbedded.cpp.template similarity index 66% rename from src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp rename to src/ObjLoading/Image/ImageLoaderEmbedded.cpp.template index d8ceb88f..9541e0fc 100644 --- a/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp +++ b/src/ObjLoading/Image/ImageLoaderEmbedded.cpp.template @@ -1,25 +1,64 @@ -#include "AssetLoaderImageIW3.h" +#options GAME (IW3, IW4, IW5, T5, T6) -#include "Game/IW3/IW3.h" +#filename "Game/" + GAME + "/Image/ImageLoaderEmbedded" + GAME + ".cpp" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +#if defined(FEATURE_IW3) +#define IWI_NS iwi6 +#define FLAG_CUBE IMG_FLAG_CUBEMAP +#define FLAG_3D IMG_FLAG_VOLMAP +#elif defined(FEATURE_IW4) || defined(FEATURE_IW5) +#define IWI_NS iwi8 +#define FLAG_CUBE IMG_FLAG_MAPTYPE_CUBE +#define FLAG_3D IMG_FLAG_MAPTYPE_3D +#elif defined(FEATURE_T5) +#define IWI_NS iwi13 +#define FLAG_CUBE IMG_FLAG_CUBEMAP +#define FLAG_3D IMG_FLAG_VOLMAP +#elif defined(FEATURE_T6) +#define IWI_NS iwi27 +#define FLAG_CUBE IMG_FLAG_CUBEMAP +#define FLAG_3D IMG_FLAG_VOLMAP +#endif + + +// This file was templated. +// See ImageLoaderEmbedded.cpp.template. +// Do not modify, changes will be lost. + +#set LOADER_HEADER "\"ImageLoaderEmbedded" + GAME + ".h\"" +#include LOADER_HEADER + +#set COMMON_HEADER "\"Game/" + GAME + "/Common" + GAME + ".h\"" +#include COMMON_HEADER #include "Image/DdsLoader.h" +#include "Image/ImageCommon.h" #include "Image/IwiTypes.h" -#include "Pool/GlobalAssetPool.h" #include "Utils/Logging/Log.h" -#include #include -#include -#include -using namespace IW3; +using namespace GAME; using namespace image; namespace { - class ImageLoader final : public AssetCreator +#set LOADER_CLASS "ImageLoader" + GAME + class LOADER_CLASS final : public AssetCreator { public: - ImageLoader(MemoryManager& memory, ISearchPath& searchPath) + LOADER_CLASS(MemoryManager& memory, ISearchPath& searchPath) : m_memory(memory), m_search_path(searchPath) { @@ -32,10 +71,7 @@ namespace if (assetName.empty() || assetName[0] != '*') return AssetCreationResult::NoAction(); - std::string safeAssetName = assetName; - std::ranges::replace(safeAssetName, '*', '_'); - - const auto file = m_search_path.Open(std::format("images/{}.dds", safeAssetName)); + const auto file = m_search_path.Open(image::GetFileNameForAsset(assetName, ".dds")); if (!file.IsOpen()) return AssetCreationResult::NoAction(); @@ -59,7 +95,9 @@ namespace image->height = static_cast(texture->GetHeight()); image->depth = static_cast(texture->GetDepth()); image->category = IMG_CATEGORY_AUTO_GENERATED; +#ifndef FEATURE_IW5 image->delayLoadPixels = false; +#endif switch (texture->GetTextureType()) { @@ -92,15 +130,23 @@ namespace loadDef->levelCount = static_cast(mipCount); loadDef->flags = 0; if (!texture->HasMipMaps()) - loadDef->flags |= image::iwi6::IMG_FLAG_NOMIPMAPS; + loadDef->flags |= IWI_NS::IMG_FLAG_NOMIPMAPS; if (texture->GetTextureType() == TextureType::T_CUBE) - loadDef->flags |= image::iwi6::IMG_FLAG_CUBEMAP; + loadDef->flags |= IWI_NS::FLAG_CUBE; if (texture->GetTextureType() == TextureType::T_3D) - loadDef->flags |= image::iwi6::IMG_FLAG_VOLMAP; + loadDef->flags |= IWI_NS::FLAG_3D; + +#if defined(FEATURE_IW3) loadDef->dimensions[0] = image->width; loadDef->dimensions[1] = image->height; loadDef->dimensions[2] = image->depth; +#endif + +#if defined(FEATURE_T6) + loadDef->format = static_cast(texture->GetFormat()->GetDxgiFormat()); +#else loadDef->format = static_cast(texture->GetFormat()->GetD3DFormat()); +#endif loadDef->resourceSize = static_cast(dataSize); char* currentDataBuffer = loadDef->data; @@ -118,7 +164,6 @@ namespace return AssetCreationResult::Success(context.AddAsset(assetName, image)); } - private: MemoryManager& m_memory; ISearchPath& m_search_path; }; @@ -126,8 +171,9 @@ namespace namespace image { - std::unique_ptr> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath) +#set LOADER_METHOD "CreateLoaderEmbedded" + GAME + std::unique_ptr> LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath) { - return std::make_unique(memory, searchPath); + return std::make_unique(memory, searchPath); } } // namespace image diff --git a/src/ObjLoading/Image/ImageLoaderEmbedded.h.template b/src/ObjLoading/Image/ImageLoaderEmbedded.h.template new file mode 100644 index 00000000..627d9ccd --- /dev/null +++ b/src/ObjLoading/Image/ImageLoaderEmbedded.h.template @@ -0,0 +1,23 @@ +#options GAME (IW3, IW4, IW5, T5, T6) + +#filename "Game/" + GAME + "/Image/ImageLoaderEmbedded" + GAME + ".h" + +// This file was templated. +// See ImageLoaderEmbedded.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Asset/IAssetCreator.h" +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" +#include GAME_HEADER +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace image +{ +#set LOADER_METHOD "CreateLoaderEmbedded" + GAME + std::unique_ptr> LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath); +} // namespace image From c4a5856bfab0510a9d11a4dceee9d00d7e44ae94 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 4 Jan 2026 23:50:38 +0100 Subject: [PATCH 4/5] chore: add tests for templated image loader --- test/ObjLoadingTests.lua | 1 + .../IW3/Image/ImageLoaderEmbeddedIW3Test.cpp | 57 +++++++++++++++++ .../IW3/Image/ImageLoaderExternalIW3Test.cpp | 54 ++++++++++++++++ .../Game/IW3/Image/TestImage.dds | Bin 0 -> 2176 bytes .../Game/IW3/Image/TestImage.iwi | Bin 0 -> 2076 bytes .../IW4/Image/ImageLoaderEmbeddedIW4Test.cpp | 57 +++++++++++++++++ .../IW4/Image/ImageLoaderExternalIW4Test.cpp | 54 ++++++++++++++++ .../Game/IW4/Image/TestImage.dds | Bin 0 -> 2176 bytes .../Game/IW4/Image/TestImage.iwi | Bin 0 -> 2080 bytes .../IW5/Image/ImageLoaderEmbeddedIW5Test.cpp | 57 +++++++++++++++++ .../IW5/Image/ImageLoaderExternalIW5Test.cpp | 54 ++++++++++++++++ .../Game/IW5/Image/TestImage.dds | Bin 0 -> 2176 bytes .../Game/IW5/Image/TestImage.iwi | Bin 0 -> 2080 bytes .../T5/Image/ImageLoaderEmbeddedT5Test.cpp | 57 +++++++++++++++++ .../T5/Image/ImageLoaderExternalT5Test.cpp | 54 ++++++++++++++++ .../Game/T5/Image/TestImage.dds | Bin 0 -> 2176 bytes .../Game/T5/Image/TestImage.iwi | Bin 0 -> 2096 bytes .../T6/Image/ImageLoaderEmbeddedT6Test.cpp | 58 ++++++++++++++++++ .../T6/Image/ImageLoaderExternalT6Test.cpp | 57 +++++++++++++++++ .../Game/T6/Image/TestImage.dds | Bin 0 -> 2176 bytes .../Game/T6/Image/TestImage.iwi | Bin 0 -> 2112 bytes 21 files changed, 560 insertions(+) create mode 100644 test/ObjLoadingTests/Game/IW3/Image/ImageLoaderEmbeddedIW3Test.cpp create mode 100644 test/ObjLoadingTests/Game/IW3/Image/ImageLoaderExternalIW3Test.cpp create mode 100644 test/ObjLoadingTests/Game/IW3/Image/TestImage.dds create mode 100644 test/ObjLoadingTests/Game/IW3/Image/TestImage.iwi create mode 100644 test/ObjLoadingTests/Game/IW4/Image/ImageLoaderEmbeddedIW4Test.cpp create mode 100644 test/ObjLoadingTests/Game/IW4/Image/ImageLoaderExternalIW4Test.cpp create mode 100644 test/ObjLoadingTests/Game/IW4/Image/TestImage.dds create mode 100644 test/ObjLoadingTests/Game/IW4/Image/TestImage.iwi create mode 100644 test/ObjLoadingTests/Game/IW5/Image/ImageLoaderEmbeddedIW5Test.cpp create mode 100644 test/ObjLoadingTests/Game/IW5/Image/ImageLoaderExternalIW5Test.cpp create mode 100644 test/ObjLoadingTests/Game/IW5/Image/TestImage.dds create mode 100644 test/ObjLoadingTests/Game/IW5/Image/TestImage.iwi create mode 100644 test/ObjLoadingTests/Game/T5/Image/ImageLoaderEmbeddedT5Test.cpp create mode 100644 test/ObjLoadingTests/Game/T5/Image/ImageLoaderExternalT5Test.cpp create mode 100644 test/ObjLoadingTests/Game/T5/Image/TestImage.dds create mode 100644 test/ObjLoadingTests/Game/T5/Image/TestImage.iwi create mode 100644 test/ObjLoadingTests/Game/T6/Image/ImageLoaderEmbeddedT6Test.cpp create mode 100644 test/ObjLoadingTests/Game/T6/Image/ImageLoaderExternalT6Test.cpp create mode 100644 test/ObjLoadingTests/Game/T6/Image/TestImage.dds create mode 100644 test/ObjLoadingTests/Game/T6/Image/TestImage.iwi diff --git a/test/ObjLoadingTests.lua b/test/ObjLoadingTests.lua index 339ca606..3d315f41 100644 --- a/test/ObjLoadingTests.lua +++ b/test/ObjLoadingTests.lua @@ -3,6 +3,7 @@ ObjLoadingTests = {} function ObjLoadingTests:include(includes) if includes:handle(self:name()) then includedirs { + "%{wks.location}/src/ObjLoading", path.join(TestFolder(), "ObjLoadingTests") } end diff --git a/test/ObjLoadingTests/Game/IW3/Image/ImageLoaderEmbeddedIW3Test.cpp b/test/ObjLoadingTests/Game/IW3/Image/ImageLoaderEmbeddedIW3Test.cpp new file mode 100644 index 00000000..d479c727 --- /dev/null +++ b/test/ObjLoadingTests/Game/IW3/Image/ImageLoaderEmbeddedIW3Test.cpp @@ -0,0 +1,57 @@ +#include "Game/IW3/Image/ImageLoaderEmbeddedIW3.h" + +#include "Game/IW3/GameIW3.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace IW3; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderEmbeddedIW3: Can parse dds", "[iw3][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW3/Image/TestImage.dds"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderEmbeddedIW3(memory, searchPath); + auto result = loader->CreateAsset("*testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "*testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + + REQUIRE(image->texture.loadDef); + REQUIRE(image->texture.loadDef->resourceSize > 0); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/IW3/Image/ImageLoaderExternalIW3Test.cpp b/test/ObjLoadingTests/Game/IW3/Image/ImageLoaderExternalIW3Test.cpp new file mode 100644 index 00000000..4041f4b6 --- /dev/null +++ b/test/ObjLoadingTests/Game/IW3/Image/ImageLoaderExternalIW3Test.cpp @@ -0,0 +1,54 @@ +#include "Game/IW3/Image/ImageLoaderExternalIW3.h" + +#include "Game/IW3/GameIW3.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace IW3; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderExternalIW3: Can parse iwi", "[iw3][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW3/Image/TestImage.iwi"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderExternalIW3(memory, searchPath); + auto result = loader->CreateAsset("testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/IW3/Image/TestImage.dds b/test/ObjLoadingTests/Game/IW3/Image/TestImage.dds new file mode 100644 index 0000000000000000000000000000000000000000..8705ec9d32facb000f43cc9228952ee8fd07bc1d GIT binary patch literal 2176 zcmc&#L1^1%6#i|mtez_Hp`+Jc3~3WX3N{{ccQ5mX>x~nBeCF z{nC5id++=He`x5dvuQ%er=F99L!>K%%dx)@KKMC{Uw(pXXmsSlkw1C<{uc0|Z~t#J z?O=RS5`>Dq6e7LNU4U2fgfIrc7h6cras2#F#iR!9!_Bw>o8-y-*z0Y`n+XX_L8h~jZC$ArKbD=$RWY4s3#+%=}TmZv4UPxx{Xk|q!-tPn8RhOG( z{`nI{>YyIlyz3s-)>Li0FW&Mtk-ROPl_Hca=i=w>RXb5Z$?Syl{9^S`^k(C(fU$YKkcujcd0^TckC zU(GAf1i~XOPfu@)TV;h=HINVLg}B&v^FQpnHh*rWx)c(n8vehYV%-j$`+7>3#qe_o;zahm$c=kvZNKjlY85BSZ6bWYD) zEIk^i)z;1fJb3DG5^_sh3Z*4Us-O;EI2=CH&MW+QBg3op)VXKoVnX#~7ZQmQ#mLwg zGh45xcw>#B-!XqC#WR(Oz;9p}7W&!gcDrd@+RsZ5Cjxt6K{&|≶4&ocS+G<`ACD7gix)g2m3dX;CO^5|$g%@69-1XG1 z#vpE(v|j-Alq}29v3fA>|GbF2I(1Ct_1+*z}IG;OBvt*spu_A1++=7ma-%;~YD6eb{+pL0?QtFJL{WPaY5_+h{>B z?q!|Cw3j2vq$tw+#mBN;b@peYIw9$;?Js#jN?I@xU{PNd;5`Hw3BD;1#^*cW)8X}T zXkuP5+1R{?ePP?t@(Nk7vEEJ`Pd1AE0IY*=QCtdP8Hg(dA49S8-9N?JDu?l@FNJTn LF%?U}#Ka6{9EyvqLZqN`)5(JDUq; zhhPjVcA=1tT+Bj(JP2qVWpQ+B4+ZB?R1ZR>uuHZWTj`;-%j%(LNq8)8mi1 zn%eQpmhC$h-^}DqA*Q~xE1G2(fp_aWUB>nbKvGA2TsMGsn=wHX)O>4 z_yHW655a*)QL^1sEHDU$Nz7pIiCmjzL_>vIWm^NG9pJJ?fXwggF0ul0M?2uVfZ)s5CCo) zxEIXNUUX8HXK9{z-v6Hdlpncv$ZsKR3TF0v`QdQAzHtuV{u2*F$T!AHIHM>^6@B=Z z$HUuhK@%sNSy6AK&px%6lX_onDVZ!&j806j^NmJYv^H4!9{Wd1{=7OB{1q(A!8|iQ zpO4n1^Stn2DtHi)q{IF{x&j^moG;(&;OqG~n8!$Fo6OZh2^8G~=*zMDqB!3ej4v@D z&DAQ}xqjUMxKr~IFWwWVD{IE;>jh0#z@YoISnA)T?!~_J9Q`%FWlw98)$6a#G$Atb z>Ff=89^KFBa;(EEl=$uiAr4eDQF?)OH`DtDi@0Uec>y%is;b5&8lgnsvl8;^>X^x^ zS5hrhoI?8jch-)PE^}XnZ zW228z7hV*v^I;02{`Fb84edL%lOwvmihRfNSXZF;9^za4(wCFR$I&N4Iqt-X_w+Al z%k4>=-?T=U7Vf8iB$HAm0dvFoFJ7cPFxFQm8n_Rm6ac8Y9&G5qPs7h}UUwVce{nfb zvfktv_t@3-&+Z!s2IER*3H6{qML?YHpaY?VpJRyau0~TSS*G6?p5uCS4&`DdA(@@s zuS7{nIWQIE&|ePVcL=Z&+$a*3=MVXGdHp-Iv9FwJZr{bZaGh!ejV!sSw_B$#7sGh~ m>JZx$SHdU*ajnR+6ua;JSFEoKSfA!n`gRxV6*SA*Ag=)DXbyY; literal 0 HcmV?d00001 diff --git a/test/ObjLoadingTests/Game/IW4/Image/ImageLoaderEmbeddedIW4Test.cpp b/test/ObjLoadingTests/Game/IW4/Image/ImageLoaderEmbeddedIW4Test.cpp new file mode 100644 index 00000000..36e75618 --- /dev/null +++ b/test/ObjLoadingTests/Game/IW4/Image/ImageLoaderEmbeddedIW4Test.cpp @@ -0,0 +1,57 @@ +#include "Game/IW4/Image/ImageLoaderEmbeddedIW4.h" + +#include "Game/IW4/GameIW4.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace IW4; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderEmbeddedIW4: Can parse dds", "[iw4][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW4/Image/TestImage.dds"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderEmbeddedIW4(memory, searchPath); + auto result = loader->CreateAsset("*testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "*testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + + REQUIRE(image->texture.loadDef); + REQUIRE(image->texture.loadDef->resourceSize > 0); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/IW4/Image/ImageLoaderExternalIW4Test.cpp b/test/ObjLoadingTests/Game/IW4/Image/ImageLoaderExternalIW4Test.cpp new file mode 100644 index 00000000..93cccc16 --- /dev/null +++ b/test/ObjLoadingTests/Game/IW4/Image/ImageLoaderExternalIW4Test.cpp @@ -0,0 +1,54 @@ +#include "Game/IW4/Image/ImageLoaderExternalIW4.h" + +#include "Game/IW4/GameIW4.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace IW4; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderExternalIW4: Can parse iwi", "[iw4][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW4/Image/TestImage.iwi"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderExternalIW4(memory, searchPath); + auto result = loader->CreateAsset("testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/IW4/Image/TestImage.dds b/test/ObjLoadingTests/Game/IW4/Image/TestImage.dds new file mode 100644 index 0000000000000000000000000000000000000000..8705ec9d32facb000f43cc9228952ee8fd07bc1d GIT binary patch literal 2176 zcmc&#L1^1%6#i|mtez_Hp`+Jc3~3WX3N{{ccQ5mX>x~nBeCF z{nC5id++=He`x5dvuQ%er=F99L!>K%%dx)@KKMC{Uw(pXXmsSlkw1C<{uc0|Z~t#J z?O=RS5`>Dq6e7LNU4U2fgfIrc7h6cras2#F#iR!9!_Bw>o8-y-*z0Y`n+XX_L8h~jZC$ArKbD=$RWY4s3#+%=}TmZv4UPxx{Xk|q!-tPn8RhOG( z{`nI{>YyIlyz3s-)>Li0FW&Mtk-ROPl_Hca=i=w>RXb5Z$?Syl{9^S`^k(C(fU$YKkcujcd0^TckC zU(GAf1i~XOPfu@)TV;h=HINVLg}B&v^FQpnHh*rWx)c(n8vehYV%-j$`+7>3#qe_o;zahm$c=kvZNKjlY85BSZ6bWYD) zEIk^i)z;1fJb3DG5^_sh3Z*4Us-O;EI2=CH&MW+QBg3op)VXKoVnX#~7ZQmQ#mLwg zGh45xcw>#B-!XqC#WR(Oz;9p}7W&!gcDrd@+RsZ5Cjxt6K{&|≶4&ocS+G<`ACD7gix)g2m3dX;CO^5|$g%@69-1XG1 z#vpE(v|j-Alq}29v3fA>|GbF2I(1Ct_1+*z}IG;OBvt*spu_A1++=7ma-%;~YD6eb{+pL0?QtFJL{WPaY5_+h{>B z?q!|Cw3j2vq$tw+#mBN;b@peYIw9$;?Js#jN?I@xU{PNd;5`Hw3BD;1#^*cW)8X}T zXkuP5+1R{?ePP?t@(Nk7vEEJ`Pd1AE0IY*=QCtdP8Hg(dA49S8-9N?JDu?l@FNJTn LF^ny8XAg<|H{rBK8D}S zd*6HS``(O*lRa)i2t#H}?ZcJ030vgJ!sE#C`Ly)f8i@4+G;J8nlKy7`!1V$lZXLjKj*{1(x%tq( zHMVa#SK`g99uL51P7srs8+uvQi}wcr1kK}RnQz~hCkrHF@Yf5$c;Wot=V>07$K9om z*{agk%ckW$65UMa3_hy7w#urh>;4bdcd~@(Wq^c+h;zB8Bbr}37aLB*UMQC(fGO4Q z_xk{B>JQ$A#}TsCkk3BcjV!gG`EntzK2PlR`L(9OwH;e#(zrKHxVWGI%3%ru1m2R$D&}@ZhNn7sqe|9ie|UIHd2I0 z$frFw|a~PMWdk^tFdg;wdV`He3!7O|1*hli` z)uq-1_HRlh?k3KsZ#bQlCjfoJ`p%uBJkZvc#_Ko_z32z1I4(?R!=0fQ*sojlYd>D_ z7tMD*#yNKC`m}vx!$3?G1kIv@oxfY;4`azOe0Rd6g_WSZ^mzZ#Ihk n0IWl3QCtpT8HlR|j-l9j?@O_^#$$ZyOY!#|jF(qUbDg{a96Jtz literal 0 HcmV?d00001 diff --git a/test/ObjLoadingTests/Game/IW5/Image/ImageLoaderEmbeddedIW5Test.cpp b/test/ObjLoadingTests/Game/IW5/Image/ImageLoaderEmbeddedIW5Test.cpp new file mode 100644 index 00000000..647306db --- /dev/null +++ b/test/ObjLoadingTests/Game/IW5/Image/ImageLoaderEmbeddedIW5Test.cpp @@ -0,0 +1,57 @@ +#include "Game/IW5/Image/ImageLoaderEmbeddedIW5.h" + +#include "Game/IW5/GameIW5.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace IW5; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderEmbeddedIW5: Can parse dds", "[iw5][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW5/Image/TestImage.dds"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderEmbeddedIW5(memory, searchPath); + auto result = loader->CreateAsset("*testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "*testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + + REQUIRE(image->texture.loadDef); + REQUIRE(image->texture.loadDef->resourceSize > 0); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/IW5/Image/ImageLoaderExternalIW5Test.cpp b/test/ObjLoadingTests/Game/IW5/Image/ImageLoaderExternalIW5Test.cpp new file mode 100644 index 00000000..96e45649 --- /dev/null +++ b/test/ObjLoadingTests/Game/IW5/Image/ImageLoaderExternalIW5Test.cpp @@ -0,0 +1,54 @@ +#include "Game/IW5/Image/ImageLoaderExternalIW5.h" + +#include "Game/IW5/GameIW5.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace IW5; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderExternalIW5: Can parse iwi", "[iw5][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW5/Image/TestImage.iwi"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderExternalIW5(memory, searchPath); + auto result = loader->CreateAsset("testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/IW5/Image/TestImage.dds b/test/ObjLoadingTests/Game/IW5/Image/TestImage.dds new file mode 100644 index 0000000000000000000000000000000000000000..8705ec9d32facb000f43cc9228952ee8fd07bc1d GIT binary patch literal 2176 zcmc&#L1^1%6#i|mtez_Hp`+Jc3~3WX3N{{ccQ5mX>x~nBeCF z{nC5id++=He`x5dvuQ%er=F99L!>K%%dx)@KKMC{Uw(pXXmsSlkw1C<{uc0|Z~t#J z?O=RS5`>Dq6e7LNU4U2fgfIrc7h6cras2#F#iR!9!_Bw>o8-y-*z0Y`n+XX_L8h~jZC$ArKbD=$RWY4s3#+%=}TmZv4UPxx{Xk|q!-tPn8RhOG( z{`nI{>YyIlyz3s-)>Li0FW&Mtk-ROPl_Hca=i=w>RXb5Z$?Syl{9^S`^k(C(fU$YKkcujcd0^TckC zU(GAf1i~XOPfu@)TV;h=HINVLg}B&v^FQpnHh*rWx)c(n8vehYV%-j$`+7>3#qe_o;zahm$c=kvZNKjlY85BSZ6bWYD) zEIk^i)z;1fJb3DG5^_sh3Z*4Us-O;EI2=CH&MW+QBg3op)VXKoVnX#~7ZQmQ#mLwg zGh45xcw>#B-!XqC#WR(Oz;9p}7W&!gcDrd@+RsZ5Cjxt6K{&|≶4&ocS+G<`ACD7gix)g2m3dX;CO^5|$g%@69-1XG1 z#vpE(v|j-Alq}29v3fA>|GbF2I(1Ct_1+*z}IG;OBvt*spu_A1++=7ma-%;~YD6eb{+pL0?QtFJL{WPaY5_+h{>B z?q!|Cw3j2vq$tw+#mBN;b@peYIw9$;?Js#jN?I@xU{PNd;5`Hw3BD;1#^*cW)8X}T zXkuP5+1R{?ePP?t@(Nk7vEEJ`Pd1AE0IY*=QCtdP8Hg(dA49S8-9N?JDu?l@FNJTn LF^ny8XAg<|H{rBK8D}S zd*6HS``(O*lRa)i2t#H}?ZcJ030vgJ!sE#C`Ly)f8i@4+G;J8nlKy7`!1V$lZXLjKj*{1(x%tq( zHMVa#SK`g99uL51P7srs8+uvQi}wcr1kK}RnQz~hCkrHF@Yf5$c;Wot=V>07$K9om z*{agk%ckW$65UMa3_hy7w#urh>;4bdcd~@(Wq^c+h;zB8Bbr}37aLB*UMQC(fGO4Q z_xk{B>JQ$A#}TsCkk3BcjV!gG`EntzK2PlR`L(9OwH;e#(zrKHxVWGI%3%ru1m2R$D&}@ZhNn7sqe|9ie|UIHd2I0 z$frFw|a~PMWdk^tFdg;wdV`He3!7O|1*hli` z)uq-1_HRlh?k3KsZ#bQlCjfoJ`p%uBJkZvc#_Ko_z32z1I4(?R!=0fQ*sojlYd>D_ z7tMD*#yNKC`m}vx!$3?G1kIv@oxfY;4`azOe0Rd6g_WSZ^mzZ#Ihk n0IWl3QCtpT8HlR|j-l9j?@O_^#$$ZyOY!#|jF(qUbDg{a96Jtz literal 0 HcmV?d00001 diff --git a/test/ObjLoadingTests/Game/T5/Image/ImageLoaderEmbeddedT5Test.cpp b/test/ObjLoadingTests/Game/T5/Image/ImageLoaderEmbeddedT5Test.cpp new file mode 100644 index 00000000..70aef769 --- /dev/null +++ b/test/ObjLoadingTests/Game/T5/Image/ImageLoaderEmbeddedT5Test.cpp @@ -0,0 +1,57 @@ +#include "Game/T5/Image/ImageLoaderEmbeddedT5.h" + +#include "Game/T5/GameT5.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace T5; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderEmbeddedT5: Can parse dds", "[t5][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/T5/Image/TestImage.dds"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::T5, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderEmbeddedT5(memory, searchPath); + auto result = loader->CreateAsset("*testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "*testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + + REQUIRE(image->texture.loadDef); + REQUIRE(image->texture.loadDef->resourceSize > 0); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/T5/Image/ImageLoaderExternalT5Test.cpp b/test/ObjLoadingTests/Game/T5/Image/ImageLoaderExternalT5Test.cpp new file mode 100644 index 00000000..6f30c048 --- /dev/null +++ b/test/ObjLoadingTests/Game/T5/Image/ImageLoaderExternalT5Test.cpp @@ -0,0 +1,54 @@ +#include "Game/T5/Image/ImageLoaderExternalT5.h" + +#include "Game/T5/GameT5.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace T5; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderExternalT5: Can parse iwi", "[t5][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/T5/Image/TestImage.iwi"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::T5, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderExternalT5(memory, searchPath); + auto result = loader->CreateAsset("testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/T5/Image/TestImage.dds b/test/ObjLoadingTests/Game/T5/Image/TestImage.dds new file mode 100644 index 0000000000000000000000000000000000000000..8705ec9d32facb000f43cc9228952ee8fd07bc1d GIT binary patch literal 2176 zcmc&#L1^1%6#i|mtez_Hp`+Jc3~3WX3N{{ccQ5mX>x~nBeCF z{nC5id++=He`x5dvuQ%er=F99L!>K%%dx)@KKMC{Uw(pXXmsSlkw1C<{uc0|Z~t#J z?O=RS5`>Dq6e7LNU4U2fgfIrc7h6cras2#F#iR!9!_Bw>o8-y-*z0Y`n+XX_L8h~jZC$ArKbD=$RWY4s3#+%=}TmZv4UPxx{Xk|q!-tPn8RhOG( z{`nI{>YyIlyz3s-)>Li0FW&Mtk-ROPl_Hca=i=w>RXb5Z$?Syl{9^S`^k(C(fU$YKkcujcd0^TckC zU(GAf1i~XOPfu@)TV;h=HINVLg}B&v^FQpnHh*rWx)c(n8vehYV%-j$`+7>3#qe_o;zahm$c=kvZNKjlY85BSZ6bWYD) zEIk^i)z;1fJb3DG5^_sh3Z*4Us-O;EI2=CH&MW+QBg3op)VXKoVnX#~7ZQmQ#mLwg zGh45xcw>#B-!XqC#WR(Oz;9p}7W&!gcDrd@+RsZ5Cjxt6K{&|≶4&ocS+G<`ACD7gix)g2m3dX;CO^5|$g%@69-1XG1 z#vpE(v|j-Alq}29v3fA>|GbF2I(1Ct_1+*z}IG;OBvt*spu_A1++=7ma-%;~YD6eb{+pL0?QtFJL{WPaY5_+h{>B z?q!|Cw3j2vq$tw+#mBN;b@peYIw9$;?Js#jN?I@xU{PNd;5`Hw3BD;1#^*cW)8X}T zXkuP5+1R{?ePP?t@(Nk7vEEJ`Pd1AE0IY*=QCtdP8Hg(dA49S8-9N?JDu?l@FNJTn LF>-#2Wx|Vtoy`Ta zhhPjXcA=1tyqJXqc@WS#%Hrs$eJD5&MfD(53VTUd7%r3`)5gBLpIZ|XnzH@~)q~H& zC*OO{z2|%ym8LkB5r{xMgg!&3J8IT zV2>Zz?u|t2rq>HFmKUW|_Ks1}jMDu<08#h)IQG-e<;fz+n!@d3C{eup=VjW*<7ImM zF;`PNe%Z2pC*qr#yeY)gS9V3S3?p#7zO!X)uK*-5WC_E+$%g=N z$H2W{e)gi1vOG)k#Pj}l^r!sD^+SFOVN)=(7s`)@>-CNE01uve7(#w9R>B!YQL5;} ze?1=Fb_<#~+02T1BYp0fy`0qha!bi%nPPNef}L+P(xSD&()ZZEQ}S2Uso)=ASq|oz z@%enTE}iGahf~3Wh$J2M|HT#X0N_ITeg|LA$H6>CGTUUX7D}M#CO}_~-516A#$bGj z0coyQ(a!hl2Eg5#mw54>KwVigR$nh@vH}L(r^QnLCUr0NrRV6c`7L`|ldN8UZKes4 zkxyrD$n)ra&X!{xUZKQKF9~s=qKVQ=th<@sH(10io6ZZMkyceTHqi(r0$-MpS69bO zUcIK8GxW&7l@cy3j-_nvKW8H%0^Y!M9-Zw-AC{drkh1XG@Yeifmsju%v zHyj&%jJoimc%2VZ5cTiQ$!%!gt(_jx^;P6MmdCmRz4s8`;+MXhJU)&-8Om{|PQ9al zL0fK5;{2vH!nANd{Ue!_G6|R)&VT6=<$CHx#iY +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace T6; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderEmbeddedT6: Can parse dds", "[t6][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/T6/Image/TestImage.dds"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderEmbeddedT6(memory, searchPath); + auto result = loader->CreateAsset("*testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "*testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + REQUIRE(image->streamedPartCount == 0); + + REQUIRE(image->texture.loadDef); + REQUIRE(image->texture.loadDef->resourceSize > 0); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/T6/Image/ImageLoaderExternalT6Test.cpp b/test/ObjLoadingTests/Game/T6/Image/ImageLoaderExternalT6Test.cpp new file mode 100644 index 00000000..b83f0042 --- /dev/null +++ b/test/ObjLoadingTests/Game/T6/Image/ImageLoaderExternalT6Test.cpp @@ -0,0 +1,57 @@ +#include "Game/T6/Image/ImageLoaderExternalT6.h" + +#include "Game/T6/GameT6.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace T6; +using namespace std::literals; + +namespace +{ + TEST_CASE("ImageLoaderExternalT6: Can parse iwi", "[t6][image]") + { + MockSearchPath searchPath; + + const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/T6/Image/TestImage.iwi"; + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + const auto data = std::make_unique(fileSize); + file.read(data.get(), fileSize); + + searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize)); + + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = image::CreateLoaderExternalT6(memory, searchPath); + auto result = loader->CreateAsset("testimage", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* image = assetInfo->Asset(); + + REQUIRE(image->name == "testimage"s); + REQUIRE(image->width == 64); + REQUIRE(image->height == 64); + REQUIRE(image->depth == 1); + REQUIRE(image->streamedPartCount == 1); + REQUIRE(image->streamedParts[0].levelSize == 2112); + REQUIRE(image->streamedParts[0].hash == (0x386422F2 & 0x1FFFFFFF)); + } +} // namespace diff --git a/test/ObjLoadingTests/Game/T6/Image/TestImage.dds b/test/ObjLoadingTests/Game/T6/Image/TestImage.dds new file mode 100644 index 0000000000000000000000000000000000000000..8705ec9d32facb000f43cc9228952ee8fd07bc1d GIT binary patch literal 2176 zcmc&#L1^1%6#i|mtez_Hp`+Jc3~3WX3N{{ccQ5mX>x~nBeCF z{nC5id++=He`x5dvuQ%er=F99L!>K%%dx)@KKMC{Uw(pXXmsSlkw1C<{uc0|Z~t#J z?O=RS5`>Dq6e7LNU4U2fgfIrc7h6cras2#F#iR!9!_Bw>o8-y-*z0Y`n+XX_L8h~jZC$ArKbD=$RWY4s3#+%=}TmZv4UPxx{Xk|q!-tPn8RhOG( z{`nI{>YyIlyz3s-)>Li0FW&Mtk-ROPl_Hca=i=w>RXb5Z$?Syl{9^S`^k(C(fU$YKkcujcd0^TckC zU(GAf1i~XOPfu@)TV;h=HINVLg}B&v^FQpnHh*rWx)c(n8vehYV%-j$`+7>3#qe_o;zahm$c=kvZNKjlY85BSZ6bWYD) zEIk^i)z;1fJb3DG5^_sh3Z*4Us-O;EI2=CH&MW+QBg3op)VXKoVnX#~7ZQmQ#mLwg zGh45xcw>#B-!XqC#WR(Oz;9p}7W&!gcDrd@+RsZ5Cjxt6K{&|≶4&ocS+G<`ACD7gix)g2m3dX;CO^5|$g%@69-1XG1 z#vpE(v|j-Alq}29v3fA>|GbF2I(1Ct_1+*z}IG;OBvt*spu_A1++=7ma-%;~YD6eb{+pL0?QtFJL{WPaY5_+h{>B z?q!|Cw3j2vq$tw+#mBN;b@peYIw9$;?Js#jN?I@xU{PNd;5`Hw3BD;1#^*cW)8X}T zXkuP5+1R{?ePP?t@(Nk7vEEJ`Pd1AE0IY*=QCtdP8Hg(dA49S8-9N?JDu?l@FNJTn LF5r{xMhN!mhqv8=CQdf9qTWcKe`YTy^}gIvGFhe=otR+f8;!JRZLst^_OF!ud37rIJ6M*3 zer9|=AB{`Iz$4Khy zd(jQYMjc~axG3KG!xTjQoAYuT+IMTGM|6D^`Htl=u0Z!5;xT&Z%gN*8sFR@_ck0v! z@)xw__9XUiS|dyg=hHuuNhy+2H@oQF{g090LiV>$54@C)qMy~dAU zUJaD2cRt2BcI*0Q`^JI6xRP1IdQhJtAWnDCfl$KFF~oLPqp6fE)BAJF9+}*0*nOT775GqhkUxc{vFzwS57sz?_poKPPBqXmRzj28>cT9 p!+rqPA+{;5gs}|7wIa__?0)xOvA!-~eCkW-`(2Dz&@5|%yaDxp4z&OP literal 0 HcmV?d00001 From b6598c5af3ee0432ebb9531c73b0a27e7b37cd78 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Mon, 5 Jan 2026 00:03:42 +0100 Subject: [PATCH 5/5] chore: move string table tests --- .../{AssetLoaders => StringTable}/LoaderStringTableIW4Test.cpp | 0 .../{AssetLoaders => StringTable}/LoaderStringTableIW5Test.cpp | 0 .../T5/{AssetLoaders => StringTable}/LoaderStringTableT5Test.cpp | 0 .../T6/{AssetLoaders => StringTable}/LoaderStringTableT6Test.cpp | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename test/ObjLoadingTests/Game/IW4/{AssetLoaders => StringTable}/LoaderStringTableIW4Test.cpp (100%) rename test/ObjLoadingTests/Game/IW5/{AssetLoaders => StringTable}/LoaderStringTableIW5Test.cpp (100%) rename test/ObjLoadingTests/Game/T5/{AssetLoaders => StringTable}/LoaderStringTableT5Test.cpp (100%) rename test/ObjLoadingTests/Game/T6/{AssetLoaders => StringTable}/LoaderStringTableT6Test.cpp (100%) diff --git a/test/ObjLoadingTests/Game/IW4/AssetLoaders/LoaderStringTableIW4Test.cpp b/test/ObjLoadingTests/Game/IW4/StringTable/LoaderStringTableIW4Test.cpp similarity index 100% rename from test/ObjLoadingTests/Game/IW4/AssetLoaders/LoaderStringTableIW4Test.cpp rename to test/ObjLoadingTests/Game/IW4/StringTable/LoaderStringTableIW4Test.cpp diff --git a/test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp b/test/ObjLoadingTests/Game/IW5/StringTable/LoaderStringTableIW5Test.cpp similarity index 100% rename from test/ObjLoadingTests/Game/IW5/AssetLoaders/LoaderStringTableIW5Test.cpp rename to test/ObjLoadingTests/Game/IW5/StringTable/LoaderStringTableIW5Test.cpp diff --git a/test/ObjLoadingTests/Game/T5/AssetLoaders/LoaderStringTableT5Test.cpp b/test/ObjLoadingTests/Game/T5/StringTable/LoaderStringTableT5Test.cpp similarity index 100% rename from test/ObjLoadingTests/Game/T5/AssetLoaders/LoaderStringTableT5Test.cpp rename to test/ObjLoadingTests/Game/T5/StringTable/LoaderStringTableT5Test.cpp diff --git a/test/ObjLoadingTests/Game/T6/AssetLoaders/LoaderStringTableT6Test.cpp b/test/ObjLoadingTests/Game/T6/StringTable/LoaderStringTableT6Test.cpp similarity index 100% rename from test/ObjLoadingTests/Game/T6/AssetLoaders/LoaderStringTableT6Test.cpp rename to test/ObjLoadingTests/Game/T6/StringTable/LoaderStringTableT6Test.cpp