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/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..89cde7f4 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,8 +79,8 @@ namespace image_converter return false; } - const auto texture = iwi::LoadIwi(file); - if (!texture) + const auto loadResult = image::LoadIwi(file); + if (!loadResult) return false; auto outPath = iwiPath; @@ -90,7 +93,7 @@ namespace image_converter return false; } - m_dds_writer.DumpImage(outFile, texture.get()); + m_dds_writer.DumpImage(outFile, loadResult->m_texture.get()); return true; } @@ -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..503c804f 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) { @@ -47,17 +49,20 @@ namespace iwi 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]; @@ -74,7 +79,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--) @@ -86,18 +91,30 @@ namespace iwi && 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) @@ -145,17 +162,20 @@ namespace iwi 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]; @@ -178,17 +198,17 @@ namespace iwi 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(); - 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--) @@ -200,18 +220,30 @@ namespace iwi && 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) @@ -256,17 +288,20 @@ namespace iwi 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]; @@ -283,7 +318,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--) @@ -295,18 +330,31 @@ namespace iwi && 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) @@ -353,17 +401,20 @@ namespace iwi 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]; @@ -380,7 +431,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--) @@ -392,35 +443,54 @@ namespace iwi && 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 - std::unique_ptr LoadIwi(std::istream& stream) +namespace image +{ + std::optional LoadIwi(std::istream& stream) { - IwiVersion iwiVersion{}; + IwiVersionHeader iwiVersionHeader{}; - stream.read(reinterpret_cast(&iwiVersion), sizeof(iwiVersion)); - if (stream.gcount() != sizeof(iwiVersion)) - return nullptr; - - if (iwiVersion.tag[0] != 'I' || iwiVersion.tag[1] != 'W' || iwiVersion.tag[2] != 'i') + stream.read(reinterpret_cast(&iwiVersionHeader), sizeof(iwiVersionHeader)); + if (stream.gcount() != sizeof(iwiVersionHeader)) { - con::error("Invalid IWI magic"); - return nullptr; + con::error("IWI version header corrupted"); + return std::nullopt; } - switch (iwiVersion.version) + if (iwiVersionHeader.tag[0] != 'I' || iwiVersionHeader.tag[1] != 'W' || iwiVersionHeader.tag[2] != 'i') + { + con::error("Invalid IWI magic"); + return std::nullopt; + } + + switch (iwiVersionHeader.version) { case 6: return LoadIwi6(stream); @@ -438,7 +508,7 @@ namespace iwi break; } - con::error("Unknown IWI version {}", iwiVersion.version); - return nullptr; + con::error("Unknown IWI version {}", iwiVersionHeader.version); + return std::nullopt; } -} // namespace iwi +} // namespace image diff --git a/src/ObjImage/Image/IwiLoader.h b/src/ObjImage/Image/IwiLoader.h index a1f65c65..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 iwi +namespace image { - std::unique_ptr LoadIwi(std::istream& stream); -}; // namespace iwi + 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 545861ca..2a26974f 100644 --- a/src/ObjImage/Image/IwiTypes.h +++ b/src/ObjImage/Image/IwiTypes.h @@ -2,234 +2,257 @@ #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 CommonIwiMetaData { - 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, + // Always high resolution + bool m_no_picmip; + bool m_streaming; + bool m_clamp_u; + bool m_clamp_v; + bool m_dynamic; - IMG_FORMAT_COUNT + float m_gamma; }; - enum IwiFlags + struct IwiVersionHeader { - 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 - -// IW4 -namespace iwi8 -{ - struct IwiHeader - { - uint32_t flags; - int8_t format; - int8_t unused; - uint16_t dimensions[3]; - uint32_t fileSizeForPicmip[4]; + char tag[3]; + char version; }; - enum class IwiFormat + namespace iwi6 { - 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]; + uint32_t fileSizeForPicmip[4]; + }; - 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, - enum IwiFlags + 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 { - 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 + { + uint32_t flags; + int8_t format; + int8_t unused; + uint16_t dimensions[3]; + uint32_t fileSizeForPicmip[4]; + }; -// T5 -namespace iwi13 -{ - 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_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 { - int8_t format; - int8_t flags; - uint16_t dimensions[3]; - float gamma; - uint32_t fileSizeForPicmip[8]; - }; + struct IwiHeader + { + int8_t format; + int8_t flags; + uint16_t dimensions[3]; + float gamma; + uint32_t fileSizeForPicmip[8]; + }; - 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_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_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_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, - }; + struct IwiHeader + { + int8_t format; + int8_t flags; + uint16_t dimensions[3]; + float gamma; + int8_t maxGlossForMip[16]; + uint32_t fileSizeForPicmip[8]; + }; - 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, - }; + 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, + }; -} // namespace iwi13 + 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, + }; -// 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.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 4052f23c..3d77d604 100644 --- a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp +++ b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp @@ -4,8 +4,9 @@ #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 "Image/AssetLoaderImageIW3.h" #include "Localize/AssetLoaderLocalizeIW3.h" #include "Material/LoaderMaterialIW3.h" #include "ObjLoading.h" @@ -95,7 +96,8 @@ 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::CreateLoaderEmbeddedIW3(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..8d5899a2 100644 --- a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp +++ b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp @@ -4,6 +4,8 @@ #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" #include "LightDef/LightDefLoaderIW4.h" @@ -130,7 +132,8 @@ 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::CreateLoaderEmbeddedIW4(memory, searchPath)); + 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 a7f68cf4..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 = iwi::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..439d1b0c 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -4,8 +4,9 @@ #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 "Image/LoaderImageIW5.h" #include "Leaderboard/LoaderLeaderboardIW5.h" #include "Localize/LoaderLocalizeIW5.h" #include "Material/LoaderMaterialIW5.h" @@ -132,7 +133,8 @@ 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::CreateLoaderEmbeddedIW5(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..01d22d5f 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp @@ -3,6 +3,8 @@ #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" #include "Localize/LoaderLocalizeT5.h" @@ -108,7 +110,8 @@ 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::CreateLoaderEmbeddedT5(memory, searchPath)); + 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 e870761c..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 = iwi::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..b9747017 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -7,12 +7,13 @@ #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" #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 +395,8 @@ 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::CreateLoaderEmbeddedT6(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 new file mode 100644 index 00000000..569b964b --- /dev/null +++ b/src/ObjLoading/Image/ImageLoaderCommon.cpp @@ -0,0 +1,89 @@ +#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 + { + if (m_failure) + return AssetCreationResult::Failure(); + + if (!m_texture) + return AssetCreationResult::NoAction(); + + 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 new file mode 100644 index 00000000..a4214603 --- /dev/null +++ b/src/ObjLoading/Image/ImageLoaderCommon.h @@ -0,0 +1,39 @@ +#pragma once + +#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; + size_t m_iwi_size; + CommonIwiMetaData m_meta; + std::unique_ptr m_texture; + CommonImageLoaderHash m_hash; + }; + + CommonImageLoaderResult + LoadImageCommon(const std::string& imageName, ISearchPath& searchPath, IwiVersion expectedIwiVersion, CommonImageLoaderHashType hashType); +} // namespace image diff --git a/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp b/src/ObjLoading/Image/ImageLoaderEmbedded.cpp.template similarity index 65% rename from src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp rename to src/ObjLoading/Image/ImageLoaderEmbedded.cpp.template index 8e876432..9541e0fc 100644 --- a/src/ObjLoading/Game/IW3/Image/AssetLoaderImageIW3.cpp +++ b/src/ObjLoading/Image/ImageLoaderEmbedded.cpp.template @@ -1,24 +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) { @@ -31,14 +71,11 @@ 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(); - 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); @@ -58,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()) { @@ -91,15 +130,23 @@ namespace loadDef->levelCount = static_cast(mipCount); loadDef->flags = 0; if (!texture->HasMipMaps()) - loadDef->flags |= iwi6::IMG_FLAG_NOMIPMAPS; + loadDef->flags |= IWI_NS::IMG_FLAG_NOMIPMAPS; if (texture->GetTextureType() == TextureType::T_CUBE) - loadDef->flags |= iwi6::IMG_FLAG_CUBEMAP; + loadDef->flags |= IWI_NS::FLAG_CUBE; if (texture->GetTextureType() == TextureType::T_3D) - loadDef->flags |= 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; @@ -117,7 +164,6 @@ namespace return AssetCreationResult::Success(context.AddAsset(assetName, image)); } - private: MemoryManager& m_memory; ISearchPath& m_search_path; }; @@ -125,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 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 06d0b422..f73d88d7 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,8 @@ namespace return nullptr; } - return iwi::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/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..e52aacd3 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,8 @@ namespace return nullptr; } - return iwi::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.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..74995f30 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,8 @@ namespace return nullptr; } - return iwi::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.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..2f0e0649 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,8 @@ namespace return nullptr; } - return iwi::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.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..61914b4a 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,11 +47,11 @@ namespace if (ipakStream) { - auto loadedTexture = iwi::LoadIwi(*ipakStream); + auto loadResult = image::LoadIwi(*ipakStream); ipakStream->close(); - if (loadedTexture != nullptr) - return loadedTexture; + if (loadResult) + return std::move(loadResult->m_texture); } } } @@ -63,7 +64,8 @@ namespace return nullptr; } - return iwi::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.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 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 00000000..8705ec9d Binary files /dev/null and b/test/ObjLoadingTests/Game/IW3/Image/TestImage.dds differ diff --git a/test/ObjLoadingTests/Game/IW3/Image/TestImage.iwi b/test/ObjLoadingTests/Game/IW3/Image/TestImage.iwi new file mode 100644 index 00000000..14294e0c Binary files /dev/null and b/test/ObjLoadingTests/Game/IW3/Image/TestImage.iwi differ 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 00000000..8705ec9d Binary files /dev/null and b/test/ObjLoadingTests/Game/IW4/Image/TestImage.dds differ diff --git a/test/ObjLoadingTests/Game/IW4/Image/TestImage.iwi b/test/ObjLoadingTests/Game/IW4/Image/TestImage.iwi new file mode 100644 index 00000000..172bde0e Binary files /dev/null and b/test/ObjLoadingTests/Game/IW4/Image/TestImage.iwi differ 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/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 00000000..8705ec9d Binary files /dev/null and b/test/ObjLoadingTests/Game/IW5/Image/TestImage.dds differ diff --git a/test/ObjLoadingTests/Game/IW5/Image/TestImage.iwi b/test/ObjLoadingTests/Game/IW5/Image/TestImage.iwi new file mode 100644 index 00000000..172bde0e Binary files /dev/null and b/test/ObjLoadingTests/Game/IW5/Image/TestImage.iwi differ 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/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 00000000..8705ec9d Binary files /dev/null and b/test/ObjLoadingTests/Game/T5/Image/TestImage.dds differ diff --git a/test/ObjLoadingTests/Game/T5/Image/TestImage.iwi b/test/ObjLoadingTests/Game/T5/Image/TestImage.iwi new file mode 100644 index 00000000..fb909fdb Binary files /dev/null and b/test/ObjLoadingTests/Game/T5/Image/TestImage.iwi differ 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/Image/ImageLoaderEmbeddedT6Test.cpp b/test/ObjLoadingTests/Game/T6/Image/ImageLoaderEmbeddedT6Test.cpp new file mode 100644 index 00000000..33b2ba0d --- /dev/null +++ b/test/ObjLoadingTests/Game/T6/Image/ImageLoaderEmbeddedT6Test.cpp @@ -0,0 +1,58 @@ +#include "Game/T6/Image/ImageLoaderEmbeddedT6.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("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 00000000..8705ec9d Binary files /dev/null and b/test/ObjLoadingTests/Game/T6/Image/TestImage.dds differ diff --git a/test/ObjLoadingTests/Game/T6/Image/TestImage.iwi b/test/ObjLoadingTests/Game/T6/Image/TestImage.iwi new file mode 100644 index 00000000..43eedd48 Binary files /dev/null and b/test/ObjLoadingTests/Game/T6/Image/TestImage.iwi differ 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