diff --git a/premake5.lua b/premake5.lua index 0ac4a6ac4..651de9118 100644 --- a/premake5.lua +++ b/premake5.lua @@ -112,6 +112,7 @@ group "" -- ======================== include "src/Common.lua" include "src/Crypto.lua" +include "src/ImageConverter.lua" include "src/Linker.lua" include "src/Parser.lua" include "src/RawTemplater.lua" @@ -125,6 +126,7 @@ include "src/ZoneLoading.lua" include "src/ZoneWriting.lua" include "src/ZoneCommon.lua" include "src/ObjCommon.lua" +include "src/ObjImage.lua" include "src/ObjLoading.lua" include "src/ObjWriting.lua" include "tools/scripts/raw.lua" @@ -141,6 +143,7 @@ group "Components" ZoneLoading:project() ZoneWriting:project() ObjCommon:project() + ObjImage:project() ObjLoading:project() ObjWriting:project() group "" @@ -155,6 +158,7 @@ group "" group "Tools" Linker:project() Unlinker:project() + ImageConverter:project() group "" group "Raw" diff --git a/src/Common/Game/IW3/IW3.h b/src/Common/Game/IW3/IW3.h index 889b87c4e..a489583c6 100644 --- a/src/Common/Game/IW3/IW3.h +++ b/src/Common/Game/IW3/IW3.h @@ -4,7 +4,6 @@ // #include #include "Game/IAsset.h" -#include "Image/Texture.h" #include "IW3_Assets.h" diff --git a/src/Common/Game/IW3/IW3_Assets.h b/src/Common/Game/IW3/IW3_Assets.h index f2ef4fd59..1cb6859ca 100644 --- a/src/Common/Game/IW3/IW3_Assets.h +++ b/src/Common/Game/IW3/IW3_Assets.h @@ -1326,7 +1326,6 @@ namespace IW3 // void/*IDirect3DTexture9*/* map; // void/*IDirect3DVolumeTexture9*/* volmap; // void/*IDirect3DCubeTexture9*/* cubemap; - Texture* texture; GfxImageLoadDef* loadDef; }; diff --git a/src/Common/Game/IW4/CommonIW4.cpp b/src/Common/Game/IW4/CommonIW4.cpp index de6cc73df..6b3b6f975 100644 --- a/src/Common/Game/IW4/CommonIW4.cpp +++ b/src/Common/Game/IW4/CommonIW4.cpp @@ -2,6 +2,8 @@ #include "Utils/Pack.h" +#include + using namespace IW4; int Common::StringTable_HashString(const char* str) diff --git a/src/Common/Game/IW4/IW4.h b/src/Common/Game/IW4/IW4.h index 25beb1687..4335bdb12 100644 --- a/src/Common/Game/IW4/IW4.h +++ b/src/Common/Game/IW4/IW4.h @@ -4,7 +4,6 @@ // #include #include "Game/IAsset.h" -#include "Image/Texture.h" #include "IW4_Assets.h" diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index d6bde24b6..2eda44b9e 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -1009,7 +1009,6 @@ namespace IW4 // IDirect3DTexture9* map; // IDirect3DVolumeTexture9* volmap; // IDirect3DCubeTexture9* cubemap; - Texture* texture; GfxImageLoadDef* loadDef; }; diff --git a/src/Common/Game/IW5/CommonIW5.cpp b/src/Common/Game/IW5/CommonIW5.cpp index 79379dd41..55b820fc5 100644 --- a/src/Common/Game/IW5/CommonIW5.cpp +++ b/src/Common/Game/IW5/CommonIW5.cpp @@ -2,6 +2,8 @@ #include "Utils/Pack.h" +#include + using namespace IW5; int Common::StringTable_HashString(const char* str) diff --git a/src/Common/Game/IW5/IW5.h b/src/Common/Game/IW5/IW5.h index df2110cc0..ba6b314d6 100644 --- a/src/Common/Game/IW5/IW5.h +++ b/src/Common/Game/IW5/IW5.h @@ -4,7 +4,6 @@ // #include #include "Game/IAsset.h" -#include "Image/Texture.h" #include "IW5_Assets.h" diff --git a/src/Common/Game/IW5/IW5_Assets.h b/src/Common/Game/IW5/IW5_Assets.h index 2d45909da..c506f3f2f 100644 --- a/src/Common/Game/IW5/IW5_Assets.h +++ b/src/Common/Game/IW5/IW5_Assets.h @@ -1143,9 +1143,6 @@ namespace IW5 // IDirect3DTexture9* map; // IDirect3DVolumeTexture9* volmap; // IDirect3DCubeTexture9* cubemap; -#ifndef __ida - Texture* texture; -#endif GfxImageLoadDef* loadDef; }; diff --git a/src/Common/Game/T5/T5.h b/src/Common/Game/T5/T5.h index efd71592c..c493782d8 100644 --- a/src/Common/Game/T5/T5.h +++ b/src/Common/Game/T5/T5.h @@ -4,7 +4,6 @@ // #include #include "Game/IAsset.h" -#include "Image/Texture.h" #include "T5_Assets.h" diff --git a/src/Common/Game/T5/T5_Assets.h b/src/Common/Game/T5/T5_Assets.h index f055f58c9..e69347ade 100644 --- a/src/Common/Game/T5/T5_Assets.h +++ b/src/Common/Game/T5/T5_Assets.h @@ -1024,7 +1024,6 @@ namespace T5 // IDirect3DTexture9* map; // IDirect3DVolumeTexture9* volmap; // IDirect3DCubeTexture9* cubemap; - Texture* texture; GfxImageLoadDef* loadDef; }; diff --git a/src/Common/Game/T6/CommonT6.cpp b/src/Common/Game/T6/CommonT6.cpp index 4c9287c5d..5a54bc8d3 100644 --- a/src/Common/Game/T6/CommonT6.cpp +++ b/src/Common/Game/T6/CommonT6.cpp @@ -2,62 +2,8 @@ #include "Utils/Pack.h" -#include - using namespace T6; -int Common::Com_HashKey(const char* str, const int maxLen) -{ - if (str == nullptr) - return 0; - - int hash = 0; - for (int i = 0; i < maxLen; i++) - { - if (str[i] == '\0') - break; - - hash += str[i] * (0x77 + i); - } - - return hash ^ ((hash ^ (hash >> 10)) >> 10); -} - -int Common::Com_HashString(const char* str) -{ - if (!str) - return 0; - - auto result = 0x1505; - auto offset = 0; - while (str[offset]) - { - const auto c = tolower(str[offset++]); - result = c + 33 * result; - } - - return result; -} - -int Common::Com_HashString(const char* str, const int len) -{ - if (!str) - return 0; - - int result = 0x1505; - int offset = 0; - while (str[offset]) - { - if (len > 0 && offset >= len) - break; - - const int c = tolower(str[offset++]); - result = c + 33 * result; - } - - return result; -} - PackedTexCoords Common::Vec2PackTexCoords(const float (&in)[2]) { return PackedTexCoords{pack32::Vec2PackTexCoordsUV(in)}; diff --git a/src/Common/Game/T6/CommonT6.h b/src/Common/Game/T6/CommonT6.h index 9f7fbb2b2..f32c9d971 100644 --- a/src/Common/Game/T6/CommonT6.h +++ b/src/Common/Game/T6/CommonT6.h @@ -2,14 +2,64 @@ #include "T6.h" +#include + namespace T6 { class Common { public: - static int Com_HashKey(const char* str, int maxLen); - static int Com_HashString(const char* str); - static int Com_HashString(const char* str, int len); + static constexpr int Com_HashKey(const char* str, const int maxLen) + { + if (str == nullptr) + return 0; + + int hash = 0; + for (int i = 0; i < maxLen; i++) + { + if (str[i] == '\0') + break; + + hash += str[i] * (0x77 + i); + } + + return hash ^ ((hash ^ (hash >> 10)) >> 10); + } + + static constexpr int Com_HashString(const char* str) + { + if (!str) + return 0; + + auto result = 0x1505; + auto offset = 0; + while (str[offset]) + { + const auto c = tolower(str[offset++]); + result = c + 33 * result; + } + + return result; + } + + static constexpr int Com_HashString(const char* str, const int len) + { + if (!str) + return 0; + + int result = 0x1505; + int offset = 0; + while (str[offset]) + { + if (len > 0 && offset >= len) + break; + + const int c = tolower(str[offset++]); + result = c + 33 * result; + } + + return result; + } static constexpr uint32_t R_HashString(const char* str, uint32_t hash) { diff --git a/src/Common/Game/T6/T6.h b/src/Common/Game/T6/T6.h index 6a0e560e0..0b9bc5c69 100644 --- a/src/Common/Game/T6/T6.h +++ b/src/Common/Game/T6/T6.h @@ -4,7 +4,6 @@ // #include #include "Game/IAsset.h" -#include "Image/Texture.h" #include "T6_Assets.h" diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 5711f232f..d6bb368e7 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -848,7 +848,6 @@ namespace T6 union GfxTexture { void /*ID3D11ShaderResourceView*/* basemap; - Texture* texture; GfxImageLoadDef* loadDef; }; diff --git a/src/Common/Image/Texture.h b/src/Common/Image/Texture.h deleted file mode 100644 index 519041a49..000000000 --- a/src/Common/Image/Texture.h +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once -#include "ImageFormat.h" - -#include - -enum class TextureType -{ - T_2D, - T_CUBE, - T_3D -}; - -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& operator=(Texture&& other) noexcept; - -public: - Texture(const Texture& other) = delete; - virtual ~Texture(); - - Texture& operator=(const Texture& other) = delete; - - virtual TextureType GetTextureType() const = 0; - const ImageFormat* GetFormat() const; - - virtual unsigned GetWidth() const = 0; - virtual unsigned GetHeight() const = 0; - virtual unsigned GetDepth() const = 0; - virtual int GetFaceCount() const = 0; - - void Allocate(); - bool Empty() const; - - virtual size_t GetSizeOfMipLevel(int mipLevel) const = 0; - virtual uint8_t* GetBufferForMipLevel(int mipLevel, int face) = 0; - uint8_t* GetBufferForMipLevel(int mipLevel); - - bool HasMipMaps() const; - virtual int GetMipMapCount() const = 0; -}; - -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; - - Texture2D& operator=(const Texture2D& other) = delete; - Texture2D& operator=(Texture2D&& other) noexcept; - - TextureType GetTextureType() const override; - - unsigned GetWidth() const override; - unsigned GetHeight() const override; - unsigned GetDepth() const override; - int GetFaceCount() const override; - - size_t GetSizeOfMipLevel(int mipLevel) const override; - uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; - - int GetMipMapCount() const override; -}; - -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; - - TextureCube& operator=(const TextureCube& other) = delete; - TextureCube& operator=(TextureCube&& other) noexcept; - - TextureType GetTextureType() const override; - - int GetFaceCount() const override; - - uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; -}; - -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; - - Texture3D& operator=(const Texture3D& other) = delete; - Texture3D& operator=(Texture3D&& other) noexcept; - - TextureType GetTextureType() const override; - - unsigned GetWidth() const override; - unsigned GetHeight() const override; - unsigned GetDepth() const override; - int GetFaceCount() const override; - - size_t GetSizeOfMipLevel(int mipLevel) const override; - uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; - - int GetMipMapCount() const override; -}; diff --git a/src/ImageConverter.lua b/src/ImageConverter.lua new file mode 100644 index 000000000..79a7f3cf4 --- /dev/null +++ b/src/ImageConverter.lua @@ -0,0 +1,48 @@ +ImageConverter = {} + +function ImageConverter:include(includes) + if includes:handle(self:name()) then + includedirs { + path.join(ProjectFolder(), "ImageConverter") + } + end +end + +function ImageConverter:link(links) + +end + +function ImageConverter:use() + dependson(self:name()) +end + +function ImageConverter:name() + return "ImageConverter" +end + +function ImageConverter:project() + local folder = ProjectFolder() + local includes = Includes:create() + local links = Links:create() + + project(self:name()) + targetdir(TargetDirectoryBin) + location "%{wks.location}/src/%{prj.name}" + kind "ConsoleApp" + language "C++" + + files { + path.join(folder, "ImageConverter/**.h"), + path.join(folder, "ImageConverter/**.cpp") + } + + self:include(includes) + Utils:include(includes) + ObjImage:include(includes) + + Raw:use() + + links:linkto(Utils) + links:linkto(ObjImage) + links:linkall() +end diff --git a/src/ImageConverter/ImageConverter.cpp b/src/ImageConverter/ImageConverter.cpp new file mode 100644 index 000000000..7f180876e --- /dev/null +++ b/src/ImageConverter/ImageConverter.cpp @@ -0,0 +1,202 @@ +#include "ImageConverter.h" + +#include "Image/DdsLoader.h" +#include "Image/DdsWriter.h" +#include "Image/IwiLoader.h" +#include "Image/IwiWriter13.h" +#include "Image/IwiWriter27.h" +#include "Image/IwiWriter6.h" +#include "Image/IwiWriter8.h" +#include "Image/Texture.h" +#include "ImageConverterArgs.h" +#include "Utils/StringUtils.h" + +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +namespace image_converter +{ + constexpr auto EXTENSION_IWI = ".iwi"; + constexpr auto EXTENSION_DDS = ".dds"; + + class ImageConverterImpl final : public ImageConverter + { + public: + ImageConverterImpl() + : m_game_to_convert_to(image_converter::Game::UNKNOWN) + { + } + + bool Start(const int argc, const char** argv) override + { + auto shouldContinue = true; + if (!m_args.ParseArgs(argc, argv, shouldContinue)) + return false; + + if (!shouldContinue) + return true; + + m_game_to_convert_to = m_args.m_game_to_convert_to; + + for (const auto& file : m_args.m_files_to_convert) + Convert(file); + + return true; + } + + private: + void Convert(const std::string& file) + { + const fs::path filePath(file); + auto extension = filePath.extension().string(); + utils::MakeStringLowerCase(extension); + + if (extension == EXTENSION_IWI) + ConvertIwi(filePath); + else if (extension == EXTENSION_DDS) + ConvertDds(filePath); + else + std::cerr << std::format("Unsupported extension {}\n", extension); + } + + bool ConvertIwi(const fs::path& iwiPath) + { + std::ifstream file(iwiPath, std::ios::in | std::ios::binary); + if (!file.is_open()) + { + std::cerr << std::format("Failed to open input file {}\n", iwiPath.string()); + return false; + } + + const auto texture = iwi::LoadIwi(file); + if (!texture) + return false; + + auto outPath = iwiPath; + outPath.replace_extension(".dds"); + + std::ofstream outFile(outPath, std::ios::out | std::ios::binary); + if (!outFile.is_open()) + { + std::cerr << std::format("Failed to open output file {}\n", outPath.string()); + return false; + } + + m_dds_writer.DumpImage(outFile, texture.get()); + return true; + } + + bool ConvertDds(const fs::path& ddsPath) + { + std::ifstream file(ddsPath, std::ios::in | std::ios::binary); + if (!file.is_open()) + { + std::cerr << std::format("Failed to open input file {}\n", ddsPath.string()); + return false; + } + + const auto texture = dds::LoadDds(file); + if (!texture) + return false; + + if (!EnsureIwiWriterIsPresent()) + return false; + + auto outPath = ddsPath; + outPath.replace_extension(".iwi"); + + std::ofstream outFile(outPath, std::ios::out | std::ios::binary); + if (!outFile.is_open()) + { + std::cerr << std::format("Failed to open output file {}\n", outPath.string()); + return false; + } + + m_iwi_writer->DumpImage(outFile, texture.get()); + return true; + } + + bool EnsureIwiWriterIsPresent() + { + if (m_iwi_writer) + return true; + + if (m_game_to_convert_to == Game::UNKNOWN && !ShowGameTui()) + return false; + + switch (m_game_to_convert_to) + { + case Game::IW3: + m_iwi_writer = std::make_unique(); + break; + case Game::IW4: + case Game::IW5: + m_iwi_writer = std::make_unique(); + break; + case Game::T5: + m_iwi_writer = std::make_unique(); + break; + case Game::T6: + m_iwi_writer = std::make_unique(); + break; + default: + assert(false); + return false; + } + + return true; + } + + bool ShowGameTui() + { + std::cout << "Select the game to convert to:\n"; + std::cout << " 1 - Call Of Duty 4: Modern Warfare (IW3)\n"; + std::cout << " 2 - Call Of Duty: Modern Warfare 2 (IW4)\n"; + std::cout << " 3 - Call Of Duty: Modern Warfare 3 (IW5)\n"; + std::cout << " 4 - Call Of Duty: Black Ops (T5)\n"; + std::cout << " 5 - Call Of Duty: Black Ops 2 (T6)\n"; + + unsigned num; + std::cin >> num; + + switch (num) + { + case 1: + m_game_to_convert_to = Game::IW3; + break; + case 2: + m_game_to_convert_to = Game::IW4; + break; + case 3: + m_game_to_convert_to = Game::IW5; + break; + case 4: + m_game_to_convert_to = Game::T5; + break; + case 5: + m_game_to_convert_to = Game::T6; + break; + default: + std::cerr << "Invalid input\n"; + return false; + } + + return true; + } + + ImageConverterArgs m_args; + image_converter::Game m_game_to_convert_to; + DdsWriter m_dds_writer; + std::unique_ptr m_iwi_writer; + }; +} // namespace image_converter + +std::unique_ptr ImageConverter::Create() +{ + return std::make_unique(); +} diff --git a/src/ImageConverter/ImageConverter.h b/src/ImageConverter/ImageConverter.h new file mode 100644 index 000000000..d0e37a874 --- /dev/null +++ b/src/ImageConverter/ImageConverter.h @@ -0,0 +1,24 @@ +#pragma once +#include + +class ImageConverter +{ +public: + ImageConverter() = default; + virtual ~ImageConverter() = default; + + ImageConverter(const ImageConverter& other) = delete; + ImageConverter(ImageConverter&& other) noexcept = delete; + ImageConverter& operator=(const ImageConverter& other) = delete; + ImageConverter& operator=(ImageConverter&& other) noexcept = delete; + + /** + * \brief Starts the ImageConverter application logic. + * \param argc The amount of command line arguments specified. + * \param argv The command line arguments. + * \return \c true if the application was successful or \c false if an error occurred. + */ + virtual bool Start(int argc, const char** argv) = 0; + + static std::unique_ptr Create(); +}; diff --git a/src/ImageConverter/ImageConverterArgs.cpp b/src/ImageConverter/ImageConverterArgs.cpp new file mode 100644 index 000000000..8b51a46fd --- /dev/null +++ b/src/ImageConverter/ImageConverterArgs.cpp @@ -0,0 +1,149 @@ +#include "ImageConverterArgs.h" + +#include "GitVersion.h" +#include "Utils/Arguments/UsageInformation.h" + +#include +#include +#include + +// clang-format off +const CommandLineOption* const OPTION_HELP = + CommandLineOption::Builder::Create() + .WithShortName("?") + .WithLongName("help") + .WithDescription("Displays usage information.") + .Build(); + +const CommandLineOption* const OPTION_VERSION = + CommandLineOption::Builder::Create() + .WithLongName("version") + .WithDescription("Prints the application version.") + .Build(); + +const CommandLineOption* const OPTION_VERBOSE = + CommandLineOption::Builder::Create() + .WithShortName("v") + .WithLongName("verbose") + .WithDescription("Outputs a lot more and more detailed messages.") + .Build(); + +constexpr auto CATEGORY_GAME = "Game"; + +const CommandLineOption* const OPTION_GAME_IW3 = + CommandLineOption::Builder::Create() + .WithLongName("iw3") + .WithCategory(CATEGORY_GAME) + .WithDescription("Converts images for IW3.") + .Build(); + +const CommandLineOption* const OPTION_GAME_IW4 = + CommandLineOption::Builder::Create() + .WithLongName("iw4") + .WithCategory(CATEGORY_GAME) + .WithDescription("Converts images for IW4.") + .Build(); + +const CommandLineOption* const OPTION_GAME_IW5 = + CommandLineOption::Builder::Create() + .WithLongName("iw5") + .WithCategory(CATEGORY_GAME) + .WithDescription("Converts images for IW5.") + .Build(); + +const CommandLineOption* const OPTION_GAME_T5 = + CommandLineOption::Builder::Create() + .WithLongName("t5") + .WithCategory(CATEGORY_GAME) + .WithDescription("Converts images for T5.") + .Build(); + +const CommandLineOption* const OPTION_GAME_T6 = + CommandLineOption::Builder::Create() + .WithLongName("t6") + .WithCategory(CATEGORY_GAME) + .WithDescription("Converts images for T6.") + .Build(); +// clang-format on + +const CommandLineOption* const COMMAND_LINE_OPTIONS[]{ + OPTION_HELP, + OPTION_VERSION, + OPTION_VERBOSE, + OPTION_GAME_IW3, + OPTION_GAME_IW4, + OPTION_GAME_IW5, + OPTION_GAME_T5, + OPTION_GAME_T6, +}; + +ImageConverterArgs::ImageConverterArgs() + : m_verbose(false), + m_game_to_convert_to(image_converter::Game::UNKNOWN), + m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v) +{ +} + +void ImageConverterArgs::PrintUsage() +{ + UsageInformation usage("ImageConverter.exe"); + + for (const auto* commandLineOption : COMMAND_LINE_OPTIONS) + { + usage.AddCommandLineOption(commandLineOption); + } + + usage.AddArgument("fileToConvert"); + usage.SetVariableArguments(true); + + usage.Print(); +} + +void ImageConverterArgs::PrintVersion() +{ + std::cout << std::format("OpenAssetTools ImageConverter {}\n", GIT_VERSION); +} + +void ImageConverterArgs::SetVerbose(const bool isVerbose) +{ + m_verbose = isVerbose; +} + +bool ImageConverterArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue) +{ + shouldContinue = true; + if (!m_argument_parser.ParseArguments(argc, argv)) + { + PrintUsage(); + return false; + } + + // Check if the user requested help + if (m_argument_parser.IsOptionSpecified(OPTION_HELP)) + { + PrintUsage(); + shouldContinue = false; + return true; + } + + // Check if the user wants to see the version + if (m_argument_parser.IsOptionSpecified(OPTION_VERSION)) + { + PrintVersion(); + shouldContinue = false; + return true; + } + + m_files_to_convert = m_argument_parser.GetArguments(); + if (m_files_to_convert.empty()) + { + // No files to convert specified... + PrintUsage(); + return false; + } + + // -v; --verbose + SetVerbose(m_argument_parser.IsOptionSpecified(OPTION_VERBOSE)); + + return true; +} diff --git a/src/ImageConverter/ImageConverterArgs.h b/src/ImageConverter/ImageConverterArgs.h new file mode 100644 index 000000000..6d39a8a49 --- /dev/null +++ b/src/ImageConverter/ImageConverterArgs.h @@ -0,0 +1,42 @@ +#pragma once + +#include "Utils/Arguments/ArgumentParser.h" + +#include +#include +#include + +namespace image_converter +{ + enum class Game : std::uint8_t + { + UNKNOWN, + IW3, + IW4, + IW5, + T5, + T6 + }; +} // namespace image_converter + +class ImageConverterArgs +{ +public: + ImageConverterArgs(); + bool ParseArgs(int argc, const char** argv, bool& shouldContinue); + + bool m_verbose; + std::vector m_files_to_convert; + image_converter::Game m_game_to_convert_to; + +private: + /** + * \brief Prints a command line usage help text for the ImageConverter tool to stdout. + */ + static void PrintUsage(); + static void PrintVersion(); + + void SetVerbose(bool isVerbose); + + ArgumentParser m_argument_parser; +}; diff --git a/src/ImageConverter/main.cpp b/src/ImageConverter/main.cpp new file mode 100644 index 000000000..23145c364 --- /dev/null +++ b/src/ImageConverter/main.cpp @@ -0,0 +1,8 @@ +#include "ImageConverter.h" + +int main(const int argc, const char** argv) +{ + const auto imageConverter = ImageConverter::Create(); + + return imageConverter->Start(argc, argv) ? 0 : 1; +} diff --git a/src/Linker/Game/IW3/ZoneCreatorIW3.cpp b/src/Linker/Game/IW3/ZoneCreatorIW3.cpp index 399f01c4c..757abfe96 100644 --- a/src/Linker/Game/IW3/ZoneCreatorIW3.cpp +++ b/src/Linker/Game/IW3/ZoneCreatorIW3.cpp @@ -79,7 +79,7 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); } - const auto assetLoadingContext = std::make_unique(zone.get(), context.m_asset_search_path, CreateGdtList(context)); + const auto assetLoadingContext = std::make_unique(*zone, *context.m_asset_search_path, CreateGdtList(context)); if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) return nullptr; @@ -92,11 +92,11 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& return nullptr; } - if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name)) + if (!ObjLoading::LoadAssetForZone(*assetLoadingContext, foundAssetTypeEntry->second, assetEntry.m_asset_name)) return nullptr; } - ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); + ObjLoading::FinalizeAssetsForZone(*assetLoadingContext); return zone; } diff --git a/src/Linker/Game/IW4/ZoneCreatorIW4.cpp b/src/Linker/Game/IW4/ZoneCreatorIW4.cpp index d12cc7777..6d105c42c 100644 --- a/src/Linker/Game/IW4/ZoneCreatorIW4.cpp +++ b/src/Linker/Game/IW4/ZoneCreatorIW4.cpp @@ -78,7 +78,7 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); } - const auto assetLoadingContext = std::make_unique(zone.get(), context.m_asset_search_path, CreateGdtList(context)); + const auto assetLoadingContext = std::make_unique(*zone, *context.m_asset_search_path, CreateGdtList(context)); if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) return nullptr; @@ -91,11 +91,11 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& return nullptr; } - if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name)) + if (!ObjLoading::LoadAssetForZone(*assetLoadingContext, foundAssetTypeEntry->second, assetEntry.m_asset_name)) return nullptr; } - ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); + ObjLoading::FinalizeAssetsForZone(*assetLoadingContext); return zone; } diff --git a/src/Linker/Game/IW5/ZoneCreatorIW5.cpp b/src/Linker/Game/IW5/ZoneCreatorIW5.cpp index 7c3d1779b..c8acd7cca 100644 --- a/src/Linker/Game/IW5/ZoneCreatorIW5.cpp +++ b/src/Linker/Game/IW5/ZoneCreatorIW5.cpp @@ -78,7 +78,7 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); } - const auto assetLoadingContext = std::make_unique(zone.get(), context.m_asset_search_path, CreateGdtList(context)); + const auto assetLoadingContext = std::make_unique(*zone, *context.m_asset_search_path, CreateGdtList(context)); if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) return nullptr; @@ -91,11 +91,11 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& return nullptr; } - if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name)) + if (!ObjLoading::LoadAssetForZone(*assetLoadingContext, foundAssetTypeEntry->second, assetEntry.m_asset_name)) return nullptr; } - ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); + ObjLoading::FinalizeAssetsForZone(*assetLoadingContext); return zone; } diff --git a/src/Linker/Game/T5/ZoneCreatorT5.cpp b/src/Linker/Game/T5/ZoneCreatorT5.cpp index c08daea4c..21d71c25b 100644 --- a/src/Linker/Game/T5/ZoneCreatorT5.cpp +++ b/src/Linker/Game/T5/ZoneCreatorT5.cpp @@ -79,7 +79,7 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); } - const auto assetLoadingContext = std::make_unique(zone.get(), context.m_asset_search_path, CreateGdtList(context)); + const auto assetLoadingContext = std::make_unique(*zone, *context.m_asset_search_path, CreateGdtList(context)); if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) return nullptr; @@ -92,11 +92,11 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& return nullptr; } - if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name)) + if (!ObjLoading::LoadAssetForZone(*assetLoadingContext, foundAssetTypeEntry->second, assetEntry.m_asset_name)) return nullptr; } - ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); + ObjLoading::FinalizeAssetsForZone(*assetLoadingContext); return zone; } diff --git a/src/Linker/Game/T6/ZoneCreatorT6.cpp b/src/Linker/Game/T6/ZoneCreatorT6.cpp index 01bdf9964..9c0b56875 100644 --- a/src/Linker/Game/T6/ZoneCreatorT6.cpp +++ b/src/Linker/Game/T6/ZoneCreatorT6.cpp @@ -128,7 +128,7 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); } - const auto assetLoadingContext = std::make_unique(zone.get(), context.m_asset_search_path, CreateGdtList(context)); + const auto assetLoadingContext = std::make_unique(*zone, *context.m_asset_search_path, CreateGdtList(context)); if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) return nullptr; @@ -143,11 +143,11 @@ std::unique_ptr ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& return nullptr; } - if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name)) + if (!ObjLoading::LoadAssetForZone(*assetLoadingContext, foundAssetTypeEntry->second, assetEntry.m_asset_name)) return nullptr; } - ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); + ObjLoading::FinalizeAssetsForZone(*assetLoadingContext); return zone; } diff --git a/src/Linker/LinkerArgs.cpp b/src/Linker/LinkerArgs.cpp index 4617dfbbf..b7ca5f4ef 100644 --- a/src/Linker/LinkerArgs.cpp +++ b/src/Linker/LinkerArgs.cpp @@ -7,6 +7,7 @@ #include "Utils/FileUtils.h" #include +#include #include #include #include @@ -138,9 +139,9 @@ LinkerArgs::LinkerArgs() { } -void LinkerArgs::PrintUsage() +void LinkerArgs::PrintUsage() const { - UsageInformation usage("Linker.exe"); + UsageInformation usage(m_argument_parser.GetExecutableName()); for (const auto* commandLineOption : COMMAND_LINE_OPTIONS) { @@ -155,7 +156,7 @@ void LinkerArgs::PrintUsage() void LinkerArgs::PrintVersion() { - std::cout << "OpenAssetTools Linker " << std::string(GIT_VERSION) << "\n"; + std::cout << std::format("OpenAssetTools Linker {}\n", GIT_VERSION); } void LinkerArgs::SetBinFolder(const char* argv0) @@ -244,7 +245,7 @@ std::set LinkerArgs::GetSearchPathsForProject(const std::set +#include #include namespace fs = std::filesystem; @@ -14,21 +15,21 @@ LinkerSearchPaths::LinkerSearchPaths(const LinkerArgs& args) { } -void LinkerSearchPaths::LoadSearchPath(ISearchPath* searchPath) const +void LinkerSearchPaths::LoadSearchPath(ISearchPath& searchPath) const { if (m_args.m_verbose) { - printf("Loading search path: \"%s\"\n", searchPath->GetPath().c_str()); + std::cout << std::format("Loading search path: \"{}\"\n", searchPath.GetPath()); } ObjLoading::LoadIWDsInSearchPath(searchPath); } -void LinkerSearchPaths::UnloadSearchPath(ISearchPath* searchPath) const +void LinkerSearchPaths::UnloadSearchPath(ISearchPath& searchPath) const { if (m_args.m_verbose) { - printf("Unloading search path: \"%s\"\n", searchPath->GetPath().c_str()); + std::cout << std::format("Unloading search path: \"{}\"\n", searchPath.GetPath()); } ObjLoading::UnloadIWDsInSearchPath(searchPath); @@ -45,15 +46,15 @@ SearchPaths LinkerSearchPaths::GetAssetSearchPathsForProject(const std::string& if (!fs::is_directory(absolutePath)) { if (m_args.m_verbose) - std::cout << "Adding asset search path (Not found): " << absolutePath.string() << "\n"; + std::cout << std::format("Adding asset search path (Not found): {}\n", absolutePath.string()); continue; } if (m_args.m_verbose) - std::cout << "Adding asset search path: " << absolutePath.string() << "\n"; + std::cout << std::format("Adding asset search path: {}\n", absolutePath.string()); auto searchPath = std::make_unique(searchPathStr); - LoadSearchPath(searchPath.get()); + LoadSearchPath(*searchPath); searchPathsForProject.IncludeSearchPath(searchPath.get()); m_loaded_project_search_paths.emplace_back(std::move(searchPath)); } @@ -79,12 +80,12 @@ SearchPaths LinkerSearchPaths::GetGdtSearchPathsForProject(const std::string& ga if (!fs::is_directory(absolutePath)) { if (m_args.m_verbose) - std::cout << "Adding gdt search path (Not found): " << absolutePath.string() << "\n"; + std::cout << std::format("Adding gdt search path (Not found): {}\n", absolutePath.string()); continue; } if (m_args.m_verbose) - std::cout << "Adding gdt search path: " << absolutePath.string() << "\n"; + std::cout << std::format("Adding gdt search path: {}\n", absolutePath.string()); searchPathsForProject.CommitSearchPath(std::make_unique(searchPathStr)); } @@ -105,12 +106,12 @@ SearchPaths LinkerSearchPaths::GetSourceSearchPathsForProject(const std::string& if (!fs::is_directory(absolutePath)) { if (m_args.m_verbose) - std::cout << "Adding source search path (Not found): " << absolutePath.string() << "\n"; + std::cout << std::format("Adding source search path (Not found): {}\n", absolutePath.string()); continue; } if (m_args.m_verbose) - std::cout << "Adding source search path: " << absolutePath.string() << "\n"; + std::cout << std::format("Adding source search path: {}\n", absolutePath.string()); searchPathsForProject.CommitSearchPath(std::make_unique(searchPathStr)); } @@ -129,15 +130,15 @@ bool LinkerSearchPaths::BuildProjectIndependentSearchPaths() if (!fs::is_directory(absolutePath)) { if (m_args.m_verbose) - std::cout << "Adding asset search path (Not found): " << absolutePath.string() << "\n"; + std::cout << std::format("Adding asset search path (Not found): {}\n", absolutePath.string()); continue; } if (m_args.m_verbose) - std::cout << "Adding asset search path: " << absolutePath.string() << "\n"; + std::cout << std::format("Adding asset search path: {}\n", absolutePath.string()); auto searchPath = std::make_unique(absolutePath.string()); - LoadSearchPath(searchPath.get()); + LoadSearchPath(*searchPath); m_asset_search_paths.CommitSearchPath(std::move(searchPath)); } @@ -148,12 +149,12 @@ bool LinkerSearchPaths::BuildProjectIndependentSearchPaths() if (!fs::is_directory(absolutePath)) { if (m_args.m_verbose) - std::cout << "Loading gdt search path (Not found): " << absolutePath.string() << "\n"; + std::cout << std::format("Loading gdt search path (Not found): {}\n", absolutePath.string()); continue; } if (m_args.m_verbose) - std::cout << "Adding gdt search path: " << absolutePath.string() << "\n"; + std::cout << std::format("Adding gdt search path: {}\n", absolutePath.string()); m_gdt_search_paths.CommitSearchPath(std::make_unique(absolutePath.string())); } @@ -165,12 +166,12 @@ bool LinkerSearchPaths::BuildProjectIndependentSearchPaths() if (!fs::is_directory(absolutePath)) { if (m_args.m_verbose) - std::cout << "Loading source search path (Not found): " << absolutePath.string() << "\n"; + std::cout << std::format("Loading source search path (Not found): {}\n", absolutePath.string()); continue; } if (m_args.m_verbose) - std::cout << "Adding source search path: " << absolutePath.string() << "\n"; + std::cout << std::format("Adding source search path: {}\n", absolutePath.string()); m_source_search_paths.CommitSearchPath(std::make_unique(absolutePath.string())); } @@ -182,7 +183,7 @@ void LinkerSearchPaths::UnloadProjectSpecificSearchPaths() { for (const auto& loadedSearchPath : m_loaded_project_search_paths) { - UnloadSearchPath(loadedSearchPath.get()); + UnloadSearchPath(*loadedSearchPath); } m_loaded_project_search_paths.clear(); diff --git a/src/Linker/LinkerSearchPaths.h b/src/Linker/LinkerSearchPaths.h index e56f7a113..f570965e1 100644 --- a/src/Linker/LinkerSearchPaths.h +++ b/src/Linker/LinkerSearchPaths.h @@ -14,13 +14,13 @@ class LinkerSearchPaths * \brief Loads a search path. * \param searchPath The search path to load. */ - void LoadSearchPath(ISearchPath* searchPath) const; + void LoadSearchPath(ISearchPath& searchPath) const; /** * \brief Unloads a search path. * \param searchPath The search path to unload. */ - void UnloadSearchPath(ISearchPath* searchPath) const; + void UnloadSearchPath(ISearchPath& searchPath) const; SearchPaths GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName); diff --git a/src/ObjImage.lua b/src/ObjImage.lua new file mode 100644 index 000000000..bbb726210 --- /dev/null +++ b/src/ObjImage.lua @@ -0,0 +1,47 @@ +ObjImage = {} + +function ObjImage:include(includes) + if includes:handle(self:name()) then + includedirs { + path.join(ProjectFolder(), "ObjImage") + } + end +end + +function ObjImage:link(links) + links:add(self:name()) + links:linkto(Utils) +end + +function ObjImage:use() + +end + +function ObjImage:name() + return "ObjImage" +end + +function ObjImage:project() + local folder = ProjectFolder() + local includes = Includes:create() + + project(self:name()) + targetdir(TargetDirectoryLib) + location "%{wks.location}/src/%{prj.name}" + kind "StaticLib" + language "C++" + + files { + path.join(folder, "ObjImage/**.h"), + path.join(folder, "ObjImage/**.cpp") + } + + vpaths { + ["*"] = { + path.join(folder, "ObjImage") + } + } + + self:include(includes) + Utils:include(includes) +end diff --git a/src/Common/Image/D3DFormat.h b/src/ObjImage/Image/D3DFormat.h similarity index 100% rename from src/Common/Image/D3DFormat.h rename to src/ObjImage/Image/D3DFormat.h diff --git a/src/ObjImage/Image/DdsLoader.cpp b/src/ObjImage/Image/DdsLoader.cpp new file mode 100644 index 000000000..bc9e0c99c --- /dev/null +++ b/src/ObjImage/Image/DdsLoader.cpp @@ -0,0 +1,271 @@ +#include "DdsLoader.h" + +#include "Image/DdsTypes.h" +#include "Utils/ClassUtils.h" +#include "Utils/FileUtils.h" + +#include +#include +#include + +namespace dds +{ + class DdsLoaderInternal + { + static constexpr auto DDS_MAGIC = FileUtils::MakeMagic32('D', 'D', 'S', ' '); + + std::istream& m_stream; + + TextureType m_texture_type; + bool m_has_mip_maps; + size_t m_width; + size_t m_height; + size_t m_depth; + const ImageFormat* m_format; + + _NODISCARD bool ReadMagic() const + { + uint32_t magic; + m_stream.read(reinterpret_cast(&magic), sizeof(magic)); + if (m_stream.gcount() != sizeof(magic)) + { + std::cerr << "Failed to read dds data\n"; + return false; + } + + if (magic != DDS_MAGIC) + { + std::cerr << "Invalid magic for dds\n"; + return false; + } + + return true; + } + + _NODISCARD bool ReadDxt10Header() + { + DDS_HEADER_DXT10 headerDx10{}; + m_stream.read(reinterpret_cast(&headerDx10), sizeof(headerDx10)); + if (m_stream.gcount() != sizeof(headerDx10)) + { + std::cerr << "Failed to read dds data\n"; + return false; + } + + if (headerDx10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D) + { + m_texture_type = TextureType::T_3D; + } + else if (headerDx10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE2D) + { + if (headerDx10.miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE || headerDx10.arraySize == 6) + { + m_texture_type = TextureType::T_CUBE; + } + else + { + m_texture_type = TextureType::T_2D; + } + } + else + { + std::cerr << std::format("Unsupported dds resourceDimension {}\n", static_cast(headerDx10.resourceDimension)); + return false; + } + + for (const auto* imageFormat : ImageFormat::ALL_FORMATS) + { + if (imageFormat->GetDxgiFormat() == headerDx10.dxgiFormat) + { + m_format = imageFormat; + return true; + } + } + + std::cerr << std::format("Unsupported dds dxgi format {}\n", static_cast(headerDx10.dxgiFormat)); + return false; + } + + _NODISCARD bool ReadPixelFormatFourCc(DDS_PIXELFORMAT& pf) + { + switch (pf.dwFourCC) + { + case FileUtils::MakeMagic32('D', 'X', 'T', '1'): + m_format = &ImageFormat::FORMAT_BC1; + return true; + + case FileUtils::MakeMagic32('D', 'X', 'T', '3'): + m_format = &ImageFormat::FORMAT_BC2; + return true; + + case FileUtils::MakeMagic32('D', 'X', 'T', '5'): + m_format = &ImageFormat::FORMAT_BC3; + return true; + + case FileUtils::MakeMagic32('D', 'X', '1', '0'): + return ReadDxt10Header(); + + default: + std::cerr << std::format("Unknown dds FourCC {}\n", pf.dwFourCC); + return false; + } + } + + static void ExtractSizeAndOffsetFromMask(uint32_t mask, unsigned& offset, unsigned& size) + { + offset = 0; + size = 0; + + if (mask == 0) + return; + + while ((mask & 1) == 0) + { + offset++; + mask >>= 1; + } + + while ((mask & 1) == 1) + { + size++; + mask >>= 1; + } + } + + _NODISCARD bool ReadPixelFormatUnsigned(DDS_PIXELFORMAT& pf) + { + unsigned rOffset, rSize, gOffset, gSize, bOffset, bSize, aOffset, aSize; + + ExtractSizeAndOffsetFromMask(pf.dwRBitMask, rOffset, rSize); + ExtractSizeAndOffsetFromMask(pf.dwGBitMask, gOffset, gSize); + ExtractSizeAndOffsetFromMask(pf.dwBBitMask, bOffset, bSize); + ExtractSizeAndOffsetFromMask(pf.dwABitMask, aOffset, aSize); + + for (const auto* imageFormat : ImageFormat::ALL_FORMATS) + { + if (imageFormat->GetType() != ImageFormatType::UNSIGNED) + continue; + + const auto* unsignedImageFormat = dynamic_cast(imageFormat); + + if (unsignedImageFormat->m_r_offset == rOffset && unsignedImageFormat->m_r_size == rSize && unsignedImageFormat->m_g_offset == gOffset + && unsignedImageFormat->m_g_size == gSize && unsignedImageFormat->m_b_offset == bOffset && unsignedImageFormat->m_b_size == bSize + && unsignedImageFormat->m_a_offset == aOffset && unsignedImageFormat->m_a_size == aSize) + { + m_format = imageFormat; + return true; + } + } + + std::cerr << std::format( + "Failed to find dds pixel format: R={:#x} G={:#x} B={:#x} A={:#x}\n", pf.dwRBitMask, pf.dwGBitMask, pf.dwBBitMask, pf.dwABitMask); + + return false; + } + + _NODISCARD bool ReadPixelFormat(DDS_PIXELFORMAT& pf) + { + if (pf.dwFlags & DDPF_FOURCC) + return ReadPixelFormatFourCc(pf); + + return ReadPixelFormatUnsigned(pf); + } + + _NODISCARD bool ReadHeader() + { + DDS_HEADER header{}; + m_stream.read(reinterpret_cast(&header), sizeof(header)); + if (m_stream.gcount() != sizeof(header)) + { + std::cerr << "Failed to read dds data\n"; + return false; + } + + m_width = header.dwWidth; + m_height = header.dwHeight; + m_depth = header.dwDepth; + m_has_mip_maps = (header.dwCaps & DDSCAPS_MIPMAP) != 0 || header.dwMipMapCount > 1; + + if (header.dwCaps2 & DDSCAPS2_CUBEMAP) + m_texture_type = TextureType::T_CUBE; + else if (header.dwDepth > 1) + m_texture_type = TextureType::T_3D; + else + m_texture_type = TextureType::T_2D; + + return ReadPixelFormat(header.ddspf); + } + + _NODISCARD std::unique_ptr ReadTextureData() const + { + std::unique_ptr result; + + switch (m_texture_type) + { + case TextureType::T_2D: + result = std::make_unique(m_format, m_width, m_height, m_has_mip_maps); + break; + + case TextureType::T_3D: + result = std::make_unique(m_format, m_width, m_height, m_depth, m_has_mip_maps); + break; + + case TextureType::T_CUBE: + result = std::make_unique(m_format, m_width, m_height, m_has_mip_maps); + break; + + default: + return nullptr; + } + + const auto mipMapCount = m_has_mip_maps ? result->GetMipMapCount() : 1; + const auto faceCount = m_texture_type == TextureType::T_CUBE ? 6 : 1; + + result->Allocate(); + + for (auto mipLevel = 0; mipLevel < mipMapCount; mipLevel++) + { + const auto mipSize = result->GetSizeOfMipLevel(mipLevel); + + for (auto face = 0; face < faceCount; face++) + { + m_stream.read(reinterpret_cast(result->GetBufferForMipLevel(mipLevel, face)), mipSize); + + if (m_stream.gcount() != mipSize) + { + std::cerr << "Failed to read texture data from dds\n"; + return nullptr; + } + } + } + + return result; + } + + public: + explicit DdsLoaderInternal(std::istream& stream) + : m_stream(stream), + m_texture_type(TextureType::T_2D), + m_has_mip_maps(false), + m_width(0u), + m_height(0u), + m_depth(0u), + m_format(nullptr) + { + } + + std::unique_ptr LoadDds() + { + if (!ReadMagic() || !ReadHeader()) + return nullptr; + + return ReadTextureData(); + } + }; + + std::unique_ptr LoadDds(std::istream& stream) + { + DdsLoaderInternal internal(stream); + return internal.LoadDds(); + } +} // namespace dds diff --git a/src/ObjImage/Image/DdsLoader.h b/src/ObjImage/Image/DdsLoader.h new file mode 100644 index 000000000..90619b9f3 --- /dev/null +++ b/src/ObjImage/Image/DdsLoader.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Image/Texture.h" + +#include +#include + +namespace dds +{ + std::unique_ptr LoadDds(std::istream& stream); +} diff --git a/src/Common/Image/DdsTypes.h b/src/ObjImage/Image/DdsTypes.h similarity index 100% rename from src/Common/Image/DdsTypes.h rename to src/ObjImage/Image/DdsTypes.h diff --git a/src/ObjWriting/Image/DdsWriter.cpp b/src/ObjImage/Image/DdsWriter.cpp similarity index 95% rename from src/ObjWriting/Image/DdsWriter.cpp rename to src/ObjImage/Image/DdsWriter.cpp index 5ecf0ec42..324dad405 100644 --- a/src/ObjWriting/Image/DdsWriter.cpp +++ b/src/ObjImage/Image/DdsWriter.cpp @@ -13,10 +13,51 @@ const std::map DDS_CONVERSION_TABLE{ class DdsWriterInternal { - std::ostream& m_stream; - Texture* m_texture; - std::unique_ptr m_converted_texture; - bool m_use_dx10_extension; +public: + static bool SupportsImageFormat(const ImageFormat* imageFormat) + { + 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) + { + 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), mipLevelSize); + } + } static constexpr unsigned Mask1(const unsigned length) { @@ -164,61 +205,20 @@ class DdsWriterInternal void ConvertTextureIfNecessary() { - auto entry = DDS_CONVERSION_TABLE.find(m_texture->GetFormat()->GetId()); + 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 = std::unique_ptr(converter.Convert()); + m_converted_texture = converter.Convert(); m_texture = m_converted_texture.get(); } } -public: - static bool SupportsImageFormat(const ImageFormat* imageFormat) - { - return true; - } - - static std::string GetFileExtension() - { - return ".dds"; - } - - DdsWriterInternal(std::ostream& stream, 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) - { - 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), mipLevelSize); - } - } + std::ostream& m_stream; + const Texture* m_texture; + std::unique_ptr m_converted_texture; + bool m_use_dx10_extension; }; DdsWriter::~DdsWriter() = default; @@ -233,7 +233,7 @@ std::string DdsWriter::GetFileExtension() return DdsWriterInternal::GetFileExtension(); } -void DdsWriter::DumpImage(std::ostream& stream, Texture* texture) +void DdsWriter::DumpImage(std::ostream& stream, const Texture* texture) { DdsWriterInternal internal(stream, texture); internal.DumpImage(); diff --git a/src/ObjWriting/Image/DdsWriter.h b/src/ObjImage/Image/DdsWriter.h similarity index 76% rename from src/ObjWriting/Image/DdsWriter.h rename to src/ObjImage/Image/DdsWriter.h index e87cfa219..c6acbab40 100644 --- a/src/ObjWriting/Image/DdsWriter.h +++ b/src/ObjImage/Image/DdsWriter.h @@ -8,5 +8,5 @@ class DdsWriter final : public IImageWriter bool SupportsImageFormat(const ImageFormat* imageFormat) override; std::string GetFileExtension() override; - void DumpImage(std::ostream& stream, Texture* texture) override; + void DumpImage(std::ostream& stream, const Texture* texture) override; }; diff --git a/src/ObjLoading/Image/Dx12TextureLoader.cpp b/src/ObjImage/Image/Dx12TextureLoader.cpp similarity index 80% rename from src/ObjLoading/Image/Dx12TextureLoader.cpp rename to src/ObjImage/Image/Dx12TextureLoader.cpp index 880b1c15e..5402a4a86 100644 --- a/src/ObjLoading/Image/Dx12TextureLoader.cpp +++ b/src/ObjImage/Image/Dx12TextureLoader.cpp @@ -2,9 +2,8 @@ #include -Dx12TextureLoader::Dx12TextureLoader(MemoryManager* memoryManager) - : m_memory_manager(memoryManager), - m_format(oat::DXGI_FORMAT_UNKNOWN), +Dx12TextureLoader::Dx12TextureLoader() + : m_format(oat::DXGI_FORMAT_UNKNOWN), m_type(TextureType::T_2D), m_has_mip_maps(false), m_width(1u), @@ -60,26 +59,26 @@ Dx12TextureLoader& Dx12TextureLoader::Depth(const size_t depth) return *this; } -Texture* Dx12TextureLoader::LoadTexture(const void* data) +std::unique_ptr Dx12TextureLoader::LoadTexture(const void* data) { const auto* format = GetFormatForDx12Format(); if (format == nullptr) return nullptr; - Texture* texture; + std::unique_ptr texture; switch (m_type) { case TextureType::T_2D: - texture = m_memory_manager->Create(format, m_width, m_height, m_has_mip_maps); + texture = std::make_unique(format, m_width, m_height, m_has_mip_maps); break; case TextureType::T_3D: - texture = m_memory_manager->Create(format, m_width, m_height, m_depth, m_has_mip_maps); + texture = std::make_unique(format, m_width, m_height, m_depth, m_has_mip_maps); break; case TextureType::T_CUBE: - texture = m_memory_manager->Create(format, m_width, m_width, m_has_mip_maps); + texture = std::make_unique(format, m_width, m_width, m_has_mip_maps); break; default: diff --git a/src/ObjLoading/Image/Dx12TextureLoader.h b/src/ObjImage/Image/Dx12TextureLoader.h similarity index 84% rename from src/ObjLoading/Image/Dx12TextureLoader.h rename to src/ObjImage/Image/Dx12TextureLoader.h index f86b2ffa7..9309f9e46 100644 --- a/src/ObjLoading/Image/Dx12TextureLoader.h +++ b/src/ObjImage/Image/Dx12TextureLoader.h @@ -5,24 +5,13 @@ #include "Utils/ClassUtils.h" #include "Utils/MemoryManager.h" +#include #include class Dx12TextureLoader { - static std::unordered_map m_conversion_table; - - MemoryManager* m_memory_manager; - oat::DXGI_FORMAT m_format; - TextureType m_type; - bool m_has_mip_maps; - size_t m_width; - size_t m_height; - size_t m_depth; - - _NODISCARD const ImageFormat* GetFormatForDx12Format() const; - public: - explicit Dx12TextureLoader(MemoryManager* memoryManager); + Dx12TextureLoader(); Dx12TextureLoader& Format(oat::DXGI_FORMAT format); Dx12TextureLoader& Type(TextureType textureType); @@ -31,5 +20,17 @@ class Dx12TextureLoader Dx12TextureLoader& Height(size_t height); Dx12TextureLoader& Depth(size_t depth); - Texture* LoadTexture(const void* data); + std::unique_ptr LoadTexture(const void* data); + +private: + _NODISCARD const ImageFormat* GetFormatForDx12Format() const; + + static std::unordered_map m_conversion_table; + + oat::DXGI_FORMAT m_format; + TextureType m_type; + bool m_has_mip_maps; + size_t m_width; + size_t m_height; + size_t m_depth; }; diff --git a/src/ObjLoading/Image/Dx9TextureLoader.cpp b/src/ObjImage/Image/Dx9TextureLoader.cpp similarity index 78% rename from src/ObjLoading/Image/Dx9TextureLoader.cpp rename to src/ObjImage/Image/Dx9TextureLoader.cpp index 1fe4f60d1..7c3ba93bd 100644 --- a/src/ObjLoading/Image/Dx9TextureLoader.cpp +++ b/src/ObjImage/Image/Dx9TextureLoader.cpp @@ -2,9 +2,8 @@ #include -Dx9TextureLoader::Dx9TextureLoader(MemoryManager* memoryManager) - : m_memory_manager(memoryManager), - m_format(oat::D3DFMT_UNKNOWN), +Dx9TextureLoader::Dx9TextureLoader() + : m_format(oat::D3DFMT_UNKNOWN), m_type(TextureType::T_2D), m_has_mip_maps(false), m_width(1u), @@ -15,7 +14,7 @@ Dx9TextureLoader::Dx9TextureLoader(MemoryManager* memoryManager) const ImageFormat* Dx9TextureLoader::GetFormatForDx9Format() const { - for (auto i : ImageFormat::ALL_FORMATS) + for (const auto* i : ImageFormat::ALL_FORMATS) { if (i->GetD3DFormat() == m_format) return i; @@ -60,26 +59,26 @@ Dx9TextureLoader& Dx9TextureLoader::Depth(const size_t depth) return *this; } -Texture* Dx9TextureLoader::LoadTexture(const void* data) +std::unique_ptr Dx9TextureLoader::LoadTexture(const void* data) { const auto* format = GetFormatForDx9Format(); if (format == nullptr) return nullptr; - Texture* texture; + std::unique_ptr texture; switch (m_type) { case TextureType::T_2D: - texture = m_memory_manager->Create(format, m_width, m_height, m_has_mip_maps); + texture = std::make_unique(format, m_width, m_height, m_has_mip_maps); break; case TextureType::T_3D: - texture = m_memory_manager->Create(format, m_width, m_height, m_depth, m_has_mip_maps); + texture = std::make_unique(format, m_width, m_height, m_depth, m_has_mip_maps); break; case TextureType::T_CUBE: - texture = m_memory_manager->Create(format, m_width, m_width, m_has_mip_maps); + texture = std::make_unique(format, m_width, m_width, m_has_mip_maps); break; default: diff --git a/src/ObjLoading/Image/Dx9TextureLoader.h b/src/ObjImage/Image/Dx9TextureLoader.h similarity index 82% rename from src/ObjLoading/Image/Dx9TextureLoader.h rename to src/ObjImage/Image/Dx9TextureLoader.h index 441317939..5baa52665 100644 --- a/src/ObjLoading/Image/Dx9TextureLoader.h +++ b/src/ObjImage/Image/Dx9TextureLoader.h @@ -5,22 +5,13 @@ #include "Utils/ClassUtils.h" #include "Utils/MemoryManager.h" +#include #include class Dx9TextureLoader { - MemoryManager* m_memory_manager; - oat::D3DFORMAT m_format; - TextureType m_type; - bool m_has_mip_maps; - size_t m_width; - size_t m_height; - size_t m_depth; - - _NODISCARD const ImageFormat* GetFormatForDx9Format() const; - public: - explicit Dx9TextureLoader(MemoryManager* memoryManager); + Dx9TextureLoader(); Dx9TextureLoader& Format(oat::D3DFORMAT format); Dx9TextureLoader& Type(TextureType textureType); @@ -29,5 +20,15 @@ class Dx9TextureLoader Dx9TextureLoader& Height(size_t height); Dx9TextureLoader& Depth(size_t depth); - Texture* LoadTexture(const void* data); + std::unique_ptr LoadTexture(const void* data); + +private: + _NODISCARD const ImageFormat* GetFormatForDx9Format() const; + + oat::D3DFORMAT m_format; + TextureType m_type; + bool m_has_mip_maps; + size_t m_width; + size_t m_height; + size_t m_depth; }; diff --git a/src/Common/Image/DxgiFormat.h b/src/ObjImage/Image/DxgiFormat.h similarity index 100% rename from src/Common/Image/DxgiFormat.h rename to src/ObjImage/Image/DxgiFormat.h diff --git a/src/ObjImage/Image/IImageWriter.h b/src/ObjImage/Image/IImageWriter.h new file mode 100644 index 000000000..ed116416d --- /dev/null +++ b/src/ObjImage/Image/IImageWriter.h @@ -0,0 +1,21 @@ +#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/Common/Image/ImageFormat.cpp b/src/ObjImage/Image/ImageFormat.cpp similarity index 100% rename from src/Common/Image/ImageFormat.cpp rename to src/ObjImage/Image/ImageFormat.cpp diff --git a/src/Common/Image/ImageFormat.h b/src/ObjImage/Image/ImageFormat.h similarity index 100% rename from src/Common/Image/ImageFormat.h rename to src/ObjImage/Image/ImageFormat.h diff --git a/src/ObjImage/Image/IwiLoader.cpp b/src/ObjImage/Image/IwiLoader.cpp new file mode 100644 index 000000000..8d6bc028a --- /dev/null +++ b/src/ObjImage/Image/IwiLoader.cpp @@ -0,0 +1,443 @@ +#include "IwiLoader.h" + +#include "Image/IwiTypes.h" + +#include +#include +#include +#include + +namespace iwi +{ + const ImageFormat* GetFormat6(int8_t format) + { + switch (static_cast(format)) + { + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_RGBA: + return &ImageFormat::FORMAT_R8_G8_B8_A8; + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_RGB: + return &ImageFormat::FORMAT_R8_G8_B8; + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: + return &ImageFormat::FORMAT_A8; + case iwi6::IwiFormat::IMG_FORMAT_DXT1: + return &ImageFormat::FORMAT_BC1; + case iwi6::IwiFormat::IMG_FORMAT_DXT3: + return &ImageFormat::FORMAT_BC2; + case iwi6::IwiFormat::IMG_FORMAT_DXT5: + return &ImageFormat::FORMAT_BC3; + case iwi6::IwiFormat::IMG_FORMAT_DXN: + return &ImageFormat::FORMAT_BC5; + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: + return &ImageFormat::FORMAT_R8_A8; + case iwi6::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: + return &ImageFormat::FORMAT_R8; + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_RGBA: // used + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_RGB: // used + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: + case iwi6::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: + std::cerr << std::format("Unsupported IWI format: {}\n", format); + break; + default: + std::cerr << std::format("Unknown IWI format: {}\n", format); + break; + } + + return nullptr; + } + + std::unique_ptr LoadIwi6(std::istream& stream) + { + iwi6::IwiHeader header{}; + + stream.read(reinterpret_cast(&header), sizeof(header)); + if (stream.gcount() != sizeof(header)) + return nullptr; + + const auto* format = GetFormat6(header.format); + if (format == nullptr) + return nullptr; + + auto width = header.dimensions[0]; + auto height = header.dimensions[1]; + auto depth = header.dimensions[2]; + auto hasMipMaps = !(header.flags & iwi6::IwiFlags::IMG_FLAG_NOMIPMAPS); + + std::unique_ptr texture; + if (header.flags & iwi6::IwiFlags::IMG_FLAG_CUBEMAP) + texture = std::make_unique(format, width, height, hasMipMaps); + else if (header.flags & iwi6::IwiFlags::IMG_FLAG_VOLMAP) + texture = std::make_unique(format, width, height, depth, hasMipMaps); + else + texture = std::make_unique(format, width, height, hasMipMaps); + + texture->Allocate(); + + auto currentFileSize = sizeof(iwi6::IwiHeader) + sizeof(IwiVersion); + const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; + + for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) + { + const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); + currentFileSize += sizeOfMipLevel; + + if (currentMipLevel < static_cast(std::extent_v) + && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) + { + std::cerr << std::format("Iwi has invalid file size for picmip {}\n", currentMipLevel); + return nullptr; + } + + stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); + if (stream.gcount() != sizeOfMipLevel) + { + std::cerr << std::format("Unexpected eof of iwi in mip level {}\n", currentMipLevel); + return nullptr; + } + } + + return texture; + } + + const ImageFormat* GetFormat8(int8_t format) + { + switch (static_cast(format)) + { + case iwi8::IwiFormat::IMG_FORMAT_BITMAP_RGBA: + return &ImageFormat::FORMAT_R8_G8_B8_A8; + case iwi8::IwiFormat::IMG_FORMAT_BITMAP_RGB: + return &ImageFormat::FORMAT_R8_G8_B8; + case iwi8::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: + return &ImageFormat::FORMAT_A8; + case iwi8::IwiFormat::IMG_FORMAT_DXT1: + return &ImageFormat::FORMAT_BC1; + case iwi8::IwiFormat::IMG_FORMAT_DXT3: + return &ImageFormat::FORMAT_BC2; + case iwi8::IwiFormat::IMG_FORMAT_DXT5: + return &ImageFormat::FORMAT_BC3; + case iwi8::IwiFormat::IMG_FORMAT_DXN: + return &ImageFormat::FORMAT_BC5; + case iwi8::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: + return &ImageFormat::FORMAT_R8_A8; + case iwi8::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: + return &ImageFormat::FORMAT_R8; + case iwi8::IwiFormat::IMG_FORMAT_WAVELET_RGBA: // used + case iwi8::IwiFormat::IMG_FORMAT_WAVELET_RGB: // used + case iwi8::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: + case iwi8::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: + case iwi8::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: + case iwi8::IwiFormat::IMG_FORMAT_DXT3A_AS_LUMINANCE: + case iwi8::IwiFormat::IMG_FORMAT_DXT5A_AS_LUMINANCE: + case iwi8::IwiFormat::IMG_FORMAT_DXT3A_AS_ALPHA: + case iwi8::IwiFormat::IMG_FORMAT_DXT5A_AS_ALPHA: + case iwi8::IwiFormat::IMG_FORMAT_DXT1_AS_LUMINANCE_ALPHA: + case iwi8::IwiFormat::IMG_FORMAT_DXN_AS_LUMINANCE_ALPHA: + case iwi8::IwiFormat::IMG_FORMAT_DXT1_AS_LUMINANCE: + case iwi8::IwiFormat::IMG_FORMAT_DXT1_AS_ALPHA: + std::cerr << std::format("Unsupported IWI format: {}\n", format); + break; + default: + std::cerr << std::format("Unknown IWI format: {}\n", format); + break; + } + + return nullptr; + } + + std::unique_ptr LoadIwi8(std::istream& stream) + { + iwi8::IwiHeader header{}; + + stream.read(reinterpret_cast(&header), sizeof(header)); + if (stream.gcount() != sizeof(header)) + return nullptr; + + const auto* format = GetFormat8(header.format); + if (format == nullptr) + return nullptr; + + auto width = header.dimensions[0]; + auto height = header.dimensions[1]; + auto depth = header.dimensions[2]; + auto hasMipMaps = !(header.flags & iwi8::IwiFlags::IMG_FLAG_NOMIPMAPS); + + std::unique_ptr texture; + if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_CUBE) + { + texture = std::make_unique(format, width, height, hasMipMaps); + } + else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_3D) + { + texture = std::make_unique(format, width, height, depth, hasMipMaps); + } + else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_2D) + { + texture = std::make_unique(format, width, height, hasMipMaps); + } + else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_1D) + { + std::cerr << "Iwi has unsupported map type 1D\n"; + return nullptr; + } + else + { + std::cerr << "Iwi has unsupported map type\n"; + return nullptr; + } + + texture->Allocate(); + + auto currentFileSize = sizeof(iwi8::IwiHeader) + sizeof(IwiVersion); + const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; + + for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) + { + const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); + currentFileSize += sizeOfMipLevel; + + if (currentMipLevel < static_cast(std::extent_v) + && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) + { + std::cerr << std::format("Iwi has invalid file size for picmip {}\n", currentMipLevel); + return nullptr; + } + + stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); + if (stream.gcount() != sizeOfMipLevel) + { + std::cerr << std::format("Unexpected eof of iwi in mip level {}\n", currentMipLevel); + return nullptr; + } + } + + return texture; + } + + const ImageFormat* GetFormat13(int8_t format) + { + switch (static_cast(format)) + { + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGBA: + return &ImageFormat::FORMAT_R8_G8_B8_A8; + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGB: + return &ImageFormat::FORMAT_R8_G8_B8; + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: + return &ImageFormat::FORMAT_A8; + case iwi13::IwiFormat::IMG_FORMAT_DXT1: + return &ImageFormat::FORMAT_BC1; + case iwi13::IwiFormat::IMG_FORMAT_DXT3: + return &ImageFormat::FORMAT_BC2; + case iwi13::IwiFormat::IMG_FORMAT_DXT5: + return &ImageFormat::FORMAT_BC3; + case iwi13::IwiFormat::IMG_FORMAT_DXN: + return &ImageFormat::FORMAT_BC5; + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: + return &ImageFormat::FORMAT_R8_A8; + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: + return &ImageFormat::FORMAT_R8; + case iwi13::IwiFormat::IMG_FORMAT_WAVELET_RGBA: // used + case iwi13::IwiFormat::IMG_FORMAT_WAVELET_RGB: // used + case iwi13::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: + case iwi13::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: + case iwi13::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGB565: + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGB5A3: + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_C8: + case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGBA8: + case iwi13::IwiFormat::IMG_FORMAT_A16B16G16R16F: + std::cerr << std::format("Unsupported IWI format: {}\n", format); + break; + default: + std::cerr << std::format("Unknown IWI format: {}\n", format); + break; + } + + return nullptr; + } + + std::unique_ptr LoadIwi13(std::istream& stream) + { + iwi13::IwiHeader header{}; + + stream.read(reinterpret_cast(&header), sizeof(header)); + if (stream.gcount() != sizeof(header)) + return nullptr; + + const auto* format = GetFormat6(header.format); + if (format == nullptr) + return nullptr; + + auto width = header.dimensions[0]; + auto height = header.dimensions[1]; + auto depth = header.dimensions[2]; + auto hasMipMaps = !(header.flags & iwi13::IwiFlags::IMG_FLAG_NOMIPMAPS); + + std::unique_ptr texture; + if (header.flags & iwi13::IwiFlags::IMG_FLAG_CUBEMAP) + texture = std::make_unique(format, width, height, hasMipMaps); + else if (header.flags & iwi13::IwiFlags::IMG_FLAG_VOLMAP) + texture = std::make_unique(format, width, height, depth, hasMipMaps); + else + texture = std::make_unique(format, width, height, hasMipMaps); + + texture->Allocate(); + + auto currentFileSize = sizeof(iwi13::IwiHeader) + sizeof(IwiVersion); + const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; + + for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) + { + const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); + currentFileSize += sizeOfMipLevel; + + if (currentMipLevel < static_cast(std::extent_v) + && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) + { + std::cerr << std::format("Iwi has invalid file size for picmip {}\n", currentMipLevel); + return nullptr; + } + + stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); + if (stream.gcount() != sizeOfMipLevel) + { + std::cerr << std::format("Unexpected eof of iwi in mip level {}\n", currentMipLevel); + return nullptr; + } + } + + return texture; + } + + const ImageFormat* GetFormat27(int8_t format) + { + switch (static_cast(format)) + { + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGBA: + return &ImageFormat::FORMAT_R8_G8_B8_A8; + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: + return &ImageFormat::FORMAT_A8; + case iwi27::IwiFormat::IMG_FORMAT_DXT1: + return &ImageFormat::FORMAT_BC1; + case iwi27::IwiFormat::IMG_FORMAT_DXT3: + return &ImageFormat::FORMAT_BC2; + case iwi27::IwiFormat::IMG_FORMAT_DXT5: + return &ImageFormat::FORMAT_BC3; + case iwi27::IwiFormat::IMG_FORMAT_DXN: + return &ImageFormat::FORMAT_BC5; + case iwi27::IwiFormat::IMG_FORMAT_A16B16G16R16F: + assert(false); // Unsupported yet + return &ImageFormat::FORMAT_R16_G16_B16_A16_FLOAT; + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB: + return &ImageFormat::FORMAT_R8_G8_B8; + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: + return &ImageFormat::FORMAT_R8_A8; + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: + return &ImageFormat::FORMAT_R8; + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_RGBA: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_RGB: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: + case iwi27::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB565: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB5A3: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_C8: + case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGBA8: + std::cerr << std::format("Unsupported IWI format: {}\n", format); + break; + default: + std::cerr << std::format("Unknown IWI format: {}\n", format); + break; + } + + return nullptr; + } + + std::unique_ptr LoadIwi27(std::istream& stream) + { + iwi27::IwiHeader header{}; + + stream.read(reinterpret_cast(&header), sizeof(header)); + if (stream.gcount() != sizeof(header)) + return nullptr; + + const auto* format = GetFormat27(header.format); + if (format == nullptr) + return nullptr; + + auto width = header.dimensions[0]; + auto height = header.dimensions[1]; + auto depth = header.dimensions[2]; + auto hasMipMaps = !(header.flags & iwi27::IwiFlags::IMG_FLAG_NOMIPMAPS); + + std::unique_ptr texture; + if (header.flags & iwi27::IwiFlags::IMG_FLAG_CUBEMAP) + texture = std::make_unique(format, width, height, hasMipMaps); + else if (header.flags & iwi27::IwiFlags::IMG_FLAG_VOLMAP) + texture = std::make_unique(format, width, height, depth, hasMipMaps); + else + texture = std::make_unique(format, width, height, hasMipMaps); + + texture->Allocate(); + + auto currentFileSize = sizeof(iwi27::IwiHeader) + sizeof(IwiVersion); + const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; + + for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) + { + const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); + currentFileSize += sizeOfMipLevel; + + if (currentMipLevel < static_cast(std::extent_v) + && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) + { + std::cerr << std::format("Iwi has invalid file size for picmip {}\n", currentMipLevel); + return nullptr; + } + + stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); + if (stream.gcount() != sizeOfMipLevel) + { + std::cerr << std::format("Unexpected eof of iwi in mip level {}\n", currentMipLevel); + return nullptr; + } + } + + return texture; + } + + std::unique_ptr LoadIwi(std::istream& stream) + { + IwiVersion iwiVersion{}; + + 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') + { + std::cerr << "Invalid IWI magic\n"; + return nullptr; + } + + switch (iwiVersion.version) + { + case 6: + return LoadIwi6(stream); + + case 8: + return LoadIwi8(stream); + + case 13: + return LoadIwi13(stream); + + case 27: + return LoadIwi27(stream); + + default: + break; + } + + std::cerr << std::format("Unknown IWI version {}\n", iwiVersion.version); + return nullptr; + } +} // namespace iwi diff --git a/src/ObjImage/Image/IwiLoader.h b/src/ObjImage/Image/IwiLoader.h new file mode 100644 index 000000000..a1f65c65a --- /dev/null +++ b/src/ObjImage/Image/IwiLoader.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Image/Texture.h" + +#include +#include + +namespace iwi +{ + std::unique_ptr LoadIwi(std::istream& stream); +}; // namespace iwi diff --git a/src/Common/Image/IwiTypes.h b/src/ObjImage/Image/IwiTypes.h similarity index 100% rename from src/Common/Image/IwiTypes.h rename to src/ObjImage/Image/IwiTypes.h diff --git a/src/ObjImage/Image/IwiWriter13.cpp b/src/ObjImage/Image/IwiWriter13.cpp new file mode 100644 index 000000000..b354b6bfc --- /dev/null +++ b/src/ObjImage/Image/IwiWriter13.cpp @@ -0,0 +1,141 @@ +#include "IwiWriter13.h" + +#include +#include + +using namespace iwi13; + +IwiWriter::IwiWriter() = default; + +IwiWriter::~IwiWriter() = default; + +IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat) +{ + switch (imageFormat->GetId()) + { + case ImageFormatId::R8_G8_B8: + return IwiFormat::IMG_FORMAT_BITMAP_RGB; + + case ImageFormatId::R8_G8_B8_A8: + return IwiFormat::IMG_FORMAT_BITMAP_RGBA; + + case ImageFormatId::A8: + return IwiFormat::IMG_FORMAT_BITMAP_ALPHA; + + case ImageFormatId::R16_G16_B16_A16_FLOAT: + return IwiFormat::IMG_FORMAT_A16B16G16R16F; + + case ImageFormatId::BC1: + return IwiFormat::IMG_FORMAT_DXT1; + + case ImageFormatId::BC2: + return IwiFormat::IMG_FORMAT_DXT3; + + case ImageFormatId::BC3: + return IwiFormat::IMG_FORMAT_DXT5; + + case ImageFormatId::BC5: + return IwiFormat::IMG_FORMAT_DXN; + + default: + return IwiFormat::IMG_FORMAT_INVALID; + } +} + +bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat) +{ + return GetIwiFormatForImageFormat(imageFormat) != IwiFormat::IMG_FORMAT_INVALID; +} + +std::string IwiWriter::GetFileExtension() +{ + return ".iwi"; +} + +void IwiWriter::WriteVersion(std::ostream& stream) +{ + IwiVersion version{}; + version.tag[0] = 'I'; + version.tag[1] = 'W'; + version.tag[2] = 'i'; + version.version = 13; + + stream.write(reinterpret_cast(&version), sizeof(IwiVersion)); +} + +void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture) +{ + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = 1; +} + +void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture) +{ + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = 1; + header.flags |= IMG_FLAG_CUBEMAP; +} + +void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture) +{ + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = static_cast(texture.GetDepth()); + header.flags |= IMG_FLAG_VOLMAP; +} + +void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture) +{ + assert(texture != nullptr); + + WriteVersion(stream); + + IwiHeader header{}; + header.flags = 0; + header.gamma = 0.0f; + + header.format = static_cast(GetIwiFormatForImageFormat(texture->GetFormat())); + + if (!texture->HasMipMaps()) + header.flags |= IMG_FLAG_NOMIPMAPS; + + auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader); + + const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1; + for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) + { + const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); + currentFileSize += mipLevelSize; + + if (currentMipLevel < static_cast(std::extent_v)) + header.fileSizeForPicmip[currentMipLevel] = currentFileSize; + } + + if (const auto* texture2D = dynamic_cast(texture)) + { + FillHeader2D(header, *texture2D); + } + else if (const auto* textureCube = dynamic_cast(texture)) + { + FillHeaderCube(header, *textureCube); + } + else if (const auto* texture3D = dynamic_cast(texture)) + { + FillHeader3D(header, *texture3D); + } + else + { + assert(false); + return; + } + + stream.write(reinterpret_cast(&header), sizeof(IwiHeader)); + + for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) + { + const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); + stream.write(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); + } +} diff --git a/src/ObjImage/Image/IwiWriter13.h b/src/ObjImage/Image/IwiWriter13.h new file mode 100644 index 000000000..4b8109b64 --- /dev/null +++ b/src/ObjImage/Image/IwiWriter13.h @@ -0,0 +1,30 @@ +#pragma once + +#include "IImageWriter.h" +#include "Image/IwiTypes.h" + +namespace iwi13 +{ + class IwiWriter final : public IImageWriter + { + static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); + + static void WriteVersion(std::ostream& stream); + static void FillHeader2D(IwiHeader& header, const Texture2D& texture); + static void FillHeaderCube(IwiHeader& header, const TextureCube& texture); + static void FillHeader3D(IwiHeader& header, const Texture3D& texture); + + public: + IwiWriter(); + IwiWriter(const IwiWriter& other) = delete; + IwiWriter(IwiWriter&& other) noexcept = delete; + ~IwiWriter() override; + + IwiWriter& operator=(const IwiWriter& other) = delete; + IwiWriter& operator=(IwiWriter&& other) noexcept = delete; + + bool SupportsImageFormat(const ImageFormat* imageFormat) override; + std::string GetFileExtension() override; + void DumpImage(std::ostream& stream, const Texture* texture) override; + }; +} // namespace iwi13 diff --git a/src/ObjWriting/Image/IwiWriter27.cpp b/src/ObjImage/Image/IwiWriter27.cpp similarity index 67% rename from src/ObjWriting/Image/IwiWriter27.cpp rename to src/ObjImage/Image/IwiWriter27.cpp index 4641b4f60..06dbfd9f1 100644 --- a/src/ObjWriting/Image/IwiWriter27.cpp +++ b/src/ObjImage/Image/IwiWriter27.cpp @@ -63,30 +63,30 @@ void IwiWriter::WriteVersion(std::ostream& stream) stream.write(reinterpret_cast(&version), sizeof(IwiVersion)); } -void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture) +void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = 1; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = 1; } -void IwiWriter::FillHeaderCube(IwiHeader* header, TextureCube* texture) +void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = 1; - header->flags |= IMG_FLAG_CUBEMAP; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = 1; + header.flags |= IMG_FLAG_CUBEMAP; } -void IwiWriter::FillHeader3D(IwiHeader* header, Texture3D* texture) +void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = static_cast(texture->GetDepth()); - header->flags |= IMG_FLAG_VOLMAP; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = static_cast(texture.GetDepth()); + header.flags |= IMG_FLAG_VOLMAP; } -void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) +void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture) { assert(texture != nullptr); @@ -116,17 +116,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) header.fileSizeForPicmip[currentMipLevel] = currentFileSize; } - if (auto* texture2D = dynamic_cast(texture)) + if (const auto* texture2D = dynamic_cast(texture)) { - FillHeader2D(&header, texture2D); + FillHeader2D(header, *texture2D); } - else if (auto* textureCube = dynamic_cast(texture)) + else if (const auto* textureCube = dynamic_cast(texture)) { - FillHeaderCube(&header, textureCube); + FillHeaderCube(header, *textureCube); } - else if (auto* texture3D = dynamic_cast(texture)) + else if (const auto* texture3D = dynamic_cast(texture)) { - FillHeader3D(&header, texture3D); + FillHeader3D(header, *texture3D); } else { @@ -139,6 +139,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) { const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); - stream.write(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); + stream.write(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); } } diff --git a/src/ObjWriting/Image/IwiWriter27.h b/src/ObjImage/Image/IwiWriter27.h similarity index 69% rename from src/ObjWriting/Image/IwiWriter27.h rename to src/ObjImage/Image/IwiWriter27.h index 3541013c4..4f47dd1ab 100644 --- a/src/ObjWriting/Image/IwiWriter27.h +++ b/src/ObjImage/Image/IwiWriter27.h @@ -10,9 +10,9 @@ namespace iwi27 static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); static void WriteVersion(std::ostream& stream); - static void FillHeader2D(IwiHeader* header, Texture2D* texture); - static void FillHeaderCube(IwiHeader* header, TextureCube* texture); - static void FillHeader3D(IwiHeader* header, Texture3D* texture); + static void FillHeader2D(IwiHeader& header, const Texture2D& texture); + static void FillHeaderCube(IwiHeader& header, const TextureCube& texture); + static void FillHeader3D(IwiHeader& header, const Texture3D& texture); public: IwiWriter(); @@ -25,6 +25,6 @@ namespace iwi27 bool SupportsImageFormat(const ImageFormat* imageFormat) override; std::string GetFileExtension() override; - void DumpImage(std::ostream& stream, Texture* texture) override; + void DumpImage(std::ostream& stream, const Texture* texture) override; }; } // namespace iwi27 diff --git a/src/ObjWriting/Image/IwiWriter6.cpp b/src/ObjImage/Image/IwiWriter6.cpp similarity index 65% rename from src/ObjWriting/Image/IwiWriter6.cpp rename to src/ObjImage/Image/IwiWriter6.cpp index 9709e45b7..af6102def 100644 --- a/src/ObjWriting/Image/IwiWriter6.cpp +++ b/src/ObjImage/Image/IwiWriter6.cpp @@ -49,27 +49,27 @@ void IwiWriter::WriteVersion(std::ostream& stream) stream.write(reinterpret_cast(&version), sizeof(IwiVersion)); } -void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture) +void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = 1u; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = 1u; } -void IwiWriter::FillHeaderCube(IwiHeader* header, TextureCube* texture) +void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = 1u; - header->flags |= IMG_FLAG_CUBEMAP; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = 1u; + header.flags |= IMG_FLAG_CUBEMAP; } -void IwiWriter::FillHeader3D(IwiHeader* header, Texture3D* texture) +void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = static_cast(texture->GetDepth()); - header->flags |= IMG_FLAG_VOLMAP; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = static_cast(texture.GetDepth()); + header.flags |= IMG_FLAG_VOLMAP; } bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat) @@ -82,7 +82,7 @@ std::string IwiWriter::GetFileExtension() return ".iwi"; } -void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) +void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture) { assert(texture != nullptr); @@ -108,17 +108,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) header.fileSizeForPicmip[currentMipLevel] = currentFileSize; } - if (auto* texture2D = dynamic_cast(texture)) + if (const auto* texture2D = dynamic_cast(texture)) { - FillHeader2D(&header, texture2D); + FillHeader2D(header, *texture2D); } - else if (auto* textureCube = dynamic_cast(texture)) + else if (const auto* textureCube = dynamic_cast(texture)) { - FillHeaderCube(&header, textureCube); + FillHeaderCube(header, *textureCube); } - else if (auto* texture3D = dynamic_cast(texture)) + else if (const auto* texture3D = dynamic_cast(texture)) { - FillHeader3D(&header, texture3D); + FillHeader3D(header, *texture3D); } else { @@ -131,6 +131,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) { const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); - stream.write(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); + stream.write(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); } } diff --git a/src/ObjWriting/Image/IwiWriter6.h b/src/ObjImage/Image/IwiWriter6.h similarity index 69% rename from src/ObjWriting/Image/IwiWriter6.h rename to src/ObjImage/Image/IwiWriter6.h index ad8d618dd..79f414dd8 100644 --- a/src/ObjWriting/Image/IwiWriter6.h +++ b/src/ObjImage/Image/IwiWriter6.h @@ -10,9 +10,9 @@ namespace iwi6 static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); static void WriteVersion(std::ostream& stream); - static void FillHeader2D(IwiHeader* header, Texture2D* texture); - static void FillHeaderCube(IwiHeader* header, TextureCube* texture); - static void FillHeader3D(IwiHeader* header, Texture3D* texture); + static void FillHeader2D(IwiHeader& header, const Texture2D& texture); + static void FillHeaderCube(IwiHeader& header, const TextureCube& texture); + static void FillHeader3D(IwiHeader& header, const Texture3D& texture); public: IwiWriter(); @@ -25,6 +25,6 @@ namespace iwi6 bool SupportsImageFormat(const ImageFormat* imageFormat) override; std::string GetFileExtension() override; - void DumpImage(std::ostream& stream, Texture* texture) override; + void DumpImage(std::ostream& stream, const Texture* texture) override; }; } // namespace iwi6 diff --git a/src/ObjWriting/Image/IwiWriter8.cpp b/src/ObjImage/Image/IwiWriter8.cpp similarity index 65% rename from src/ObjWriting/Image/IwiWriter8.cpp rename to src/ObjImage/Image/IwiWriter8.cpp index 3806320e7..c062bd04e 100644 --- a/src/ObjWriting/Image/IwiWriter8.cpp +++ b/src/ObjImage/Image/IwiWriter8.cpp @@ -49,27 +49,27 @@ void IwiWriter::WriteVersion(std::ostream& stream) stream.write(reinterpret_cast(&version), sizeof(IwiVersion)); } -void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture) +void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = 1u; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = 1u; } -void IwiWriter::FillHeaderCube(IwiHeader* header, TextureCube* texture) +void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = 1u; - header->flags |= IMG_FLAG_MAPTYPE_CUBE; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = 1u; + header.flags |= IMG_FLAG_MAPTYPE_CUBE; } -void IwiWriter::FillHeader3D(IwiHeader* header, Texture3D* texture) +void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture) { - header->dimensions[0] = static_cast(texture->GetWidth()); - header->dimensions[1] = static_cast(texture->GetHeight()); - header->dimensions[2] = static_cast(texture->GetDepth()); - header->flags |= IMG_FLAG_MAPTYPE_3D; + header.dimensions[0] = static_cast(texture.GetWidth()); + header.dimensions[1] = static_cast(texture.GetHeight()); + header.dimensions[2] = static_cast(texture.GetDepth()); + header.flags |= IMG_FLAG_MAPTYPE_3D; } bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat) @@ -82,7 +82,7 @@ std::string IwiWriter::GetFileExtension() return ".iwi"; } -void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) +void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture) { assert(texture != nullptr); @@ -108,17 +108,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) header.fileSizeForPicmip[currentMipLevel] = currentFileSize; } - if (auto* texture2D = dynamic_cast(texture)) + if (const auto* texture2D = dynamic_cast(texture)) { - FillHeader2D(&header, texture2D); + FillHeader2D(header, *texture2D); } - else if (auto* textureCube = dynamic_cast(texture)) + else if (const auto* textureCube = dynamic_cast(texture)) { - FillHeaderCube(&header, textureCube); + FillHeaderCube(header, *textureCube); } - else if (auto* texture3D = dynamic_cast(texture)) + else if (const auto* texture3D = dynamic_cast(texture)) { - FillHeader3D(&header, texture3D); + FillHeader3D(header, *texture3D); } else { @@ -131,6 +131,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) { const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); - stream.write(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); + stream.write(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); } } diff --git a/src/ObjWriting/Image/IwiWriter8.h b/src/ObjImage/Image/IwiWriter8.h similarity index 69% rename from src/ObjWriting/Image/IwiWriter8.h rename to src/ObjImage/Image/IwiWriter8.h index 830a77bb6..018926701 100644 --- a/src/ObjWriting/Image/IwiWriter8.h +++ b/src/ObjImage/Image/IwiWriter8.h @@ -10,9 +10,9 @@ namespace iwi8 static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); static void WriteVersion(std::ostream& stream); - static void FillHeader2D(IwiHeader* header, Texture2D* texture); - static void FillHeaderCube(IwiHeader* header, TextureCube* texture); - static void FillHeader3D(IwiHeader* header, Texture3D* texture); + static void FillHeader2D(IwiHeader& header, const Texture2D& texture); + static void FillHeaderCube(IwiHeader& header, const TextureCube& texture); + static void FillHeader3D(IwiHeader& header, const Texture3D& texture); public: IwiWriter(); @@ -25,6 +25,6 @@ namespace iwi8 bool SupportsImageFormat(const ImageFormat* imageFormat) override; std::string GetFileExtension() override; - void DumpImage(std::ostream& stream, Texture* texture) override; + void DumpImage(std::ostream& stream, const Texture* texture) override; }; } // namespace iwi8 diff --git a/src/Common/Image/Texture.cpp b/src/ObjImage/Image/Texture.cpp similarity index 78% rename from src/Common/Image/Texture.cpp rename to src/ObjImage/Image/Texture.cpp index 393942947..c9e763729 100644 --- a/src/Common/Image/Texture.cpp +++ b/src/ObjImage/Image/Texture.cpp @@ -77,6 +77,11 @@ 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 =================== // ============================================== @@ -183,6 +188,31 @@ uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face) 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 ================== // ============================================== @@ -251,6 +281,32 @@ uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face) 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 =================== // ============================================== @@ -360,3 +416,28 @@ uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face) 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]; +} diff --git a/src/ObjImage/Image/Texture.h b/src/ObjImage/Image/Texture.h new file mode 100644 index 000000000..6f5185510 --- /dev/null +++ b/src/ObjImage/Image/Texture.h @@ -0,0 +1,132 @@ +#pragma once +#include "ImageFormat.h" + +#include + +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; + + Texture(const ImageFormat* format, bool mipMaps); + Texture(Texture&& other) noexcept; + + Texture& operator=(Texture&& other) noexcept; + +public: + Texture(const Texture& other) = delete; + virtual ~Texture(); + + Texture& operator=(const Texture& other) = delete; + + [[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; + + 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]] bool HasMipMaps() const; + [[nodiscard]] virtual int GetMipMapCount() const = 0; +}; + +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; + + Texture2D& operator=(const Texture2D& other) = delete; + Texture2D& operator=(Texture2D&& other) noexcept; + + [[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]] 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; +}; + +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; + + TextureCube& operator=(const TextureCube& other) = delete; + TextureCube& operator=(TextureCube&& other) noexcept; + + [[nodiscard]] TextureType GetTextureType() 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; +}; + +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; + + Texture3D& operator=(const Texture3D& other) = delete; + Texture3D& operator=(Texture3D&& other) noexcept; + + [[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]] 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; +}; diff --git a/src/Common/Image/TextureConverter.cpp b/src/ObjImage/Image/TextureConverter.cpp similarity index 92% rename from src/Common/Image/TextureConverter.cpp rename to src/ObjImage/Image/TextureConverter.cpp index a2ab8545a..109aaf735 100644 --- a/src/Common/Image/TextureConverter.cpp +++ b/src/ObjImage/Image/TextureConverter.cpp @@ -104,7 +104,7 @@ void TextureConverter::SetPixelFunctions(const unsigned inBitCount, const unsign } } -TextureConverter::TextureConverter(Texture* inputTexture, const ImageFormat* targetFormat) +TextureConverter::TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat) : m_input_texture(inputTexture), m_output_texture(nullptr), m_input_format(inputTexture->GetFormat()), @@ -117,15 +117,17 @@ void TextureConverter::CreateOutputTexture() switch (m_input_texture->GetTextureType()) { case TextureType::T_2D: - m_output_texture = new Texture2D(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps()); + 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 = new TextureCube(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps()); + 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 = new Texture3D( + 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: @@ -202,7 +204,7 @@ void TextureConverter::ConvertUnsignedToUnsigned() } } -Texture* TextureConverter::Convert() +std::unique_ptr TextureConverter::Convert() { CreateOutputTexture(); @@ -216,5 +218,5 @@ Texture* TextureConverter::Convert() assert(false); } - return m_output_texture; + return std::move(m_output_texture); } diff --git a/src/Common/Image/TextureConverter.h b/src/ObjImage/Image/TextureConverter.h similarity index 71% rename from src/Common/Image/TextureConverter.h rename to src/ObjImage/Image/TextureConverter.h index f499549f6..30bc382d9 100644 --- a/src/Common/Image/TextureConverter.h +++ b/src/ObjImage/Image/TextureConverter.h @@ -3,17 +3,16 @@ #include "Texture.h" #include +#include class TextureConverter { - Texture* m_input_texture; - Texture* m_output_texture; - const ImageFormat* m_input_format; - const ImageFormat* m_output_format; +public: + TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat); - std::function m_read_pixel_func; - std::function m_write_pixel_func; + std::unique_ptr Convert(); +private: static constexpr uint64_t Mask1(unsigned length); void SetPixelFunctions(unsigned inBitCount, unsigned outBitCount); @@ -22,8 +21,11 @@ class TextureConverter void ReorderUnsignedToUnsigned() const; void ConvertUnsignedToUnsigned(); -public: - TextureConverter(Texture* inputTexture, const ImageFormat* targetFormat); + std::function m_read_pixel_func; + std::function m_write_pixel_func; - Texture* Convert(); + const Texture* m_input_texture; + std::unique_ptr m_output_texture; + const ImageFormat* m_input_format; + const ImageFormat* m_output_format; }; diff --git a/src/ObjLoading.lua b/src/ObjLoading.lua index 45f110c2c..712ad146d 100644 --- a/src/ObjLoading.lua +++ b/src/ObjLoading.lua @@ -3,6 +3,7 @@ ObjLoading = {} function ObjLoading:include(includes) if includes:handle(self:name()) then ObjCommon:include(includes) + ObjImage:include(includes) ZoneCommon:include(includes) includedirs { path.join(ProjectFolder(), "ObjLoading") @@ -14,6 +15,7 @@ function ObjLoading:link(links) links:add(self:name()) links:linkto(Utils) links:linkto(ObjCommon) + links:linkto(ObjImage) links:linkto(ZoneCommon) links:linkto(minilzo) links:linkto(minizip) diff --git a/src/ObjLoading/AssetLoading/AssetLoadingContext.cpp b/src/ObjLoading/AssetLoading/AssetLoadingContext.cpp index 76a0f72e3..26480fd9c 100644 --- a/src/ObjLoading/AssetLoading/AssetLoadingContext.cpp +++ b/src/ObjLoading/AssetLoading/AssetLoadingContext.cpp @@ -1,6 +1,6 @@ #include "AssetLoadingContext.h" -AssetLoadingContext::AssetLoadingContext(Zone* zone, ISearchPath* rawSearchPath, std::vector gdtFiles) +AssetLoadingContext::AssetLoadingContext(Zone& zone, ISearchPath& rawSearchPath, std::vector gdtFiles) : m_zone(zone), m_raw_search_path(rawSearchPath), m_gdt_files(std::move(gdtFiles)) @@ -10,7 +10,7 @@ AssetLoadingContext::AssetLoadingContext(Zone* zone, ISearchPath* rawSearchPath, void AssetLoadingContext::BuildGdtEntryCache() { - for (auto* gdt : m_gdt_files) + for (const auto* gdt : m_gdt_files) { for (const auto& entry : gdt->m_entries) { diff --git a/src/ObjLoading/AssetLoading/AssetLoadingContext.h b/src/ObjLoading/AssetLoading/AssetLoadingContext.h index b1744bb16..18a425969 100644 --- a/src/ObjLoading/AssetLoading/AssetLoadingContext.h +++ b/src/ObjLoading/AssetLoading/AssetLoadingContext.h @@ -12,18 +12,8 @@ class AssetLoadingContext final : public IGdtQueryable { - std::unordered_map> m_entries_by_gdf_and_by_name; - std::unordered_map> m_zone_asset_loader_states; - - void BuildGdtEntryCache(); - public: - Zone* const m_zone; - ISearchPath* const m_raw_search_path; - const std::vector m_gdt_files; - std::unordered_map m_ignored_asset_map; - - AssetLoadingContext(Zone* zone, ISearchPath* rawSearchPath, std::vector gdtFiles); + AssetLoadingContext(Zone& zone, ISearchPath& rawSearchPath, std::vector gdtFiles); GdtEntry* GetGdtEntryByGdfAndName(const std::string& gdfName, const std::string& entryName) override; template T* GetZoneAssetLoaderState() @@ -36,9 +26,21 @@ class AssetLoadingContext final : public IGdtQueryable return dynamic_cast(foundEntry->second.get()); auto newState = std::make_unique(); - newState->SetZone(m_zone); + newState->SetZone(&m_zone); auto* newStatePtr = newState.get(); m_zone_asset_loader_states.emplace(std::make_pair>(typeid(T), std::move(newState))); return newStatePtr; } + +private: + void BuildGdtEntryCache(); + +public: + Zone& m_zone; + ISearchPath& m_raw_search_path; + const std::vector m_gdt_files; + std::unordered_map m_ignored_asset_map; + + std::unordered_map> m_entries_by_gdf_and_by_name; + std::unordered_map> m_zone_asset_loader_states; }; diff --git a/src/ObjLoading/AssetLoading/AssetLoadingManager.cpp b/src/ObjLoading/AssetLoading/AssetLoadingManager.cpp index 4788d2416..c7a97a3d6 100644 --- a/src/ObjLoading/AssetLoading/AssetLoadingManager.cpp +++ b/src/ObjLoading/AssetLoading/AssetLoadingManager.cpp @@ -6,7 +6,8 @@ #include #include -AssetLoadingManager::AssetLoadingManager(const std::map>& assetLoadersByType, AssetLoadingContext& context) +AssetLoadingManager::AssetLoadingManager(const std::unordered_map>& assetLoadersByType, + AssetLoadingContext& context) : m_asset_loaders_by_type(assetLoadersByType), m_context(context), m_last_dependency_loaded(nullptr) @@ -28,26 +29,26 @@ XAssetInfoGeneric* AssetLoadingManager::AddAssetInternal(std::unique_ptrm_type; const auto* pAssetName = xAssetInfo->m_name.c_str(); - m_last_dependency_loaded = m_context.m_zone->m_pools->AddAsset(std::move(xAssetInfo)); + m_last_dependency_loaded = m_context.m_zone.m_pools->AddAsset(std::move(xAssetInfo)); if (m_last_dependency_loaded == nullptr) - std::cerr << "Failed to add asset of type \"" << m_context.m_zone->m_pools->GetAssetTypeName(assetType) << "\" to pool: \"" << pAssetName << "\"\n"; + std::cerr << std::format("Failed to add asset of type \"{}\" to pool: \"{}\"\n", m_context.m_zone.m_pools->GetAssetTypeName(assetType), pAssetName); return m_last_dependency_loaded; } XAssetInfoGeneric* AssetLoadingManager::AddAsset(std::unique_ptr xAssetInfo) { - xAssetInfo->m_zone = m_context.m_zone; + xAssetInfo->m_zone = &m_context.m_zone; return AddAssetInternal(std::move(xAssetInfo)); } XAssetInfoGeneric* AssetLoadingManager::LoadIgnoredDependency(const asset_type_t assetType, const std::string& assetName, IAssetLoader* loader) { - auto* alreadyLoadedAsset = m_context.m_zone->m_pools->GetAssetOrAssetReference(assetType, assetName); + auto* alreadyLoadedAsset = m_context.m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName); if (alreadyLoadedAsset) return alreadyLoadedAsset; - auto* linkAsset = loader->CreateEmptyAsset(assetName, m_context.m_zone->GetMemory()); + auto* linkAsset = loader->CreateEmptyAsset(assetName, m_context.m_zone.GetMemory()); if (linkAsset) { AddAsset(std::make_unique(assetType, assetName, linkAsset)); @@ -65,21 +66,21 @@ XAssetInfoGeneric* AssetLoadingManager::LoadIgnoredDependency(const asset_type_t return lastDependency; } - std::cerr << "Failed to create empty asset \"" << assetName << "\" for type \"" << m_context.m_zone->m_pools->GetAssetTypeName(assetType) << "\"\n"; + std::cerr << std::format("Failed to create empty asset \"{}\" for type \"{}\"\n", assetName, m_context.m_zone.m_pools->GetAssetTypeName(assetType)); return nullptr; } XAssetInfoGeneric* AssetLoadingManager::LoadAssetDependency(const asset_type_t assetType, const std::string& assetName, const IAssetLoader* loader) { if (loader->CanLoadFromGdt() && !m_context.m_gdt_files.empty() - && loader->LoadFromGdt(assetName, &m_context, m_context.m_zone->GetMemory(), this, m_context.m_zone)) + && loader->LoadFromGdt(assetName, &m_context, m_context.m_zone.GetMemory(), this, &m_context.m_zone)) { auto* lastDependency = m_last_dependency_loaded; m_last_dependency_loaded = nullptr; return lastDependency; } - if (loader->CanLoadFromRaw() && loader->LoadFromRaw(assetName, m_context.m_raw_search_path, m_context.m_zone->GetMemory(), this, m_context.m_zone)) + if (loader->CanLoadFromRaw() && loader->LoadFromRaw(assetName, &m_context.m_raw_search_path, m_context.m_zone.GetMemory(), this, &m_context.m_zone)) { auto* lastDependency = m_last_dependency_loaded; m_last_dependency_loaded = nullptr; @@ -110,7 +111,7 @@ XAssetInfoGeneric* AssetLoadingManager::LoadAssetDependency(const asset_type_t a // Make sure any used script string is available in the created zone // The replacement of the scr_string_t values will be done upon writing for (const auto scrString : existingAsset->m_used_script_strings) - m_context.m_zone->m_script_strings.AddOrGetScriptString(existingAsset->m_zone->m_script_strings.CValue(scrString)); + m_context.m_zone.m_script_strings.AddOrGetScriptString(existingAsset->m_zone->m_script_strings.CValue(scrString)); AddAssetInternal(std::make_unique(existingAsset->m_type, existingAsset->m_name, @@ -125,13 +126,13 @@ XAssetInfoGeneric* AssetLoadingManager::LoadAssetDependency(const asset_type_t a return lastDependency; } - std::cerr << "Failed to load asset of type \"" << m_context.m_zone->m_pools->GetAssetTypeName(assetType) << "\": \"" << assetName << "\"\n"; + std::cerr << std::format("Failed to load asset of type \"{}\": \"{}\"\n", m_context.m_zone.m_pools->GetAssetTypeName(assetType), assetName); return nullptr; } XAssetInfoGeneric* AssetLoadingManager::LoadDependency(const asset_type_t assetType, const std::string& assetName) { - auto* alreadyLoadedAsset = m_context.m_zone->m_pools->GetAssetOrAssetReference(assetType, assetName); + auto* alreadyLoadedAsset = m_context.m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName); if (alreadyLoadedAsset) return alreadyLoadedAsset; @@ -149,13 +150,13 @@ XAssetInfoGeneric* AssetLoadingManager::LoadDependency(const asset_type_t assetT return LoadAssetDependency(assetType, assetName, loader->second.get()); } - std::cerr << "Failed to find loader for asset type \"" << m_context.m_zone->m_pools->GetAssetTypeName(assetType) << "\"\n"; + std::cerr << std::format("Failed to find loader for asset type \"{}\"\n", m_context.m_zone.m_pools->GetAssetTypeName(assetType)); return nullptr; } IndirectAssetReference AssetLoadingManager::LoadIndirectAssetReference(const asset_type_t assetType, const std::string& assetName) { - const auto* alreadyLoadedAsset = m_context.m_zone->m_pools->GetAssetOrAssetReference(assetType, assetName); + const auto* alreadyLoadedAsset = m_context.m_zone.m_pools->GetAssetOrAssetReference(assetType, assetName); if (alreadyLoadedAsset) return IndirectAssetReference(assetType, assetName); @@ -170,6 +171,6 @@ IndirectAssetReference AssetLoadingManager::LoadIndirectAssetReference(const ass return IndirectAssetReference(assetType, assetName); } - std::cerr << "Failed to find loader for asset type \"" << m_context.m_zone->m_pools->GetAssetTypeName(assetType) << "\"\n"; + std::cerr << std::format("Failed to find loader for asset type \"{}\"\n", m_context.m_zone.m_pools->GetAssetTypeName(assetType)); return IndirectAssetReference(assetType, assetName); } diff --git a/src/ObjLoading/AssetLoading/AssetLoadingManager.h b/src/ObjLoading/AssetLoading/AssetLoadingManager.h index 3a5e4808a..47e1dcecb 100644 --- a/src/ObjLoading/AssetLoading/AssetLoadingManager.h +++ b/src/ObjLoading/AssetLoading/AssetLoadingManager.h @@ -4,12 +4,12 @@ #include "IAssetLoader.h" #include "IAssetLoadingManager.h" -#include +#include class AssetLoadingManager final : public IAssetLoadingManager { public: - AssetLoadingManager(const std::map>& assetLoadersByType, AssetLoadingContext& context); + AssetLoadingManager(const std::unordered_map>& assetLoadersByType, AssetLoadingContext& context); bool LoadAssetFromLoader(asset_type_t assetType, const std::string& assetName); @@ -25,7 +25,7 @@ class AssetLoadingManager final : public IAssetLoadingManager XAssetInfoGeneric* AddAssetInternal(std::unique_ptr xAssetInfo); - const std::map>& m_asset_loaders_by_type; + const std::unordered_map>& m_asset_loaders_by_type; AssetLoadingContext& m_context; XAssetInfoGeneric* m_last_dependency_loaded; }; diff --git a/src/ObjLoading/AssetLoading/IAssetLoader.h b/src/ObjLoading/AssetLoading/IAssetLoader.h index 060ec4260..625c72b53 100644 --- a/src/ObjLoading/AssetLoading/IAssetLoader.h +++ b/src/ObjLoading/AssetLoading/IAssetLoader.h @@ -46,7 +46,7 @@ class IAssetLoader return false; } - virtual void FinalizeAssetsForZone(AssetLoadingContext* context) const + virtual void FinalizeAssetsForZone(AssetLoadingContext& context) const { // Do nothing by default } diff --git a/src/ObjLoading/Game/IW3/AssetLoaders/AssetLoaderGfxImage.cpp b/src/ObjLoading/Game/IW3/AssetLoaders/AssetLoaderGfxImage.cpp index 0351f7882..7daaf7200 100644 --- a/src/ObjLoading/Game/IW3/AssetLoaders/AssetLoaderGfxImage.cpp +++ b/src/ObjLoading/Game/IW3/AssetLoaders/AssetLoaderGfxImage.cpp @@ -5,7 +5,9 @@ #include "Image/IwiTypes.h" #include "Pool/GlobalAssetPool.h" +#include #include +#include #include using namespace IW3; @@ -32,29 +34,16 @@ bool AssetLoaderGfxImage::LoadFromRaw( return false; std::string safeAssetName = assetName; - for (auto& c : safeAssetName) - { - switch (c) - { - case '*': - c = '_'; - break; - - default: - break; - } - } + std::ranges::replace(safeAssetName, '*', '_'); - const auto file = searchPath->Open("images/" + safeAssetName + ".dds"); + const auto file = searchPath->Open(std::format("images/{}.dds", safeAssetName)); if (!file.IsOpen()) return false; - const DdsLoader ddsLoader(zone->GetMemory()); - auto* texture = ddsLoader.LoadDds(*file.m_stream); - - if (texture == nullptr) + const auto texture = dds::LoadDds(*file.m_stream); + if (!texture) { - std::cout << "Failed to load dds file for image asset \"" << assetName << "\"\n"; + std::cerr << std::format("Failed to load dds file for image asset \"{}\"\n", assetName); return false; } diff --git a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp index a67a013be..9faea56b3 100644 --- a/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp +++ b/src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp @@ -4,13 +4,7 @@ #include "AssetLoaders/AssetLoaderLocalizeEntry.h" #include "AssetLoaders/AssetLoaderRawFile.h" #include "AssetLoading/AssetLoadingManager.h" -#include "Game/IW3/GameAssetPoolIW3.h" #include "Game/IW3/GameIW3.h" -#include "Image/Dx9TextureLoader.h" -#include "Image/IwiLoader.h" -#include "Image/IwiTypes.h" -#include "Image/Texture.h" -#include "ObjContainer/IPak/IPak.h" #include "ObjLoading.h" using namespace IW3; @@ -54,129 +48,32 @@ ObjLoader::ObjLoader() #undef REGISTER_ASSET_LOADER } -bool ObjLoader::SupportsZone(Zone* zone) const +bool ObjLoader::SupportsZone(const Zone& zone) const { - return zone->m_game == &g_GameIW3; + return zone.m_game == &g_GameIW3; } -bool ObjLoader::IsMpZone(Zone* zone) +bool ObjLoader::IsMpZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "mp_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_mp") == 0; + return zone.m_name.compare(0, 3, "mp_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_mp") == 0; } -bool ObjLoader::IsZmZone(Zone* zone) +bool ObjLoader::IsZmZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "zm_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_zm") == 0; + return zone.m_name.compare(0, 3, "zm_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_zm") == 0; } -void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const {} +void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const {} -void ObjLoader::UnloadContainersOfZone(Zone* zone) const {} +void ObjLoader::UnloadContainersOfZone(Zone& zone) const {} -void ObjLoader::LoadImageFromLoadDef(GfxImage* image, Zone* zone) +bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, const asset_type_t assetType, const std::string& assetName) const { - const auto* loadDef = image->texture.loadDef; - Dx9TextureLoader textureLoader(zone->GetMemory()); - - textureLoader.Width(loadDef->dimensions[0]).Height(loadDef->dimensions[1]).Depth(loadDef->dimensions[2]); - - if (loadDef->flags & iwi6::IMG_FLAG_VOLMAP) - textureLoader.Type(TextureType::T_3D); - else if (loadDef->flags & 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)); - Texture* loadedTexture = textureLoader.LoadTexture(image->texture.loadDef->data); - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->cardMemory.platform[0] = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->cardMemory.platform[0] += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } -} - -void ObjLoader::LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone) -{ - Texture* loadedTexture = nullptr; - IwiLoader loader(zone->GetMemory()); - - const auto imageFileName = "images/" + std::string(image->name) + ".iwi"; - - { - const auto filePathImage = searchPath->Open(imageFileName); - if (filePathImage.IsOpen()) - { - loadedTexture = loader.LoadIwi(*filePathImage.m_stream); - } - } - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->cardMemory.platform[0] = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->cardMemory.platform[0] += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } - else - { - printf("Could not find data for image \"%s\"\n", image->name); - } -} - -void ObjLoader::LoadImageData(ISearchPath* searchPath, Zone* zone) -{ - auto* assetPool = dynamic_cast(zone->m_pools.get()); - - if (assetPool && assetPool->m_image != nullptr) - { - for (auto* imageEntry : *assetPool->m_image) - { - auto* image = imageEntry->Asset(); - - if (image->cardMemory.platform[0] > 0) - { - continue; - } - - // Do not load linked assets - if (image->name && image->name[0] == ',') - { - continue; - } - - if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) - { - LoadImageFromLoadDef(image, zone); - } - else - { - LoadImageFromIwi(image, searchPath, zone); - } - } - } -} - -void ObjLoader::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const -{ - LoadImageData(searchPath, zone); -} - -bool ObjLoader::LoadAssetForZone(AssetLoadingContext* context, const asset_type_t assetType, const std::string& assetName) const -{ - AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, *context); + AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context); return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); } -void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext* context) const +void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext& context) const { for (const auto& [type, loader] : m_asset_loaders_by_type) loader->FinalizeAssetsForZone(context); diff --git a/src/ObjLoading/Game/IW3/ObjLoaderIW3.h b/src/ObjLoading/Game/IW3/ObjLoaderIW3.h index 3c44b98d4..ec733cbe9 100644 --- a/src/ObjLoading/Game/IW3/ObjLoaderIW3.h +++ b/src/ObjLoading/Game/IW3/ObjLoaderIW3.h @@ -1,37 +1,30 @@ #pragma once #include "AssetLoading/IAssetLoader.h" -#include "Game/IW3/IW3.h" #include "IObjLoader.h" #include "SearchPath/ISearchPath.h" -#include #include +#include namespace IW3 { class ObjLoader final : public IObjLoader { - std::map> m_asset_loaders_by_type; + std::unordered_map> m_asset_loaders_by_type; - static void LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone); - static void LoadImageFromLoadDef(GfxImage* image, Zone* zone); - static void LoadImageData(ISearchPath* searchPath, Zone* zone); - - static bool IsMpZone(Zone* zone); - static bool IsZmZone(Zone* zone); + static bool IsMpZone(const Zone& zone); + static bool IsZmZone(const Zone& zone); public: ObjLoader(); - bool SupportsZone(Zone* zone) const override; - - void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; - void UnloadContainersOfZone(Zone* zone) const override; + [[nodiscard]] bool SupportsZone(const Zone& zone) const override; - void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const override; + void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override; + void UnloadContainersOfZone(Zone& zone) const override; - bool LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const override; - void FinalizeAssetsForZone(AssetLoadingContext* context) const override; + bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override; + void FinalizeAssetsForZone(AssetLoadingContext& context) const override; }; } // namespace IW3 diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMaterial.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMaterial.cpp index d10a43b97..02c81a664 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMaterial.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMaterial.cpp @@ -820,10 +820,10 @@ namespace IW4 m_material->techniqueSet = techset->Asset(); auto* loadingContext = m_manager->GetAssetLoadingContext(); - auto* searchPath = loadingContext->m_raw_search_path; + auto& searchPath = loadingContext->m_raw_search_path; auto* definitionCache = loadingContext->GetZoneAssetLoaderState(); - const auto* techsetDefinition = AssetLoaderTechniqueSet::LoadTechsetDefinition(techsetName, searchPath, definitionCache); + const auto* techsetDefinition = AssetLoaderTechniqueSet::LoadTechsetDefinition(techsetName, &searchPath, definitionCache); if (techsetDefinition == nullptr) { std::ostringstream ss; @@ -1375,7 +1375,7 @@ bool AssetLoaderMaterial::LoadFromGdt( if (!entry) return false; - MaterialGdtLoader loader(*entry, memory, manager->GetAssetLoadingContext()->m_raw_search_path, manager); + MaterialGdtLoader loader(*entry, memory, &manager->GetAssetLoadingContext()->m_raw_search_path, manager); try { diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.cpp index 1907a41b1..276cefc3e 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.cpp @@ -227,7 +227,7 @@ bool AssetLoaderMenuList::LoadFromRaw( return true; } -void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext* context) const +void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext& context) const { - context->GetZoneAssetLoaderState()->FinalizeSupportingData(); + context.GetZoneAssetLoaderState()->FinalizeSupportingData(); } diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.h b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.h index 88835e509..61f45486d 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.h +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMenuList.h @@ -14,6 +14,6 @@ namespace IW4 _NODISCARD bool CanLoadFromRaw() const override; bool LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; - void FinalizeAssetsForZone(AssetLoadingContext* context) const override; + void FinalizeAssetsForZone(AssetLoadingContext& context) const override; }; } // namespace IW4 diff --git a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h index 046461041..22f85756b 100644 --- a/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h +++ b/src/ObjLoading/Game/IW4/Leaderboard/JsonLeaderboardDefLoader.h @@ -3,6 +3,8 @@ #include "Game/IW4/IW4.h" #include "Utils/MemoryManager.h" +#include + namespace IW4 { bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager* memory); diff --git a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp index f35df1311..c055156e7 100644 --- a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp +++ b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp @@ -37,14 +37,9 @@ #include "AssetLoaders/AssetLoaderXModel.h" #include "AssetLoaders/AssetLoaderXModelSurfs.h" #include "AssetLoading/AssetLoadingManager.h" -#include "Game/IW4/GameAssetPoolIW4.h" #include "Game/IW4/GameIW4.h" -#include "Image/Dx9TextureLoader.h" #include "Image/IwiLoader.h" -#include "Image/IwiTypes.h" -#include "Image/Texture.h" #include "ObjContainer/IPak/IPak.h" -#include "ObjLoading.h" using namespace IW4; @@ -97,129 +92,32 @@ ObjLoader::ObjLoader() #undef REGISTER_ASSET_LOADER } -bool ObjLoader::SupportsZone(Zone* zone) const +bool ObjLoader::SupportsZone(const Zone& zone) const { - return zone->m_game == &g_GameIW4; + return zone.m_game == &g_GameIW4; } -bool ObjLoader::IsMpZone(Zone* zone) +bool ObjLoader::IsMpZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "mp_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_mp") == 0; + return zone.m_name.compare(0, 3, "mp_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_mp") == 0; } -bool ObjLoader::IsZmZone(Zone* zone) +bool ObjLoader::IsZmZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "zm_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_zm") == 0; + return zone.m_name.compare(0, 3, "zm_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_zm") == 0; } -void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const {} +void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const {} -void ObjLoader::UnloadContainersOfZone(Zone* zone) const {} +void ObjLoader::UnloadContainersOfZone(Zone& zone) const {} -void ObjLoader::LoadImageFromLoadDef(GfxImage* image, Zone* zone) +bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const { - const auto* loadDef = image->texture.loadDef; - Dx9TextureLoader textureLoader(zone->GetMemory()); - - textureLoader.Width(image->width).Height(image->height).Depth(image->depth); - - if ((loadDef->flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_3D) - textureLoader.Type(TextureType::T_3D); - else if ((loadDef->flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == 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)); - Texture* loadedTexture = textureLoader.LoadTexture(image->texture.loadDef->data); - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->cardMemory.platform[0] = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->cardMemory.platform[0] += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } -} - -void ObjLoader::LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone) -{ - Texture* loadedTexture = nullptr; - IwiLoader loader(zone->GetMemory()); - - const auto imageFileName = "images/" + std::string(image->name) + ".iwi"; - - { - const auto filePathImage = searchPath->Open(imageFileName); - if (filePathImage.IsOpen()) - { - loadedTexture = loader.LoadIwi(*filePathImage.m_stream); - } - } - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->cardMemory.platform[0] = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->cardMemory.platform[0] += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } - else - { - printf("Could not find data for image \"%s\"\n", image->name); - } -} - -void ObjLoader::LoadImageData(ISearchPath* searchPath, Zone* zone) -{ - auto* assetPool = dynamic_cast(zone->m_pools.get()); - - if (assetPool && assetPool->m_image != nullptr) - { - for (auto* imageEntry : *assetPool->m_image) - { - auto* image = imageEntry->Asset(); - - if (image->cardMemory.platform[0] > 0) - { - continue; - } - - // Do not load linked assets - if (image->name && image->name[0] == ',') - { - continue; - } - - if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) - { - LoadImageFromLoadDef(image, zone); - } - else - { - LoadImageFromIwi(image, searchPath, zone); - } - } - } -} - -void ObjLoader::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const -{ - LoadImageData(searchPath, zone); -} - -bool ObjLoader::LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const -{ - AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, *context); + AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context); return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); } -void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext* context) const +void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext& context) const { for (const auto& [type, loader] : m_asset_loaders_by_type) loader->FinalizeAssetsForZone(context); diff --git a/src/ObjLoading/Game/IW4/ObjLoaderIW4.h b/src/ObjLoading/Game/IW4/ObjLoaderIW4.h index 1739fab4a..e19a58054 100644 --- a/src/ObjLoading/Game/IW4/ObjLoaderIW4.h +++ b/src/ObjLoading/Game/IW4/ObjLoaderIW4.h @@ -1,37 +1,31 @@ #pragma once #include "AssetLoading/IAssetLoader.h" -#include "Game/IW4/IW4.h" #include "IObjLoader.h" #include "SearchPath/ISearchPath.h" -#include #include +#include namespace IW4 { class ObjLoader final : public IObjLoader { - std::map> m_asset_loaders_by_type; - - static void LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone); - static void LoadImageFromLoadDef(GfxImage* image, Zone* zone); - static void LoadImageData(ISearchPath* searchPath, Zone* zone); - - static bool IsMpZone(Zone* zone); - static bool IsZmZone(Zone* zone); - public: ObjLoader(); - bool SupportsZone(Zone* zone) const override; + [[nodiscard]] bool SupportsZone(const Zone& zone) const override; + + void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override; + void UnloadContainersOfZone(Zone& zone) const override; - void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; - void UnloadContainersOfZone(Zone* zone) const override; + bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override; + void FinalizeAssetsForZone(AssetLoadingContext& context) const override; - void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const override; + private: + static bool IsMpZone(const Zone& zone); + static bool IsZmZone(const Zone& zone); - bool LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const override; - void FinalizeAssetsForZone(AssetLoadingContext* context) const override; + std::unordered_map> m_asset_loaders_by_type; }; } // namespace IW4 diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderGfxImage.cpp b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderGfxImage.cpp index 174b568c1..e6a1948e4 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderGfxImage.cpp +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderGfxImage.cpp @@ -35,10 +35,8 @@ bool AssetLoaderGfxImage::LoadFromRaw( const auto fileData = std::make_unique(fileSize); file.m_stream->read(fileData.get(), fileSize); - MemoryManager tempMemory; - IwiLoader iwiLoader(&tempMemory); std::istringstream ss(std::string(fileData.get(), fileSize)); - const auto texture = iwiLoader.LoadIwi(ss); + const auto texture = iwi::LoadIwi(ss); if (!texture) { std::cerr << std::format("Failed to load texture from: {}\n", fileName); diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.cpp b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.cpp index 8a0ba21e2..ce6988216 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.cpp +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.cpp @@ -227,7 +227,7 @@ bool AssetLoaderMenuList::LoadFromRaw( return true; } -void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext* context) const +void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext& context) const { - context->GetZoneAssetLoaderState()->FinalizeSupportingData(); + context.GetZoneAssetLoaderState()->FinalizeSupportingData(); } diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.h b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.h index 42d9a410b..00f42417c 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.h +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.h @@ -14,6 +14,6 @@ namespace IW5 _NODISCARD bool CanLoadFromRaw() const override; bool LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; - void FinalizeAssetsForZone(AssetLoadingContext* context) const override; + void FinalizeAssetsForZone(AssetLoadingContext& context) const override; }; } // namespace IW5 diff --git a/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.h b/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.h index 84186e24c..1dc020b67 100644 --- a/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.h +++ b/src/ObjLoading/Game/IW5/Leaderboard/JsonLeaderboardDefLoader.h @@ -3,6 +3,8 @@ #include "Game/IW5/IW5.h" #include "Utils/MemoryManager.h" +#include + namespace IW5 { bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager* memory); diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp index a05d69a11..6dbcec543 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -41,14 +41,9 @@ #include "AssetLoaders/AssetLoaderXModel.h" #include "AssetLoaders/AssetLoaderXModelSurfs.h" #include "AssetLoading/AssetLoadingManager.h" -#include "Game/IW5/GameAssetPoolIW5.h" #include "Game/IW5/GameIW5.h" -#include "Image/Dx9TextureLoader.h" #include "Image/IwiLoader.h" -#include "Image/IwiTypes.h" -#include "Image/Texture.h" #include "ObjContainer/IPak/IPak.h" -#include "ObjLoading.h" using namespace IW5; @@ -104,129 +99,32 @@ ObjLoader::ObjLoader() #undef REGISTER_ASSET_LOADER } -bool ObjLoader::SupportsZone(Zone* zone) const +bool ObjLoader::SupportsZone(const Zone& zone) const { - return zone->m_game == &g_GameIW5; + return zone.m_game == &g_GameIW5; } -bool ObjLoader::IsMpZone(Zone* zone) +bool ObjLoader::IsMpZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "mp_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_mp") == 0; + return zone.m_name.compare(0, 3, "mp_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_mp") == 0; } -bool ObjLoader::IsZmZone(Zone* zone) +bool ObjLoader::IsZmZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "zm_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_zm") == 0; + return zone.m_name.compare(0, 3, "zm_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_zm") == 0; } -void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const {} +void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const {} -void ObjLoader::UnloadContainersOfZone(Zone* zone) const {} +void ObjLoader::UnloadContainersOfZone(Zone& zone) const {} -void ObjLoader::LoadImageFromLoadDef(GfxImage* image, Zone* zone) +bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, const asset_type_t assetType, const std::string& assetName) const { - const auto* loadDef = image->texture.loadDef; - Dx9TextureLoader textureLoader(zone->GetMemory()); - - textureLoader.Width(image->width).Height(image->height).Depth(image->depth); - - if ((loadDef->flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_3D) - textureLoader.Type(TextureType::T_3D); - else if ((loadDef->flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == 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)); - Texture* loadedTexture = textureLoader.LoadTexture(image->texture.loadDef->data); - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->cardMemory.platform[0] = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->cardMemory.platform[0] += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } -} - -void ObjLoader::LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone) -{ - Texture* loadedTexture = nullptr; - IwiLoader loader(zone->GetMemory()); - - const auto imageFileName = "images/" + std::string(image->name) + ".iwi"; - - { - const auto filePathImage = searchPath->Open(imageFileName); - if (filePathImage.IsOpen()) - { - loadedTexture = loader.LoadIwi(*filePathImage.m_stream); - } - } - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->cardMemory.platform[0] = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->cardMemory.platform[0] += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } - else - { - printf("Could not find data for image \"%s\"\n", image->name); - } -} - -void ObjLoader::LoadImageData(ISearchPath* searchPath, Zone* zone) -{ - auto* assetPool = dynamic_cast(zone->m_pools.get()); - - if (assetPool && assetPool->m_image != nullptr) - { - for (auto* imageEntry : *assetPool->m_image) - { - auto* image = imageEntry->Asset(); - - if (image->cardMemory.platform[0] > 0) - { - continue; - } - - // Do not load linked assets - if (image->name && image->name[0] == ',') - { - continue; - } - - if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) - { - LoadImageFromLoadDef(image, zone); - } - else - { - LoadImageFromIwi(image, searchPath, zone); - } - } - } -} - -void ObjLoader::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const -{ - LoadImageData(searchPath, zone); -} - -bool ObjLoader::LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const -{ - AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, *context); + AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context); return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); } -void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext* context) const +void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext& context) const { for (const auto& [type, loader] : m_asset_loaders_by_type) loader->FinalizeAssetsForZone(context); diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.h b/src/ObjLoading/Game/IW5/ObjLoaderIW5.h index e843d1ae6..e60ee44d4 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.h +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.h @@ -1,37 +1,31 @@ #pragma once #include "AssetLoading/IAssetLoader.h" -#include "Game/IW5/IW5.h" #include "IObjLoader.h" #include "SearchPath/ISearchPath.h" -#include #include +#include namespace IW5 { class ObjLoader final : public IObjLoader { - std::map> m_asset_loaders_by_type; - - static void LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone); - static void LoadImageFromLoadDef(GfxImage* image, Zone* zone); - static void LoadImageData(ISearchPath* searchPath, Zone* zone); - - static bool IsMpZone(Zone* zone); - static bool IsZmZone(Zone* zone); - public: ObjLoader(); - bool SupportsZone(Zone* zone) const override; + [[nodiscard]] bool SupportsZone(const Zone& zone) const override; + + void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override; + void UnloadContainersOfZone(Zone& zone) const override; - void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; - void UnloadContainersOfZone(Zone* zone) const override; + bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override; + void FinalizeAssetsForZone(AssetLoadingContext& context) const override; - void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const override; + private: + static bool IsMpZone(const Zone& zone); + static bool IsZmZone(const Zone& zone); - bool LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const override; - void FinalizeAssetsForZone(AssetLoadingContext* context) const override; + std::unordered_map> m_asset_loaders_by_type; }; } // namespace IW5 diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp index 0b98c9593..dd8f8522d 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp @@ -5,14 +5,9 @@ #include "AssetLoaders/AssetLoaderStringTable.h" #include "AssetLoaders/AssetLoaderXModel.h" #include "AssetLoading/AssetLoadingManager.h" -#include "Game/T5/GameAssetPoolT5.h" #include "Game/T5/GameT5.h" -#include "Image/Dx9TextureLoader.h" #include "Image/IwiLoader.h" -#include "Image/IwiTypes.h" -#include "Image/Texture.h" #include "ObjContainer/IPak/IPak.h" -#include "ObjLoading.h" using namespace T5; @@ -61,129 +56,32 @@ ObjLoader::ObjLoader() #undef REGISTER_ASSET_LOADER } -bool ObjLoader::SupportsZone(Zone* zone) const +bool ObjLoader::SupportsZone(const Zone& zone) const { - return zone->m_game == &g_GameT5; + return zone.m_game == &g_GameT5; } -bool ObjLoader::IsMpZone(Zone* zone) +bool ObjLoader::IsMpZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "mp_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_mp") == 0; + return zone.m_name.compare(0, 3, "mp_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_mp") == 0; } -bool ObjLoader::IsZmZone(Zone* zone) +bool ObjLoader::IsZmZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "zm_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_zm") == 0; + return zone.m_name.compare(0, 3, "zm_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_zm") == 0; } -void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const {} +void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const {} -void ObjLoader::UnloadContainersOfZone(Zone* zone) const {} +void ObjLoader::UnloadContainersOfZone(Zone& zone) const {} -void ObjLoader::LoadImageFromLoadDef(GfxImage* image, Zone* zone) +bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const { - const auto* loadDef = image->texture.loadDef; - Dx9TextureLoader textureLoader(zone->GetMemory()); - - textureLoader.Width(image->width).Height(image->height).Depth(image->depth); - - if (loadDef->flags & iwi13::IMG_FLAG_VOLMAP) - textureLoader.Type(TextureType::T_3D); - else if (loadDef->flags & 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)); - Texture* loadedTexture = textureLoader.LoadTexture(image->texture.loadDef->data); - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->loadedSize = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->loadedSize += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } -} - -void ObjLoader::LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone) -{ - Texture* loadedTexture = nullptr; - IwiLoader loader(zone->GetMemory()); - - const auto imageFileName = "images/" + std::string(image->name) + ".iwi"; - - { - const auto filePathImage = searchPath->Open(imageFileName); - if (filePathImage.IsOpen()) - { - loadedTexture = loader.LoadIwi(*filePathImage.m_stream); - } - } - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->loadedSize = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->loadedSize += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } - else - { - printf("Could not find data for image \"%s\"\n", image->name); - } -} - -void ObjLoader::LoadImageData(ISearchPath* searchPath, Zone* zone) -{ - auto* assetPool = dynamic_cast(zone->m_pools.get()); - - if (assetPool && assetPool->m_image != nullptr) - { - for (auto* imageEntry : *assetPool->m_image) - { - auto* image = imageEntry->Asset(); - - if (image->loadedSize > 0) - { - continue; - } - - // Do not load linked assets - if (image->name && image->name[0] == ',') - { - continue; - } - - if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) - { - LoadImageFromLoadDef(image, zone); - } - else - { - LoadImageFromIwi(image, searchPath, zone); - } - } - } -} - -void ObjLoader::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const -{ - LoadImageData(searchPath, zone); -} - -bool ObjLoader::LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const -{ - AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, *context); + AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context); return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); } -void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext* context) const +void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext& context) const { for (const auto& [type, loader] : m_asset_loaders_by_type) loader->FinalizeAssetsForZone(context); diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.h b/src/ObjLoading/Game/T5/ObjLoaderT5.h index bb8d00359..f8fadd5f2 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.h +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.h @@ -1,37 +1,31 @@ #pragma once #include "AssetLoading/IAssetLoader.h" -#include "Game/T5/T5.h" #include "IObjLoader.h" #include "SearchPath/ISearchPath.h" -#include #include +#include namespace T5 { class ObjLoader final : public IObjLoader { - std::map> m_asset_loaders_by_type; - - static void LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone); - static void LoadImageFromLoadDef(GfxImage* image, Zone* zone); - static void LoadImageData(ISearchPath* searchPath, Zone* zone); - - static bool IsMpZone(Zone* zone); - static bool IsZmZone(Zone* zone); - public: ObjLoader(); - bool SupportsZone(Zone* zone) const override; + bool SupportsZone(const Zone& zone) const override; + + void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override; + void UnloadContainersOfZone(Zone& zone) const override; - void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; - void UnloadContainersOfZone(Zone* zone) const override; + bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override; + void FinalizeAssetsForZone(AssetLoadingContext& context) const override; - void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const override; + private: + static bool IsMpZone(const Zone& zone); + static bool IsZmZone(const Zone& zone); - bool LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const override; - void FinalizeAssetsForZone(AssetLoadingContext* context) const override; + std::unordered_map> m_asset_loaders_by_type; }; } // namespace T5 diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderGfxImage.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderGfxImage.cpp index dbd7e3ff9..5c47dceb3 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderGfxImage.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderGfxImage.cpp @@ -6,6 +6,7 @@ #include "Pool/GlobalAssetPool.h" #include +#include #include #include #include @@ -27,7 +28,7 @@ bool AssetLoaderGfxImage::CanLoadFromRaw() const bool AssetLoaderGfxImage::LoadFromRaw( const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const { - const auto fileName = "images/" + assetName + ".iwi"; + const auto fileName = std::format("images/{}.iwi", assetName); const auto file = searchPath->Open(fileName); if (!file.IsOpen()) return false; @@ -37,13 +38,11 @@ bool AssetLoaderGfxImage::LoadFromRaw( file.m_stream->read(fileData.get(), fileSize); const auto dataHash = static_cast(crc32(0u, reinterpret_cast(fileData.get()), fileSize)); - MemoryManager tempMemory; - IwiLoader iwiLoader(&tempMemory); std::istringstream ss(std::string(fileData.get(), fileSize)); - const auto texture = iwiLoader.LoadIwi(ss); + const auto texture = iwi::LoadIwi(ss); if (!texture) { - std::cerr << "Failed to load texture from: " << fileName << "\n"; + std::cerr << std::format("Failed to load texture from: {}\n", fileName); return false; } diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 67f48f206..846c34d8e 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -58,12 +58,12 @@ #include "ObjContainer/IPak/IPak.h" #include "ObjLoading.h" -#include +#include namespace T6 { - const int ObjLoader::IPAK_READ_HASH = Common::Com_HashKey("ipak_read", 64); - const int ObjLoader::GLOBAL_HASH = Common::Com_HashKey("GLOBAL", 64); + constexpr auto IPAK_READ_HASH = Common::Com_HashKey("ipak_read", 64); + constexpr auto GLOBAL_HASH = Common::Com_HashKey("GLOBAL", 64); ObjLoader::ObjLoader() { @@ -125,37 +125,37 @@ namespace T6 #undef REGISTER_ASSET_LOADER } - bool ObjLoader::SupportsZone(Zone* zone) const + bool ObjLoader::SupportsZone(const Zone& zone) const { - return zone->m_game == &g_GameT6; + return zone.m_game == &g_GameT6; } - bool ObjLoader::VerifySoundBankChecksum(const SoundBank* soundBank, const SndRuntimeAssetBank& sndRuntimeAssetBank) + bool ObjLoader::VerifySoundBankChecksum(const SoundBank& soundBank, const SndRuntimeAssetBank& sndRuntimeAssetBank) { SoundAssetBankChecksum checksum{}; static_assert(sizeof(SoundAssetBankChecksum::checksumBytes) == sizeof(SndRuntimeAssetBank::linkTimeChecksum)); for (auto i = 0u; i < sizeof(SoundAssetBankChecksum::checksumBytes); i++) checksum.checksumBytes[i] = sndRuntimeAssetBank.linkTimeChecksum[i]; - return soundBank->VerifyChecksum(checksum); + return soundBank.VerifyChecksum(checksum); } - SoundBank* ObjLoader::LoadSoundBankForZone(ISearchPath* searchPath, const std::string& soundBankFileName, Zone* zone) + SoundBank* ObjLoader::LoadSoundBankForZone(ISearchPath& searchPath, const std::string& soundBankFileName, Zone& zone) { if (ObjLoading::Configuration.Verbose) - std::cout << "Trying to load sound bank '" << soundBankFileName << "' for zone '" << zone->m_name << "'\n"; + std::cout << std::format("Trying to load sound bank '{}' for zone '{}'\n", soundBankFileName, zone.m_name); auto* existingSoundBank = SoundBank::Repository.GetContainerByName(soundBankFileName); if (existingSoundBank != nullptr) { if (ObjLoading::Configuration.Verbose) - std::cout << "Referencing loaded sound bank '" << soundBankFileName << "'.\n"; + std::cout << std::format("Referencing loaded sound bank '{}'.\n", soundBankFileName); - SoundBank::Repository.AddContainerReference(existingSoundBank, zone); + SoundBank::Repository.AddContainerReference(existingSoundBank, &zone); return existingSoundBank; } - auto file = searchPath->Open(soundBankFileName); + auto file = searchPath.Open(soundBankFileName); if (file.IsOpen()) { auto sndBank = std::make_unique(soundBankFileName, std::move(file.m_stream), file.m_length); @@ -163,26 +163,26 @@ namespace T6 if (!sndBank->Initialize()) { - std::cout << "Failed to load sound bank '" << soundBankFileName << "'\n"; + std::cerr << std::format("Failed to load sound bank '{}'\n", soundBankFileName); return nullptr; } - SoundBank::Repository.AddContainer(std::move(sndBank), zone); + SoundBank::Repository.AddContainer(std::move(sndBank), &zone); if (ObjLoading::Configuration.Verbose) - std::cout << "Found and loaded sound bank '" << soundBankFileName << "'\n"; + std::cout << std::format("Found and loaded sound bank '{}'\n", soundBankFileName); return sndBankPtr; } - std::cout << "Failed to load sound bank '" << soundBankFileName << "'\n"; + std::cerr << std::format("Failed to load sound bank '{}'\n", soundBankFileName); return nullptr; } - void ObjLoader::LoadSoundBankFromLinkedInfo(ISearchPath* searchPath, + void ObjLoader::LoadSoundBankFromLinkedInfo(ISearchPath& searchPath, const std::string& soundBankFileName, - const SndRuntimeAssetBank* sndBankLinkedInfo, - Zone* zone, + const SndRuntimeAssetBank& sndBankLinkedInfo, + Zone& zone, std::set& loadedBanksForZone, std::stack& dependenciesToLoad) { @@ -192,10 +192,9 @@ namespace T6 if (soundBank) { - if (!VerifySoundBankChecksum(soundBank, *sndBankLinkedInfo)) - { - std::cout << "Checksum of sound bank does not match link time checksum for '" << soundBankFileName << "'\n"; - } + if (!VerifySoundBankChecksum(*soundBank, sndBankLinkedInfo)) + std::cout << std::format("Checksum of sound bank does not match link time checksum for '{}'\n", soundBankFileName); + loadedBanksForZone.emplace(soundBankFileName); for (const auto& dependency : soundBank->GetDependencies()) @@ -206,20 +205,20 @@ namespace T6 } } - void ObjLoader::LoadSoundBanksFromAsset(ISearchPath* searchPath, const SndBank* sndBank, Zone* zone, std::set& loadedBanksForZone) + void ObjLoader::LoadSoundBanksFromAsset(ISearchPath& searchPath, const SndBank& sndBank, Zone& zone, std::set& loadedBanksForZone) { std::stack dependenciesToLoad; - if (sndBank->streamAssetBank.zone) + if (sndBank.streamAssetBank.zone) { - const auto soundBankFileName = SoundBank::GetFileNameForDefinition(true, sndBank->streamAssetBank.zone, sndBank->streamAssetBank.language); - LoadSoundBankFromLinkedInfo(searchPath, soundBankFileName, &sndBank->streamAssetBank, zone, loadedBanksForZone, dependenciesToLoad); + const auto soundBankFileName = SoundBank::GetFileNameForDefinition(true, sndBank.streamAssetBank.zone, sndBank.streamAssetBank.language); + LoadSoundBankFromLinkedInfo(searchPath, soundBankFileName, sndBank.streamAssetBank, zone, loadedBanksForZone, dependenciesToLoad); } - if (sndBank->runtimeAssetLoad && sndBank->loadAssetBank.zone) + if (sndBank.runtimeAssetLoad && sndBank.loadAssetBank.zone) { - const auto soundBankFileName = SoundBank::GetFileNameForDefinition(false, sndBank->loadAssetBank.zone, sndBank->loadAssetBank.language); - LoadSoundBankFromLinkedInfo(searchPath, soundBankFileName, &sndBank->loadAssetBank, zone, loadedBanksForZone, dependenciesToLoad); + const auto soundBankFileName = SoundBank::GetFileNameForDefinition(false, sndBank.loadAssetBank.zone, sndBank.loadAssetBank.language); + LoadSoundBankFromLinkedInfo(searchPath, soundBankFileName, sndBank.loadAssetBank, zone, loadedBanksForZone, dependenciesToLoad); } while (!dependenciesToLoad.empty()) @@ -236,76 +235,72 @@ namespace T6 loadedBanksForZone.emplace(dependencyFileName); for (const auto& dependency : soundBank->GetDependencies()) - { dependenciesToLoad.emplace(dependency); - } } } } } - void ObjLoader::LoadIPakForZone(ISearchPath* searchPath, const std::string& ipakName, Zone* zone) + void ObjLoader::LoadIPakForZone(ISearchPath& searchPath, const std::string& ipakName, Zone& zone) { if (ObjLoading::Configuration.Verbose) - printf("Trying to load ipak '%s' for zone '%s'\n", ipakName.c_str(), zone->m_name.c_str()); + std::cout << std::format("Trying to load ipak '{}' for zone '{}'\n", ipakName, zone.m_name); auto* existingIPak = IPak::Repository.GetContainerByName(ipakName); if (existingIPak != nullptr) { if (ObjLoading::Configuration.Verbose) - printf("Referencing loaded ipak '%s'.\n", ipakName.c_str()); + std::cout << std::format("Referencing loaded ipak '{}'.\n", ipakName); - IPak::Repository.AddContainerReference(existingIPak, zone); + IPak::Repository.AddContainerReference(existingIPak, &zone); return; } - const auto ipakFilename = ipakName + ".ipak"; + const auto ipakFilename = std::format("{}.ipak", ipakName); - auto file = searchPath->Open(ipakFilename); + auto file = searchPath.Open(ipakFilename); if (file.IsOpen()) { auto ipak = std::make_unique(ipakFilename, std::move(file.m_stream)); if (ipak->Initialize()) { - IPak::Repository.AddContainer(std::move(ipak), zone); + IPak::Repository.AddContainer(std::move(ipak), &zone); if (ObjLoading::Configuration.Verbose) - printf("Found and loaded ipak '%s'.\n", ipakFilename.c_str()); + std::cout << std::format("Found and loaded ipak '{}'.\n", ipakFilename); } else { - printf("Failed to load ipak '%s'!\n", ipakFilename.c_str()); + std::cerr << std::format("Failed to load ipak '{}'!\n", ipakFilename); } } } - bool ObjLoader::IsMpZone(Zone* zone) + bool ObjLoader::IsMpZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "mp_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_mp") == 0; + return zone.m_name.compare(0, 3, "mp_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_mp") == 0; } - bool ObjLoader::IsZmZone(Zone* zone) + bool ObjLoader::IsZmZone(const Zone& zone) { - return zone->m_name.compare(0, 3, "zm_") == 0 || zone->m_name.compare(zone->m_name.length() - 3, 3, "_zm") == 0; + return zone.m_name.compare(0, 3, "zm_") == 0 || zone.m_name.compare(zone.m_name.length() - 3, 3, "_zm") == 0; } - void ObjLoader::LoadCommonIPaks(ISearchPath* searchPath, Zone* zone) + void ObjLoader::LoadCommonIPaks(ISearchPath& searchPath, Zone& zone) { if (ObjLoading::Configuration.Verbose) - printf("Loading common ipaks for zone \"%s\"\n", zone->m_name.c_str()); + std::cout << std::format("Loading common ipaks for zone \"{}\"\n", zone.m_name); LoadIPakForZone(searchPath, "base", zone); - auto languagePrefixes = g_GameT6.GetLanguagePrefixes(); + const auto languagePrefixes = g_GameT6.GetLanguagePrefixes(); for (const auto& languagePrefix : languagePrefixes) - { - LoadIPakForZone(searchPath, languagePrefix.m_prefix + "base", zone); - } + LoadIPakForZone(searchPath, std::format("{}base", languagePrefix.m_prefix), zone); if (IsMpZone(zone)) { if (ObjLoading::Configuration.Verbose) - printf("Loading multiplayer ipaks for zone \"%s\"\n", zone->m_name.c_str()); + std::cout << std::format("Loading multiplayer ipaks for zone \"{}\"\n", zone.m_name); LoadIPakForZone(searchPath, "mp", zone); LoadIPakForZone(searchPath, "so", zone); @@ -313,23 +308,23 @@ namespace T6 else if (IsZmZone(zone)) { if (ObjLoading::Configuration.Verbose) - printf("Loading zombie ipak for zone \"%s\"\n", zone->m_name.c_str()); + std::cout << std::format("Loading zombie ipak for zone \"{}\"\n", zone.m_name); LoadIPakForZone(searchPath, "zm", zone); } else { if (ObjLoading::Configuration.Verbose) - printf("Loading singleplayer ipak for zone \"%s\"\n", zone->m_name.c_str()); + std::cout << std::format("Loading singleplayer ipak for zone \"{}\"\n", zone.m_name); LoadIPakForZone(searchPath, "sp", zone); } } - void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const + void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const { - auto* assetPoolT6 = dynamic_cast(zone->m_pools.get()); - const auto zoneNameHash = Common::Com_HashKey(zone->m_name.c_str(), 64); + const auto* assetPoolT6 = dynamic_cast(zone.m_pools.get()); + const auto zoneNameHash = Common::Com_HashKey(zone.m_name.c_str(), 64); LoadCommonIPaks(searchPath, zone); @@ -337,7 +332,7 @@ namespace T6 { for (auto* keyValuePairsEntry : *assetPoolT6->m_key_value_pairs) { - auto* keyValuePairs = keyValuePairsEntry->Asset(); + const auto* keyValuePairs = keyValuePairsEntry->Asset(); for (auto variableIndex = 0; variableIndex < keyValuePairs->numVariables; variableIndex++) { auto* variable = &keyValuePairs->keyValuePairs[variableIndex]; @@ -356,143 +351,23 @@ namespace T6 for (auto* sndBankAssetInfo : *assetPoolT6->m_sound_bank) { - LoadSoundBanksFromAsset(searchPath, sndBankAssetInfo->Asset(), zone, loadedSoundBanksForZone); - } - } - } - - void ObjLoader::UnloadContainersOfZone(Zone* zone) const - { - IPak::Repository.RemoveContainerReferences(zone); - } - - void ObjLoader::LoadImageFromLoadDef(GfxImage* image, Zone* zone) - { - const auto* loadDef = image->texture.loadDef; - Dx12TextureLoader textureLoader(zone->GetMemory()); - - textureLoader.Width(image->width).Height(image->height).Depth(image->depth); - - if (loadDef->flags & iwi27::IMG_FLAG_VOLMAP) - textureLoader.Type(TextureType::T_3D); - else if (loadDef->flags & 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)); - Texture* loadedTexture = textureLoader.LoadTexture(image->texture.loadDef->data); - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->loadedSize = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->loadedSize += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); - } - } - - void ObjLoader::LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone) - { - Texture* loadedTexture = nullptr; - IwiLoader loader(zone->GetMemory()); - - if (image->streamedPartCount > 0) - { - for (auto* ipak : IPak::Repository) - { - auto ipakStream = ipak->GetEntryStream(image->hash, image->streamedParts[0].hash); - - if (ipakStream) - { - loadedTexture = loader.LoadIwi(*ipakStream); - - ipakStream->close(); - - if (loadedTexture != nullptr) - { - break; - } - } - } - } - - if (loadedTexture == nullptr) - { - const auto imageFileName = "images/" + std::string(image->name) + ".iwi"; - - { - const auto filePathImage = searchPath->Open(imageFileName); - if (filePathImage.IsOpen()) - { - loadedTexture = loader.LoadIwi(*filePathImage.m_stream); - } - } - } - - if (loadedTexture != nullptr) - { - image->texture.texture = loadedTexture; - image->loadedSize = 0; - - const auto textureMipCount = loadedTexture->GetMipMapCount(); - for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) - image->loadedSize += loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount(); - } - else - { - printf("Could not find data for image \"%s\"\n", image->name); - } - } - - void ObjLoader::LoadImageData(ISearchPath* searchPath, Zone* zone) - { - auto* assetPoolT6 = dynamic_cast(zone->m_pools.get()); - - if (assetPoolT6 && assetPoolT6->m_image != nullptr) - { - for (auto* imageEntry : *assetPoolT6->m_image) - { - auto* image = imageEntry->Asset(); - - if (image->loadedSize > 0) - { - continue; - } - - // Do not load linked assets - if (image->name && image->name[0] == ',') - { - continue; - } - - if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) - { - LoadImageFromLoadDef(image, zone); - } - else - { - LoadImageFromIwi(image, searchPath, zone); - } + LoadSoundBanksFromAsset(searchPath, *sndBankAssetInfo->Asset(), zone, loadedSoundBanksForZone); } } } - void ObjLoader::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const + void ObjLoader::UnloadContainersOfZone(Zone& zone) const { - LoadImageData(searchPath, zone); + IPak::Repository.RemoveContainerReferences(&zone); } - bool ObjLoader::LoadAssetForZone(AssetLoadingContext* context, const asset_type_t assetType, const std::string& assetName) const + bool ObjLoader::LoadAssetForZone(AssetLoadingContext& context, const asset_type_t assetType, const std::string& assetName) const { - AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, *context); + AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context); return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); } - void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext* context) const + void ObjLoader::FinalizeAssetsForZone(AssetLoadingContext& context) const { for (const auto& [type, loader] : m_asset_loaders_by_type) loader->FinalizeAssetsForZone(context); diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.h b/src/ObjLoading/Game/T6/ObjLoaderT6.h index 747841b69..e6cb0ee98 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.h +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.h @@ -6,52 +6,44 @@ #include "ObjContainer/SoundBank/SoundBank.h" #include "SearchPath/ISearchPath.h" -#include #include #include #include #include +#include namespace T6 { class ObjLoader final : public IObjLoader { - static const int IPAK_READ_HASH; - static const int GLOBAL_HASH; + public: + ObjLoader(); + + [[nodiscard]] bool SupportsZone(const Zone& zone) const override; - std::map> m_asset_loaders_by_type; + void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override; + void UnloadContainersOfZone(Zone& zone) const override; - static bool VerifySoundBankChecksum(const SoundBank* soundBank, const SndRuntimeAssetBank& sndRuntimeAssetBank); - static SoundBank* LoadSoundBankForZone(ISearchPath* searchPath, const std::string& soundBankFileName, Zone* zone); - static void LoadSoundBankFromLinkedInfo(ISearchPath* searchPath, + bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const override; + void FinalizeAssetsForZone(AssetLoadingContext& context) const override; + + private: + static bool VerifySoundBankChecksum(const SoundBank& soundBank, const SndRuntimeAssetBank& sndRuntimeAssetBank); + static SoundBank* LoadSoundBankForZone(ISearchPath& searchPath, const std::string& soundBankFileName, Zone& zone); + static void LoadSoundBankFromLinkedInfo(ISearchPath& searchPath, const std::string& soundBankFileName, - const SndRuntimeAssetBank* sndBankLinkedInfo, - Zone* zone, + const SndRuntimeAssetBank& sndBankLinkedInfo, + Zone& zone, std::set& loadedBanksForZone, std::stack& dependenciesToLoad); - static void LoadSoundBanksFromAsset(ISearchPath* searchPath, const SndBank* sndBank, Zone* zone, std::set& loadedBanksForZone); - - static void LoadIPakForZone(ISearchPath* searchPath, const std::string& ipakName, Zone* zone); - - static void LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone); - static void LoadImageFromLoadDef(GfxImage* image, Zone* zone); - static void LoadImageData(ISearchPath* searchPath, Zone* zone); - - static bool IsMpZone(Zone* zone); - static bool IsZmZone(Zone* zone); - static void LoadCommonIPaks(ISearchPath* searchPath, Zone* zone); - - public: - ObjLoader(); - - bool SupportsZone(Zone* zone) const override; + static void LoadSoundBanksFromAsset(ISearchPath& searchPath, const SndBank& sndBank, Zone& zone, std::set& loadedBanksForZone); - void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; - void UnloadContainersOfZone(Zone* zone) const override; + static void LoadIPakForZone(ISearchPath& searchPath, const std::string& ipakName, Zone& zone); + static void LoadCommonIPaks(ISearchPath& searchPath, Zone& zone); - void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const override; + static bool IsMpZone(const Zone& zone); + static bool IsZmZone(const Zone& zone); - bool LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const override; - void FinalizeAssetsForZone(AssetLoadingContext* context) const override; + std::unordered_map> m_asset_loaders_by_type; }; } // namespace T6 diff --git a/src/ObjLoading/IObjLoader.h b/src/ObjLoading/IObjLoader.h index ccf00d9aa..b494fe332 100644 --- a/src/ObjLoading/IObjLoader.h +++ b/src/ObjLoading/IObjLoader.h @@ -7,35 +7,33 @@ class IObjLoader { public: + IObjLoader() = default; virtual ~IObjLoader() = default; + IObjLoader(const IObjLoader& other) = default; + IObjLoader(IObjLoader&& other) noexcept = default; + IObjLoader& operator=(const IObjLoader& other) = default; + IObjLoader& operator=(IObjLoader&& other) noexcept = default; /** * \brief Checks whether this ObjLoader supports a specified zone. * \param zone The zone to check. * \return \c true if the specified zone is supported. */ - virtual bool SupportsZone(Zone* zone) const = 0; + [[nodiscard]] virtual bool SupportsZone(const Zone& zone) const = 0; /** * \brief Loads all containers that are referenced by a specified zone. * \param searchPath The search path object to use to find the referenced containers. * \param zone The zone to check for referenced containers. */ - virtual void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const = 0; + virtual void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const = 0; /** * \brief Unloads all containers of a specified zone. If a container is also loaded by another zone it will only be unloaded when all referencing zones are * unloaded. \param zone The zone to unload all containers for. */ - virtual void UnloadContainersOfZone(Zone* zone) const = 0; + virtual void UnloadContainersOfZone(Zone& zone) const = 0; - /** - * \brief Loads the obj data for all assets of a specified zone. - * \param searchPath The search path object to use to find obj files. - * \param zone The zone of the assets to load the obj data for. - */ - virtual void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const = 0; - - virtual bool LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const = 0; - virtual void FinalizeAssetsForZone(AssetLoadingContext* context) const = 0; + virtual bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const = 0; + virtual void FinalizeAssetsForZone(AssetLoadingContext& context) const = 0; }; diff --git a/src/ObjLoading/Image/DdsLoader.cpp b/src/ObjLoading/Image/DdsLoader.cpp deleted file mode 100644 index d8dc118cc..000000000 --- a/src/ObjLoading/Image/DdsLoader.cpp +++ /dev/null @@ -1,276 +0,0 @@ -#include "DdsLoader.h" - -#include "Image/DdsTypes.h" -#include "Utils/ClassUtils.h" -#include "Utils/FileUtils.h" - -#include - -class DdsLoaderInternal -{ - static constexpr auto DDS_MAGIC = FileUtils::MakeMagic32('D', 'D', 'S', ' '); - - MemoryManager* m_memory_manager; - std::istream& m_stream; - - TextureType m_texture_type; - bool m_has_mip_maps; - size_t m_width; - size_t m_height; - size_t m_depth; - const ImageFormat* m_format; - - _NODISCARD bool ReadMagic() const - { - uint32_t magic; - m_stream.read(reinterpret_cast(&magic), sizeof(magic)); - if (m_stream.gcount() != sizeof(magic)) - { - std::cout << "Failed to read dds data\n"; - return false; - } - - if (magic != DDS_MAGIC) - { - std::cout << "Invalid magic for dds\n"; - return false; - } - - return true; - } - - _NODISCARD bool ReadDxt10Header() - { - DDS_HEADER_DXT10 headerDx10{}; - m_stream.read(reinterpret_cast(&headerDx10), sizeof(headerDx10)); - if (m_stream.gcount() != sizeof(headerDx10)) - { - std::cout << "Failed to read dds data\n"; - return false; - } - - if (headerDx10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D) - { - m_texture_type = TextureType::T_3D; - } - else if (headerDx10.resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE2D) - { - if (headerDx10.miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE || headerDx10.arraySize == 6) - { - m_texture_type = TextureType::T_CUBE; - } - else - { - m_texture_type = TextureType::T_2D; - } - } - else - { - std::cout << "Unsupported dds resourceDimension " << headerDx10.resourceDimension << "\n"; - return false; - } - - for (const auto* imageFormat : ImageFormat::ALL_FORMATS) - { - if (imageFormat->GetDxgiFormat() == headerDx10.dxgiFormat) - { - m_format = imageFormat; - return true; - } - } - - std::cout << "Unsupported dds dxgi format " << headerDx10.dxgiFormat << "\n"; - return false; - } - - _NODISCARD bool ReadPixelFormatFourCc(DDS_PIXELFORMAT& pf) - { - switch (pf.dwFourCC) - { - case FileUtils::MakeMagic32('D', 'X', 'T', '1'): - m_format = &ImageFormat::FORMAT_BC1; - return true; - - case FileUtils::MakeMagic32('D', 'X', 'T', '3'): - m_format = &ImageFormat::FORMAT_BC2; - return true; - - case FileUtils::MakeMagic32('D', 'X', 'T', '5'): - m_format = &ImageFormat::FORMAT_BC3; - return true; - - case FileUtils::MakeMagic32('D', 'X', '1', '0'): - return ReadDxt10Header(); - - default: - std::cout << "Unknown dds FourCC " << pf.dwFourCC << "\n"; - return false; - } - } - - static void ExtractSizeAndOffsetFromMask(uint32_t mask, unsigned& offset, unsigned& size) - { - offset = 0; - size = 0; - - if (mask == 0) - return; - - while ((mask & 1) == 0) - { - offset++; - mask >>= 1; - } - - while ((mask & 1) == 1) - { - size++; - mask >>= 1; - } - } - - _NODISCARD bool ReadPixelFormatUnsigned(DDS_PIXELFORMAT& pf) - { - unsigned rOffset, rSize, gOffset, gSize, bOffset, bSize, aOffset, aSize; - - ExtractSizeAndOffsetFromMask(pf.dwRBitMask, rOffset, rSize); - ExtractSizeAndOffsetFromMask(pf.dwGBitMask, gOffset, gSize); - ExtractSizeAndOffsetFromMask(pf.dwBBitMask, bOffset, bSize); - ExtractSizeAndOffsetFromMask(pf.dwABitMask, aOffset, aSize); - - for (const auto* imageFormat : ImageFormat::ALL_FORMATS) - { - if (imageFormat->GetType() != ImageFormatType::UNSIGNED) - continue; - - const auto* unsignedImageFormat = dynamic_cast(imageFormat); - - if (unsignedImageFormat->m_r_offset == rOffset && unsignedImageFormat->m_r_size == rSize && unsignedImageFormat->m_g_offset == gOffset - && unsignedImageFormat->m_g_size == gSize && unsignedImageFormat->m_b_offset == bOffset && unsignedImageFormat->m_b_size == bSize - && unsignedImageFormat->m_a_offset == aOffset && unsignedImageFormat->m_a_size == aSize) - { - m_format = imageFormat; - return true; - } - } - - std::cout << "Failed to find dds pixel format: R=" << std::hex << pf.dwRBitMask << " G=" << std::hex << pf.dwGBitMask << " B=" << std::hex - << pf.dwBBitMask << " A=" << std::hex << pf.dwABitMask << "\n"; - - return false; - } - - _NODISCARD bool ReadPixelFormat(DDS_PIXELFORMAT& pf) - { - if (pf.dwFlags & DDPF_FOURCC) - return ReadPixelFormatFourCc(pf); - - return ReadPixelFormatUnsigned(pf); - } - - _NODISCARD bool ReadHeader() - { - DDS_HEADER header{}; - m_stream.read(reinterpret_cast(&header), sizeof(header)); - if (m_stream.gcount() != sizeof(header)) - { - std::cout << "Failed to read dds data\n"; - return false; - } - - m_width = header.dwWidth; - m_height = header.dwHeight; - m_depth = header.dwDepth; - m_has_mip_maps = (header.dwCaps & DDSCAPS_MIPMAP) != 0 || header.dwMipMapCount > 1; - - if (header.dwCaps2 & DDSCAPS2_CUBEMAP) - m_texture_type = TextureType::T_CUBE; - else if (header.dwDepth > 1) - m_texture_type = TextureType::T_3D; - else - m_texture_type = TextureType::T_2D; - - return ReadPixelFormat(header.ddspf); - } - - _NODISCARD Texture* ReadTextureData() const - { - Texture* result; - - switch (m_texture_type) - { - case TextureType::T_2D: - result = new Texture2D(m_format, m_width, m_height, m_has_mip_maps); - break; - - case TextureType::T_3D: - result = new Texture3D(m_format, m_width, m_height, m_depth, m_has_mip_maps); - break; - - case TextureType::T_CUBE: - result = new TextureCube(m_format, m_width, m_height, m_has_mip_maps); - break; - - default: - return nullptr; - } - - const auto mipMapCount = m_has_mip_maps ? result->GetMipMapCount() : 1; - const auto faceCount = m_texture_type == TextureType::T_CUBE ? 6 : 1; - - result->Allocate(); - - for (auto mipLevel = 0; mipLevel < mipMapCount; mipLevel++) - { - const auto mipSize = result->GetSizeOfMipLevel(mipLevel); - - for (auto face = 0; face < faceCount; face++) - { - m_stream.read(reinterpret_cast(result->GetBufferForMipLevel(mipLevel, face)), mipSize); - - if (m_stream.gcount() != mipSize) - { - std::cout << "Failed to read texture data from dds\n"; - delete result; - return nullptr; - } - } - } - - return result; - } - -public: - DdsLoaderInternal(MemoryManager* memoryManager, std::istream& stream) - : m_memory_manager(memoryManager), - m_stream(stream), - m_texture_type(TextureType::T_2D), - m_has_mip_maps(false), - m_width(0u), - m_height(0u), - m_depth(0u), - m_format(nullptr) - { - } - - Texture* LoadDds() - { - if (!ReadMagic() || !ReadHeader()) - { - return nullptr; - } - - return ReadTextureData(); - } -}; - -DdsLoader::DdsLoader(MemoryManager* memoryManager) - : m_memory_manager(memoryManager) -{ -} - -Texture* DdsLoader::LoadDds(std::istream& stream) const -{ - DdsLoaderInternal internal(m_memory_manager, stream); - return internal.LoadDds(); -} diff --git a/src/ObjLoading/Image/DdsLoader.h b/src/ObjLoading/Image/DdsLoader.h deleted file mode 100644 index 28aa59acd..000000000 --- a/src/ObjLoading/Image/DdsLoader.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "Image/Texture.h" -#include "Utils/MemoryManager.h" - -#include - -class DdsLoader -{ - MemoryManager* m_memory_manager; - -public: - explicit DdsLoader(MemoryManager* memoryManager); - - Texture* LoadDds(std::istream& stream) const; -}; diff --git a/src/ObjLoading/Image/IwiLoader.cpp b/src/ObjLoading/Image/IwiLoader.cpp deleted file mode 100644 index 18598fcea..000000000 --- a/src/ObjLoading/Image/IwiLoader.cpp +++ /dev/null @@ -1,476 +0,0 @@ -#include "IwiLoader.h" - -#include "Image/IwiTypes.h" - -#include -#include - -IwiLoader::IwiLoader(MemoryManager* memoryManager) -{ - m_memory_manager = memoryManager; -} - -const ImageFormat* IwiLoader::GetFormat6(int8_t format) -{ - switch (static_cast(format)) - { - case iwi6::IwiFormat::IMG_FORMAT_BITMAP_RGBA: - return &ImageFormat::FORMAT_R8_G8_B8_A8; - case iwi6::IwiFormat::IMG_FORMAT_BITMAP_RGB: - return &ImageFormat::FORMAT_R8_G8_B8; - case iwi6::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: - return &ImageFormat::FORMAT_A8; - case iwi6::IwiFormat::IMG_FORMAT_DXT1: - return &ImageFormat::FORMAT_BC1; - case iwi6::IwiFormat::IMG_FORMAT_DXT3: - return &ImageFormat::FORMAT_BC2; - case iwi6::IwiFormat::IMG_FORMAT_DXT5: - return &ImageFormat::FORMAT_BC3; - case iwi6::IwiFormat::IMG_FORMAT_DXN: - return &ImageFormat::FORMAT_BC5; - case iwi6::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: - return &ImageFormat::FORMAT_R8_A8; - case iwi6::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: - return &ImageFormat::FORMAT_R8; - case iwi6::IwiFormat::IMG_FORMAT_WAVELET_RGBA: // used - case iwi6::IwiFormat::IMG_FORMAT_WAVELET_RGB: // used - case iwi6::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: - case iwi6::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: - case iwi6::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: - printf("Unsupported IWI format: %i\n", format); - break; - default: - printf("Unknown IWI format: %i\n", format); - break; - } - - return nullptr; -} - -Texture* IwiLoader::LoadIwi6(std::istream& stream) const -{ - iwi6::IwiHeader header{}; - - stream.read(reinterpret_cast(&header), sizeof(header)); - if (stream.gcount() != sizeof(header)) - return nullptr; - - const auto* format = GetFormat6(header.format); - if (format == nullptr) - return nullptr; - - auto width = header.dimensions[0]; - auto height = header.dimensions[1]; - auto depth = header.dimensions[2]; - auto hasMipMaps = !(header.flags & iwi6::IwiFlags::IMG_FLAG_NOMIPMAPS); - - Texture* texture; - if (header.flags & iwi6::IwiFlags::IMG_FLAG_CUBEMAP) - { - texture = m_memory_manager->Create(format, width, height, hasMipMaps); - } - else if (header.flags & iwi6::IwiFlags::IMG_FLAG_VOLMAP) - { - texture = m_memory_manager->Create(format, width, height, depth, hasMipMaps); - } - else - { - texture = m_memory_manager->Create(format, width, height, hasMipMaps); - } - - texture->Allocate(); - - auto currentFileSize = sizeof(iwi6::IwiHeader) + sizeof(IwiVersion); - const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; - - for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) - { - const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); - currentFileSize += sizeOfMipLevel; - - if (currentMipLevel < static_cast(std::extent_v) - && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) - { - printf("Iwi has invalid file size for picmip %i\n", currentMipLevel); - - m_memory_manager->Delete(texture); - return nullptr; - } - - stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); - if (stream.gcount() != sizeOfMipLevel) - { - printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel); - - m_memory_manager->Delete(texture); - return nullptr; - } - } - - return texture; -} - -const ImageFormat* IwiLoader::GetFormat8(int8_t format) -{ - switch (static_cast(format)) - { - case iwi8::IwiFormat::IMG_FORMAT_BITMAP_RGBA: - return &ImageFormat::FORMAT_R8_G8_B8_A8; - case iwi8::IwiFormat::IMG_FORMAT_BITMAP_RGB: - return &ImageFormat::FORMAT_R8_G8_B8; - case iwi8::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: - return &ImageFormat::FORMAT_A8; - case iwi8::IwiFormat::IMG_FORMAT_DXT1: - return &ImageFormat::FORMAT_BC1; - case iwi8::IwiFormat::IMG_FORMAT_DXT3: - return &ImageFormat::FORMAT_BC2; - case iwi8::IwiFormat::IMG_FORMAT_DXT5: - return &ImageFormat::FORMAT_BC3; - case iwi8::IwiFormat::IMG_FORMAT_DXN: - return &ImageFormat::FORMAT_BC5; - case iwi8::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: - return &ImageFormat::FORMAT_R8_A8; - case iwi8::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: - return &ImageFormat::FORMAT_R8; - case iwi8::IwiFormat::IMG_FORMAT_WAVELET_RGBA: // used - case iwi8::IwiFormat::IMG_FORMAT_WAVELET_RGB: // used - case iwi8::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: - case iwi8::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: - case iwi8::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: - case iwi8::IwiFormat::IMG_FORMAT_DXT3A_AS_LUMINANCE: - case iwi8::IwiFormat::IMG_FORMAT_DXT5A_AS_LUMINANCE: - case iwi8::IwiFormat::IMG_FORMAT_DXT3A_AS_ALPHA: - case iwi8::IwiFormat::IMG_FORMAT_DXT5A_AS_ALPHA: - case iwi8::IwiFormat::IMG_FORMAT_DXT1_AS_LUMINANCE_ALPHA: - case iwi8::IwiFormat::IMG_FORMAT_DXN_AS_LUMINANCE_ALPHA: - case iwi8::IwiFormat::IMG_FORMAT_DXT1_AS_LUMINANCE: - case iwi8::IwiFormat::IMG_FORMAT_DXT1_AS_ALPHA: - printf("Unsupported IWI format: %i\n", format); - break; - default: - printf("Unknown IWI format: %i\n", format); - break; - } - - return nullptr; -} - -Texture* IwiLoader::LoadIwi8(std::istream& stream) const -{ - iwi8::IwiHeader header{}; - - stream.read(reinterpret_cast(&header), sizeof(header)); - if (stream.gcount() != sizeof(header)) - return nullptr; - - const auto* format = GetFormat8(header.format); - if (format == nullptr) - return nullptr; - - auto width = header.dimensions[0]; - auto height = header.dimensions[1]; - auto depth = header.dimensions[2]; - auto hasMipMaps = !(header.flags & iwi8::IwiFlags::IMG_FLAG_NOMIPMAPS); - - Texture* texture; - if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_CUBE) - { - texture = m_memory_manager->Create(format, width, height, hasMipMaps); - } - else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_3D) - { - texture = m_memory_manager->Create(format, width, height, depth, hasMipMaps); - } - else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_2D) - { - texture = m_memory_manager->Create(format, width, height, hasMipMaps); - } - else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_1D) - { - printf("Iwi has unsupported map type 1D\n"); - return nullptr; - } - else - { - printf("Iwi has unsupported map type\n"); - return nullptr; - } - - texture->Allocate(); - - auto currentFileSize = sizeof(iwi8::IwiHeader) + sizeof(IwiVersion); - const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; - - for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) - { - const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); - currentFileSize += sizeOfMipLevel; - - if (currentMipLevel < static_cast(std::extent_v) - && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) - { - printf("Iwi has invalid file size for picmip %i\n", currentMipLevel); - - m_memory_manager->Delete(texture); - return nullptr; - } - - stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); - if (stream.gcount() != sizeOfMipLevel) - { - printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel); - - m_memory_manager->Delete(texture); - return nullptr; - } - } - - return texture; -} - -const ImageFormat* IwiLoader::GetFormat13(int8_t format) -{ - switch (static_cast(format)) - { - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGBA: - return &ImageFormat::FORMAT_R8_G8_B8_A8; - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGB: - return &ImageFormat::FORMAT_R8_G8_B8; - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: - return &ImageFormat::FORMAT_A8; - case iwi13::IwiFormat::IMG_FORMAT_DXT1: - return &ImageFormat::FORMAT_BC1; - case iwi13::IwiFormat::IMG_FORMAT_DXT3: - return &ImageFormat::FORMAT_BC2; - case iwi13::IwiFormat::IMG_FORMAT_DXT5: - return &ImageFormat::FORMAT_BC3; - case iwi13::IwiFormat::IMG_FORMAT_DXN: - return &ImageFormat::FORMAT_BC5; - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: - return &ImageFormat::FORMAT_R8_A8; - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: - return &ImageFormat::FORMAT_R8; - case iwi13::IwiFormat::IMG_FORMAT_WAVELET_RGBA: // used - case iwi13::IwiFormat::IMG_FORMAT_WAVELET_RGB: // used - case iwi13::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: - case iwi13::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: - case iwi13::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGB565: - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGB5A3: - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_C8: - case iwi13::IwiFormat::IMG_FORMAT_BITMAP_RGBA8: - case iwi13::IwiFormat::IMG_FORMAT_A16B16G16R16F: - printf("Unsupported IWI format: %i\n", format); - break; - default: - printf("Unknown IWI format: %i\n", format); - break; - } - - return nullptr; -} - -Texture* IwiLoader::LoadIwi13(std::istream& stream) const -{ - iwi13::IwiHeader header{}; - - stream.read(reinterpret_cast(&header), sizeof(header)); - if (stream.gcount() != sizeof(header)) - return nullptr; - - const auto* format = GetFormat6(header.format); - if (format == nullptr) - return nullptr; - - auto width = header.dimensions[0]; - auto height = header.dimensions[1]; - auto depth = header.dimensions[2]; - auto hasMipMaps = !(header.flags & iwi13::IwiFlags::IMG_FLAG_NOMIPMAPS); - - Texture* texture; - if (header.flags & iwi13::IwiFlags::IMG_FLAG_CUBEMAP) - { - texture = m_memory_manager->Create(format, width, height, hasMipMaps); - } - else if (header.flags & iwi13::IwiFlags::IMG_FLAG_VOLMAP) - { - texture = m_memory_manager->Create(format, width, height, depth, hasMipMaps); - } - else - { - texture = m_memory_manager->Create(format, width, height, hasMipMaps); - } - - texture->Allocate(); - - auto currentFileSize = sizeof(iwi13::IwiHeader) + sizeof(IwiVersion); - const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; - - for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) - { - const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); - currentFileSize += sizeOfMipLevel; - - if (currentMipLevel < static_cast(std::extent_v) - && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) - { - printf("Iwi has invalid file size for picmip %i\n", currentMipLevel); - - m_memory_manager->Delete(texture); - return nullptr; - } - - stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); - if (stream.gcount() != sizeOfMipLevel) - { - printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel); - - m_memory_manager->Delete(texture); - return nullptr; - } - } - - return texture; -} - -const ImageFormat* IwiLoader::GetFormat27(int8_t format) -{ - switch (static_cast(format)) - { - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGBA: - return &ImageFormat::FORMAT_R8_G8_B8_A8; - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_ALPHA: - return &ImageFormat::FORMAT_A8; - case iwi27::IwiFormat::IMG_FORMAT_DXT1: - return &ImageFormat::FORMAT_BC1; - case iwi27::IwiFormat::IMG_FORMAT_DXT3: - return &ImageFormat::FORMAT_BC2; - case iwi27::IwiFormat::IMG_FORMAT_DXT5: - return &ImageFormat::FORMAT_BC3; - case iwi27::IwiFormat::IMG_FORMAT_DXN: - return &ImageFormat::FORMAT_BC5; - case iwi27::IwiFormat::IMG_FORMAT_A16B16G16R16F: - assert(false); // Unsupported yet - return &ImageFormat::FORMAT_R16_G16_B16_A16_FLOAT; - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB: - return &ImageFormat::FORMAT_R8_G8_B8; - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE_ALPHA: - return &ImageFormat::FORMAT_R8_A8; - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_LUMINANCE: - return &ImageFormat::FORMAT_R8; - case iwi27::IwiFormat::IMG_FORMAT_WAVELET_RGBA: - case iwi27::IwiFormat::IMG_FORMAT_WAVELET_RGB: - case iwi27::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE_ALPHA: - case iwi27::IwiFormat::IMG_FORMAT_WAVELET_LUMINANCE: - case iwi27::IwiFormat::IMG_FORMAT_WAVELET_ALPHA: - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB565: - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGB5A3: - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_C8: - case iwi27::IwiFormat::IMG_FORMAT_BITMAP_RGBA8: - printf("Unsupported IWI format: %i\n", format); - break; - default: - printf("Unknown IWI format: %i\n", format); - break; - } - - return nullptr; -} - -Texture* IwiLoader::LoadIwi27(std::istream& stream) const -{ - iwi27::IwiHeader header{}; - - stream.read(reinterpret_cast(&header), sizeof(header)); - if (stream.gcount() != sizeof(header)) - return nullptr; - - const auto* format = GetFormat27(header.format); - if (format == nullptr) - return nullptr; - - auto width = header.dimensions[0]; - auto height = header.dimensions[1]; - auto depth = header.dimensions[2]; - auto hasMipMaps = !(header.flags & iwi27::IwiFlags::IMG_FLAG_NOMIPMAPS); - - Texture* texture; - if (header.flags & iwi27::IwiFlags::IMG_FLAG_CUBEMAP) - { - texture = m_memory_manager->Create(format, width, height, hasMipMaps); - } - else if (header.flags & iwi27::IwiFlags::IMG_FLAG_VOLMAP) - { - texture = m_memory_manager->Create(format, width, height, depth, hasMipMaps); - } - else - { - texture = m_memory_manager->Create(format, width, height, hasMipMaps); - } - - texture->Allocate(); - - auto currentFileSize = sizeof(iwi27::IwiHeader) + sizeof(IwiVersion); - const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; - - for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) - { - const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); - currentFileSize += sizeOfMipLevel; - - if (currentMipLevel < static_cast(std::extent_v) - && currentFileSize != header.fileSizeForPicmip[currentMipLevel]) - { - printf("Iwi has invalid file size for picmip %i\n", currentMipLevel); - - m_memory_manager->Delete(texture); - return nullptr; - } - - stream.read(reinterpret_cast(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel); - if (stream.gcount() != sizeOfMipLevel) - { - printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel); - - m_memory_manager->Delete(texture); - return nullptr; - } - } - - return texture; -} - -Texture* IwiLoader::LoadIwi(std::istream& stream) -{ - IwiVersion iwiVersion{}; - - 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') - { - printf("Invalid IWI magic\n"); - } - - switch (iwiVersion.version) - { - case 6: - return LoadIwi6(stream); - - case 8: - return LoadIwi8(stream); - - case 13: - return LoadIwi13(stream); - - case 27: - return LoadIwi27(stream); - - default: - break; - } - - printf("Unknown IWI version %i\n", iwiVersion.version); - return nullptr; -} diff --git a/src/ObjLoading/Image/IwiLoader.h b/src/ObjLoading/Image/IwiLoader.h deleted file mode 100644 index 2a01572bb..000000000 --- a/src/ObjLoading/Image/IwiLoader.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "Image/Texture.h" -#include "Utils/MemoryManager.h" - -#include - -class IwiLoader -{ - MemoryManager* m_memory_manager; - - static const ImageFormat* GetFormat6(int8_t format); - Texture* LoadIwi6(std::istream& stream) const; - - static const ImageFormat* GetFormat8(int8_t format); - Texture* LoadIwi8(std::istream& stream) const; - - static const ImageFormat* GetFormat13(int8_t format); - Texture* LoadIwi13(std::istream& stream) const; - - static const ImageFormat* GetFormat27(int8_t format); - Texture* LoadIwi27(std::istream& stream) const; - -public: - explicit IwiLoader(MemoryManager* memoryManager); - - Texture* LoadIwi(std::istream& stream); -}; diff --git a/src/ObjLoading/ObjContainer/ObjContainerRepository.h b/src/ObjLoading/ObjContainer/ObjContainerRepository.h index 1f4fc27f7..f4cf97c89 100644 --- a/src/ObjLoading/ObjContainer/ObjContainerRepository.h +++ b/src/ObjLoading/ObjContainer/ObjContainerRepository.h @@ -29,8 +29,6 @@ template class ObjContainerRepo ObjContainerEntry& operator=(ObjContainerEntry&& other) noexcept = default; }; - std::vector m_containers; - public: ObjContainerRepository() = default; ~ObjContainerRepository() = default; @@ -120,4 +118,7 @@ template class ObjContainerRepo return entry.m_container.get(); }); } + +private: + std::vector m_containers; }; diff --git a/src/ObjLoading/ObjLoading.cpp b/src/ObjLoading/ObjLoading.cpp index a4727ec15..2a0524e7f 100644 --- a/src/ObjLoading/ObjLoading.cpp +++ b/src/ObjLoading/ObjLoading.cpp @@ -22,7 +22,7 @@ const IObjLoader* const OBJ_LOADERS[]{ new T6::ObjLoader(), }; -void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) +void ObjLoading::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) { for (const auto* loader : OBJ_LOADERS) { @@ -34,19 +34,7 @@ void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* } } -void ObjLoading::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) -{ - for (const auto* loader : OBJ_LOADERS) - { - if (loader->SupportsZone(zone)) - { - loader->LoadObjDataForZone(searchPath, zone); - return; - } - } -} - -void ObjLoading::UnloadContainersOfZone(Zone* zone) +void ObjLoading::UnloadContainersOfZone(Zone& zone) { for (const auto* loader : OBJ_LOADERS) { @@ -58,28 +46,28 @@ void ObjLoading::UnloadContainersOfZone(Zone* zone) } } -void ObjLoading::LoadIWDsInSearchPath(ISearchPath* searchPath) +void ObjLoading::LoadIWDsInSearchPath(ISearchPath& searchPath) { - searchPath->Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"), - [searchPath](const std::string& path) - { - auto file = std::make_unique(path, std::fstream::in | std::fstream::binary); - - if (file->is_open()) - { - auto iwd = std::make_unique(path, std::move(file)); - - if (iwd->Initialize()) - { - IWD::Repository.AddContainer(std::move(iwd), searchPath); - } - } - }); + searchPath.Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"), + [&searchPath](const std::string& path) + { + auto file = std::make_unique(path, std::fstream::in | std::fstream::binary); + + if (file->is_open()) + { + auto iwd = std::make_unique(path, std::move(file)); + + if (iwd->Initialize()) + { + IWD::Repository.AddContainer(std::move(iwd), &searchPath); + } + } + }); } -void ObjLoading::UnloadIWDsInSearchPath(ISearchPath* searchPath) +void ObjLoading::UnloadIWDsInSearchPath(ISearchPath& searchPath) { - IWD::Repository.RemoveContainerReferences(searchPath); + IWD::Repository.RemoveContainerReferences(&searchPath); } SearchPaths ObjLoading::GetIWDSearchPaths() @@ -94,11 +82,11 @@ SearchPaths ObjLoading::GetIWDSearchPaths() return iwdPaths; } -bool ObjLoading::LoadAssetForZone(AssetLoadingContext* context, const asset_type_t assetType, const std::string& assetName) +bool ObjLoading::LoadAssetForZone(AssetLoadingContext& context, const asset_type_t assetType, const std::string& assetName) { for (const auto* loader : OBJ_LOADERS) { - if (loader->SupportsZone(context->m_zone)) + if (loader->SupportsZone(context.m_zone)) { return loader->LoadAssetForZone(context, assetType, assetName); } @@ -107,11 +95,11 @@ bool ObjLoading::LoadAssetForZone(AssetLoadingContext* context, const asset_type return false; } -void ObjLoading::FinalizeAssetsForZone(AssetLoadingContext* context) +void ObjLoading::FinalizeAssetsForZone(AssetLoadingContext& context) { for (const auto* loader : OBJ_LOADERS) { - if (loader->SupportsZone(context->m_zone)) + if (loader->SupportsZone(context.m_zone)) { loader->FinalizeAssetsForZone(context); return; diff --git a/src/ObjLoading/ObjLoading.h b/src/ObjLoading/ObjLoading.h index 9582a50d1..c0baa1ad5 100644 --- a/src/ObjLoading/ObjLoading.h +++ b/src/ObjLoading/ObjLoading.h @@ -21,25 +21,25 @@ class ObjLoading * \param searchPath The search path to use to find the referenced containers. * \param zone The zone to load all referenced containers of. */ - static void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone); + static void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone); /** * \brief Unloads all containers that were referenced by a specified zone. If referenced by more than one zone a container will only be unloaded once all * referencing zones were unloaded the container. \param zone The zone to unload all referenced containers for. */ - static void UnloadContainersOfZone(Zone* zone); + static void UnloadContainersOfZone(Zone& zone); /** * \brief Loads all IWDs that can be found in a specified search path. * \param searchPath The search path that contains IWDs to be loaded. */ - static void LoadIWDsInSearchPath(ISearchPath* searchPath); + static void LoadIWDsInSearchPath(ISearchPath& searchPath); /** * \brief Unloads all IWDs that were loaded from the specified search path. * \param searchPath The search path that was used to load the IWDs to be unloaded. */ - static void UnloadIWDsInSearchPath(ISearchPath* searchPath); + static void UnloadIWDsInSearchPath(ISearchPath& searchPath); /** * \brief Creates a \c SearchPaths object containing all IWDs that are currently loaded. @@ -47,13 +47,6 @@ class ObjLoading */ static SearchPaths GetIWDSearchPaths(); - /** - * \brief Loads the obj data for all assets of a zone. - * \param searchPath The search path to use to search for all obj data files. - * \param zone The zone of the assets to load the obj data for. - */ - static void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone); - - static bool LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName); - static void FinalizeAssetsForZone(AssetLoadingContext* context); + static bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName); + static void FinalizeAssetsForZone(AssetLoadingContext& context); }; diff --git a/src/ObjLoading/SearchPath/SearchPaths.cpp b/src/ObjLoading/SearchPath/SearchPaths.cpp index 221bfaca4..58cf62a4f 100644 --- a/src/ObjLoading/SearchPath/SearchPaths.cpp +++ b/src/ObjLoading/SearchPath/SearchPaths.cpp @@ -1,5 +1,6 @@ #include "SearchPaths.h" +#include #include SearchPathOpenFile SearchPaths::Open(const std::string& fileName) @@ -38,11 +39,13 @@ void SearchPaths::CommitSearchPath(std::unique_ptr searchPath) void SearchPaths::IncludeSearchPath(ISearchPath* searchPath) { + assert(searchPath); m_search_paths.push_back(searchPath); } -void SearchPaths::RemoveSearchPath(ISearchPath* searchPath) +void SearchPaths::RemoveSearchPath(const ISearchPath* searchPath) { + assert(searchPath); for (auto i = m_search_paths.begin(); i != m_search_paths.end(); ++i) { if (*i == searchPath) diff --git a/src/ObjLoading/SearchPath/SearchPaths.h b/src/ObjLoading/SearchPath/SearchPaths.h index d327f5b2f..a1a06252d 100644 --- a/src/ObjLoading/SearchPath/SearchPaths.h +++ b/src/ObjLoading/SearchPath/SearchPaths.h @@ -40,7 +40,7 @@ class SearchPaths final : public ISearchPath * \brief Removes a search path from the \c SearchPaths object. If the search path was committed then it will \b NOT be deleted when destructing the \c * SearchPaths object. \param searchPath The search path to remove. */ - void RemoveSearchPath(ISearchPath* searchPath); + void RemoveSearchPath(const ISearchPath* searchPath); iterator begin(); iterator end(); diff --git a/src/ObjLoading/Sound/SoundCurveLoader.cpp b/src/ObjLoading/Sound/SoundCurveLoader.cpp index a1f2650c0..cb5034ddc 100644 --- a/src/ObjLoading/Sound/SoundCurveLoader.cpp +++ b/src/ObjLoading/Sound/SoundCurveLoader.cpp @@ -8,9 +8,9 @@ namespace sound_curve { std::unique_ptr LoadSoundCurve(const IAssetLoadingManager* manager, const std::string& soundCurveName) { - auto* searchPath = manager->GetAssetLoadingContext()->m_raw_search_path; + auto& searchPath = manager->GetAssetLoadingContext()->m_raw_search_path; const auto fileName = std::format("soundaliases/{}.vfcurve", soundCurveName); - const auto file = searchPath->Open(fileName); + const auto file = searchPath.Open(fileName); if (!file.IsOpen()) { return nullptr; diff --git a/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp b/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp index 4ffae119e..de09c1626 100644 --- a/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp +++ b/src/ObjLoading/Weapon/AccuracyGraphLoader.cpp @@ -9,9 +9,9 @@ namespace { std::unique_ptr LoadAccuracyGraph(const IAssetLoadingManager* manager, const std::string& graphName, const std::string& subFolder) { - auto* searchPath = manager->GetAssetLoadingContext()->m_raw_search_path; + auto& searchPath = manager->GetAssetLoadingContext()->m_raw_search_path; const auto fileName = std::format("accuracy/{}/{}", subFolder, graphName); - const auto file = searchPath->Open(fileName); + const auto file = searchPath.Open(fileName); if (!file.IsOpen()) { std::cerr << std::format("Failed to open file for accuracy graph: {}/{}\n", subFolder, graphName); diff --git a/src/ObjLoading/XModel/PartClassificationState.cpp b/src/ObjLoading/XModel/PartClassificationState.cpp index a09e33741..6667a4dfc 100644 --- a/src/ObjLoading/XModel/PartClassificationState.cpp +++ b/src/ObjLoading/XModel/PartClassificationState.cpp @@ -20,7 +20,7 @@ bool PartClassificationState::Load(const char** hitLocNames, const size_t hitLoc if (ObjLoading::Configuration.Verbose) std::cout << "Loading part classification...\n"; - const auto file = manager.GetAssetLoadingContext()->m_raw_search_path->Open(PART_CLASSIFICATION_FILE); + const auto file = manager.GetAssetLoadingContext()->m_raw_search_path.Open(PART_CLASSIFICATION_FILE); if (!file.IsOpen()) { std::cerr << std::format("Could not load part classification: Failed to open {}\n", PART_CLASSIFICATION_FILE); diff --git a/src/ObjLoading/XModel/XModelLoader.cpp.template b/src/ObjLoading/XModel/XModelLoader.cpp.template index 100acd527..01994f053 100644 --- a/src/ObjLoading/XModel/XModelLoader.cpp.template +++ b/src/ObjLoading/XModel/XModelLoader.cpp.template @@ -54,7 +54,7 @@ namespace GAME XModelLoader(std::istream& stream, MemoryManager& memory, IAssetLoadingManager& manager, std::set& dependencies) : m_stream(stream), m_memory(memory), - m_script_strings(manager.GetAssetLoadingContext()->m_zone->m_script_strings), + m_script_strings(manager.GetAssetLoadingContext()->m_zone.m_script_strings), m_manager(manager), m_part_classification_state(*m_manager.GetAssetLoadingContext()->GetZoneAssetLoaderState()), m_dependencies(dependencies) @@ -616,7 +616,7 @@ namespace GAME bool LoadLod(const JsonXModelLod& jLod, XModel& xmodel, unsigned lodNumber) { - const auto file = m_manager.GetAssetLoadingContext()->m_raw_search_path->Open(jLod.file); + const auto file = m_manager.GetAssetLoadingContext()->m_raw_search_path.Open(jLod.file); if (!file.IsOpen()) { PrintError(xmodel, std::format("Failed to open file for lod {}: \"{}\"", lodNumber, jLod.file)); diff --git a/src/ObjWriting.lua b/src/ObjWriting.lua index 39f15dca6..ac3e69e8e 100644 --- a/src/ObjWriting.lua +++ b/src/ObjWriting.lua @@ -3,6 +3,7 @@ ObjWriting = {} function ObjWriting:include(includes) if includes:handle(self:name()) then ObjCommon:include(includes) + ObjImage:include(includes) ObjLoading:include(includes) ZoneCommon:include(includes) includedirs { @@ -15,6 +16,7 @@ function ObjWriting:link(links) links:add(self:name()) links:linkto(Utils) links:linkto(ObjCommon) + links:linkto(ObjImage) links:linkto(ObjLoading) links:linkto(ZoneCommon) links:linkto(minilzo) diff --git a/src/ObjWriting/Dumping/AssetDumpingContext.h b/src/ObjWriting/Dumping/AssetDumpingContext.h index 1061ee62c..d4e78735b 100644 --- a/src/ObjWriting/Dumping/AssetDumpingContext.h +++ b/src/ObjWriting/Dumping/AssetDumpingContext.h @@ -2,6 +2,7 @@ #include "IZoneAssetDumperState.h" #include "Obj/Gdt/GdtStream.h" +#include "SearchPath/ISearchPath.h" #include "Utils/ClassUtils.h" #include "Zone/Zone.h" @@ -18,6 +19,7 @@ class AssetDumpingContext Zone* m_zone; std::string m_base_path; std::unique_ptr m_gdt; + ISearchPath* m_obj_search_path; AssetDumpingContext(); diff --git a/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperGfxImage.cpp b/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperGfxImage.cpp index f86ffe609..b482f8fbc 100644 --- a/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperGfxImage.cpp +++ b/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperGfxImage.cpp @@ -1,13 +1,63 @@ #include "AssetDumperGfxImage.h" #include "Image/DdsWriter.h" +#include "Image/Dx9TextureLoader.h" +#include "Image/IwiLoader.h" +#include "Image/IwiTypes.h" #include "Image/IwiWriter6.h" +#include "Image/Texture.h" #include "ObjWriting.h" +#include "SearchPath/ISearchPath.h" +#include #include +#include using namespace IW3; +namespace +{ + std::unique_ptr LoadImageFromLoadDef(const GfxImage* image) + { + Dx9TextureLoader textureLoader; + + 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) + textureLoader.Type(TextureType::T_3D); + else if (loadDef.flags & 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)); + return textureLoader.LoadTexture(loadDef.data); + } + + std::unique_ptr LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath) + { + const auto imageFileName = std::format("images/{}.iwi", image->name); + const auto filePathImage = searchPath->Open(imageFileName); + if (!filePathImage.IsOpen()) + { + std::cerr << std::format("Could not find data for image \"{}\"\n", image->name); + return nullptr; + } + + return iwi::LoadIwi(*filePathImage.m_stream); + } + + std::unique_ptr LoadImageData(ISearchPath* searchPath, const GfxImage* image) + { + if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) + return LoadImageFromLoadDef(image); + + return LoadImageFromIwi(image, searchPath); + } +} // namespace + AssetDumperGfxImage::AssetDumperGfxImage() { switch (ObjWriting::Configuration.ImageOutputFormat) @@ -27,37 +77,29 @@ AssetDumperGfxImage::AssetDumperGfxImage() bool AssetDumperGfxImage::ShouldDump(XAssetInfo* asset) { - const auto* image = asset->Asset(); - return image->cardMemory.platform[0] > 0; + return true; } -std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo* asset) const +std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo& asset) const { - std::string cleanAssetName = asset->m_name; - for (auto& c : cleanAssetName) - { - switch (c) - { - case '*': - c = '_'; - break; - - default: - break; - } - } + auto cleanAssetName = asset.m_name; + std::ranges::replace(cleanAssetName, '*', '_'); - return "images/" + cleanAssetName + m_writer->GetFileExtension(); + return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension()); } void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { const auto* image = asset->Asset(); - const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset)); + const auto texture = LoadImageData(context.m_obj_search_path, image); + if (!texture) + return; + + const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset)); if (!assetFile) return; auto& stream = *assetFile; - m_writer->DumpImage(stream, image->texture.texture); + m_writer->DumpImage(stream, texture.get()); } diff --git a/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperGfxImage.h b/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperGfxImage.h index d5a2792f0..009a7e57f 100644 --- a/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperGfxImage.h +++ b/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperGfxImage.h @@ -12,7 +12,7 @@ namespace IW3 { std::unique_ptr m_writer; - std::string GetAssetFileName(XAssetInfo* asset) const; + [[nodiscard]] std::string GetAssetFileName(const XAssetInfo& asset) const; protected: bool ShouldDump(XAssetInfo* asset) override; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxImage.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxImage.cpp index 93eebcb2d..fe311b935 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxImage.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxImage.cpp @@ -1,13 +1,60 @@ #include "AssetDumperGfxImage.h" #include "Image/DdsWriter.h" +#include "Image/Dx9TextureLoader.h" +#include "Image/IwiLoader.h" #include "Image/IwiWriter8.h" #include "ObjWriting.h" +#include #include +#include using namespace IW4; +namespace +{ + std::unique_ptr LoadImageFromLoadDef(const GfxImage* image) + { + Dx9TextureLoader textureLoader; + + 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) + textureLoader.Type(TextureType::T_3D); + else if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == 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)); + return textureLoader.LoadTexture(loadDef.data); + } + + std::unique_ptr LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath) + { + const auto imageFileName = std::format("images/{}.iwi", image->name); + const auto filePathImage = searchPath->Open(imageFileName); + if (!filePathImage.IsOpen()) + { + std::cerr << std::format("Could not find data for image \"{}\"\n", image->name); + return nullptr; + } + + return iwi::LoadIwi(*filePathImage.m_stream); + } + + std::unique_ptr LoadImageData(ISearchPath* searchPath, const GfxImage* image) + { + if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) + return LoadImageFromLoadDef(image); + + return LoadImageFromIwi(image, searchPath); + } +} // namespace + AssetDumperGfxImage::AssetDumperGfxImage() { switch (ObjWriting::Configuration.ImageOutputFormat) @@ -27,37 +74,29 @@ AssetDumperGfxImage::AssetDumperGfxImage() bool AssetDumperGfxImage::ShouldDump(XAssetInfo* asset) { - const auto* image = asset->Asset(); - return image->cardMemory.platform[0] > 0; + return true; } -std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo* asset) const +std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo& asset) const { - std::string cleanAssetName = asset->m_name; - for (auto& c : cleanAssetName) - { - switch (c) - { - case '*': - c = '_'; - break; - - default: - break; - } - } + auto cleanAssetName = asset.m_name; + std::ranges::replace(cleanAssetName, '*', '_'); - return "images/" + cleanAssetName + m_writer->GetFileExtension(); + return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension()); } void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { const auto* image = asset->Asset(); - const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset)); + const auto texture = LoadImageData(context.m_obj_search_path, image); + if (!texture) + return; + + const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset)); if (!assetFile) return; auto& stream = *assetFile; - m_writer->DumpImage(stream, image->texture.texture); + m_writer->DumpImage(stream, texture.get()); } diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxImage.h b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxImage.h index 4f3cf9d52..bcbee6ece 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxImage.h +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxImage.h @@ -12,7 +12,7 @@ namespace IW4 { std::unique_ptr m_writer; - std::string GetAssetFileName(XAssetInfo* asset) const; + [[nodiscard]] std::string GetAssetFileName(const XAssetInfo& asset) const; protected: bool ShouldDump(XAssetInfo* asset) override; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperTechniqueSet.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperTechniqueSet.cpp index 610b18cbf..101d323d2 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperTechniqueSet.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperTechniqueSet.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperGfxImage.cpp b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperGfxImage.cpp index 01b644812..8e3e76d12 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperGfxImage.cpp +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperGfxImage.cpp @@ -1,13 +1,61 @@ #include "AssetDumperGfxImage.h" #include "Image/DdsWriter.h" +#include "Image/Dx9TextureLoader.h" +#include "Image/IwiLoader.h" #include "Image/IwiWriter8.h" #include "ObjWriting.h" +#include #include +#include using namespace IW5; +namespace +{ + std::unique_ptr LoadImageFromLoadDef(const GfxImage* image) + { + Dx9TextureLoader textureLoader; + + 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) + textureLoader.Type(TextureType::T_3D); + else if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == 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)); + return textureLoader.LoadTexture(loadDef.data); + } + + std::unique_ptr LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath) + { + const auto imageFileName = std::format("images/{}.iwi", image->name); + const auto filePathImage = searchPath->Open(imageFileName); + if (!filePathImage.IsOpen()) + { + std::cerr << std::format("Could not find data for image \"{}\"\n", image->name); + return nullptr; + } + + return iwi::LoadIwi(*filePathImage.m_stream); + } + + std::unique_ptr LoadImageData(ISearchPath* searchPath, const GfxImage* image) + { + if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) + return LoadImageFromLoadDef(image); + + return LoadImageFromIwi(image, searchPath); + } +} // namespace + AssetDumperGfxImage::AssetDumperGfxImage() { switch (ObjWriting::Configuration.ImageOutputFormat) @@ -27,37 +75,29 @@ AssetDumperGfxImage::AssetDumperGfxImage() bool AssetDumperGfxImage::ShouldDump(XAssetInfo* asset) { - const auto* image = asset->Asset(); - return image->cardMemory.platform[0] > 0; + return true; } -std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo* asset) const +std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo& asset) const { - std::string cleanAssetName = asset->m_name; - for (auto& c : cleanAssetName) - { - switch (c) - { - case '*': - c = '_'; - break; - - default: - break; - } - } + auto cleanAssetName = asset.m_name; + std::ranges::replace(cleanAssetName, '*', '_'); - return "images/" + cleanAssetName + m_writer->GetFileExtension(); + return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension()); } void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { const auto* image = asset->Asset(); - const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset)); + const auto texture = LoadImageData(context.m_obj_search_path, image); + if (!texture) + return; + + const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset)); if (!assetFile) return; auto& stream = *assetFile; - m_writer->DumpImage(stream, image->texture.texture); + m_writer->DumpImage(stream, texture.get()); } diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperGfxImage.h b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperGfxImage.h index 2cd2ec80d..fac3f66b6 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperGfxImage.h +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperGfxImage.h @@ -12,7 +12,7 @@ namespace IW5 { std::unique_ptr m_writer; - std::string GetAssetFileName(XAssetInfo* asset) const; + [[nodiscard]] std::string GetAssetFileName(const XAssetInfo& asset) const; protected: bool ShouldDump(XAssetInfo* asset) override; diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.cpp b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.cpp index fca948780..c150e2d9c 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.cpp +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.cpp @@ -1,13 +1,60 @@ #include "AssetDumperGfxImage.h" #include "Image/DdsWriter.h" -#include "Image/IwiWriter27.h" +#include "Image/Dx9TextureLoader.h" +#include "Image/IwiLoader.h" +#include "Image/IwiWriter13.h" #include "ObjWriting.h" +#include #include +#include using namespace T5; +namespace +{ + std::unique_ptr LoadImageFromLoadDef(const GfxImage* image) + { + Dx9TextureLoader textureLoader; + + const auto& loadDef = *image->texture.loadDef; + textureLoader.Width(image->width).Height(image->height).Depth(image->depth); + + if (loadDef.flags & iwi13::IMG_FLAG_VOLMAP) + textureLoader.Type(TextureType::T_3D); + else if (loadDef.flags & 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)); + return textureLoader.LoadTexture(loadDef.data); + } + + std::unique_ptr LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath) + { + const auto imageFileName = std::format("images/{}.iwi", image->name); + const auto filePathImage = searchPath->Open(imageFileName); + if (!filePathImage.IsOpen()) + { + std::cerr << std::format("Could not find data for image \"{}\"\n", image->name); + return nullptr; + } + + return iwi::LoadIwi(*filePathImage.m_stream); + } + + std::unique_ptr LoadImageData(ISearchPath* searchPath, const GfxImage* image) + { + if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) + return LoadImageFromLoadDef(image); + + return LoadImageFromIwi(image, searchPath); + } +} // namespace + AssetDumperGfxImage::AssetDumperGfxImage() { switch (ObjWriting::Configuration.ImageOutputFormat) @@ -16,7 +63,7 @@ AssetDumperGfxImage::AssetDumperGfxImage() m_writer = std::make_unique(); break; case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI: - m_writer = std::make_unique(); + m_writer = std::make_unique(); break; default: assert(false); @@ -27,37 +74,29 @@ AssetDumperGfxImage::AssetDumperGfxImage() bool AssetDumperGfxImage::ShouldDump(XAssetInfo* asset) { - const auto* image = asset->Asset(); - return image->loadedSize > 0; + return true; } -std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo* asset) const +std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo& asset) const { - std::string cleanAssetName = asset->m_name; - for (auto& c : cleanAssetName) - { - switch (c) - { - case '*': - c = '_'; - break; - - default: - break; - } - } + auto cleanAssetName = asset.m_name; + std::ranges::replace(cleanAssetName, '*', '_'); - return "images/" + cleanAssetName + m_writer->GetFileExtension(); + return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension()); } void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { const auto* image = asset->Asset(); - const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset)); + const auto texture = LoadImageData(context.m_obj_search_path, image); + if (!texture) + return; + + const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset)); if (!assetFile) return; auto& stream = *assetFile; - m_writer->DumpImage(stream, image->texture.texture); + m_writer->DumpImage(stream, texture.get()); } diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.h b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.h index c1a158a22..b9f89b36a 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.h +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.h @@ -12,7 +12,7 @@ namespace T5 { std::unique_ptr m_writer; - std::string GetAssetFileName(XAssetInfo* asset) const; + [[nodiscard]] std::string GetAssetFileName(const XAssetInfo& asset) const; protected: bool ShouldDump(XAssetInfo* asset) override; diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperGfxImage.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperGfxImage.cpp index f51e26e98..bb89ddd30 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperGfxImage.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperGfxImage.cpp @@ -1,13 +1,78 @@ #include "AssetDumperGfxImage.h" #include "Image/DdsWriter.h" +#include "Image/Dx12TextureLoader.h" +#include "Image/IwiLoader.h" #include "Image/IwiWriter27.h" +#include "ObjContainer/IPak/IPak.h" #include "ObjWriting.h" +#include #include +#include using namespace T6; +namespace +{ + std::unique_ptr LoadImageFromLoadDef(const GfxImage* image) + { + Dx12TextureLoader textureLoader; + + const auto& loadDef = *image->texture.loadDef; + textureLoader.Width(image->width).Height(image->height).Depth(image->depth); + + if (loadDef.flags & iwi27::IMG_FLAG_VOLMAP) + textureLoader.Type(TextureType::T_3D); + else if (loadDef.flags & 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)); + return textureLoader.LoadTexture(loadDef.data); + } + + std::unique_ptr LoadImageFromIwi(const GfxImage* image, ISearchPath* searchPath) + { + if (image->streamedPartCount > 0) + { + for (auto* ipak : IPak::Repository) + { + auto ipakStream = ipak->GetEntryStream(image->hash, image->streamedParts[0].hash); + + if (ipakStream) + { + auto loadedTexture = iwi::LoadIwi(*ipakStream); + ipakStream->close(); + + if (loadedTexture != nullptr) + return loadedTexture; + } + } + } + + const auto imageFileName = std::format("images/{}.iwi", image->name); + const auto filePathImage = searchPath->Open(imageFileName); + if (!filePathImage.IsOpen()) + { + std::cerr << std::format("Could not find data for image \"{}\"\n", image->name); + return nullptr; + } + + return iwi::LoadIwi(*filePathImage.m_stream); + } + + std::unique_ptr LoadImageData(ISearchPath* searchPath, const GfxImage* image) + { + if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) + return LoadImageFromLoadDef(image); + + return LoadImageFromIwi(image, searchPath); + } +} // namespace + AssetDumperGfxImage::AssetDumperGfxImage() { switch (ObjWriting::Configuration.ImageOutputFormat) @@ -27,37 +92,29 @@ AssetDumperGfxImage::AssetDumperGfxImage() bool AssetDumperGfxImage::ShouldDump(XAssetInfo* asset) { - const auto* image = asset->Asset(); - return image->loadedSize > 0; + return true; } -std::string AssetDumperGfxImage::GetAssetFileName(XAssetInfo* asset) const +std::string AssetDumperGfxImage::GetAssetFileName(const XAssetInfo& asset) const { - std::string cleanAssetName = asset->m_name; - for (auto& c : cleanAssetName) - { - switch (c) - { - case '*': - c = '_'; - break; + auto cleanAssetName = asset.m_name; + std::ranges::replace(cleanAssetName, '*', '_'); - default: - break; - } - } - - return "images/" + cleanAssetName + m_writer->GetFileExtension(); + return std::format("images/{}{}", cleanAssetName, m_writer->GetFileExtension()); } void AssetDumperGfxImage::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { const auto* image = asset->Asset(); - const auto assetFile = context.OpenAssetFile(GetAssetFileName(asset)); + const auto texture = LoadImageData(context.m_obj_search_path, image); + if (!texture) + return; + + const auto assetFile = context.OpenAssetFile(GetAssetFileName(*asset)); if (!assetFile) return; auto& stream = *assetFile; - m_writer->DumpImage(stream, image->texture.texture); + m_writer->DumpImage(stream, texture.get()); } diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperGfxImage.h b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperGfxImage.h index 820c90ae8..401aae5ef 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperGfxImage.h +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperGfxImage.h @@ -12,7 +12,7 @@ namespace T6 { std::unique_ptr m_writer; - std::string GetAssetFileName(XAssetInfo* asset) const; + std::string GetAssetFileName(const XAssetInfo& asset) const; protected: bool ShouldDump(XAssetInfo* asset) override; diff --git a/src/ObjWriting/Image/IImageWriter.h b/src/ObjWriting/Image/IImageWriter.h deleted file mode 100644 index d494c656f..000000000 --- a/src/ObjWriting/Image/IImageWriter.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "Image/Texture.h" - -#include -#include - -class IImageWriter -{ -public: - virtual ~IImageWriter() = default; - - virtual bool SupportsImageFormat(const ImageFormat* imageFormat) = 0; - virtual std::string GetFileExtension() = 0; - virtual void DumpImage(std::ostream& stream, Texture* texture) = 0; -}; diff --git a/src/RawTemplater/RawTemplaterArguments.cpp b/src/RawTemplater/RawTemplaterArguments.cpp index d3879b10b..7962e1644 100644 --- a/src/RawTemplater/RawTemplaterArguments.cpp +++ b/src/RawTemplater/RawTemplaterArguments.cpp @@ -4,38 +4,55 @@ #include "Utils/Arguments/CommandLineOption.h" #include "Utils/Arguments/UsageInformation.h" +#include #include #include +// clang-format off const CommandLineOption* const OPTION_HELP = - CommandLineOption::Builder::Create().WithShortName("?").WithLongName("help").WithDescription("Displays usage information.").Build(); + CommandLineOption::Builder::Create() + .WithShortName("?") + .WithLongName("help") + .WithDescription("Displays usage information.") + .Build(); const CommandLineOption* const OPTION_VERSION = - CommandLineOption::Builder::Create().WithLongName("version").WithDescription("Prints the application version.").Build(); + CommandLineOption::Builder::Create() + .WithLongName("version") + .WithDescription("Prints the application version.") + .Build(); const CommandLineOption* const OPTION_VERBOSE = - CommandLineOption::Builder::Create().WithShortName("v").WithLongName("verbose").WithDescription("Outputs a lot more and more detailed messages.").Build(); - -const CommandLineOption* const OPTION_OUTPUT_FOLDER = CommandLineOption::Builder::Create() - .WithShortName("o") - .WithLongName("output") - .WithDescription("Specify the folder to save the generated files. Defaults to the current directory.") - .WithParameter("outputPath") - .Build(); - -const CommandLineOption* const OPTION_BUILD_LOG = CommandLineOption::Builder::Create() - .WithLongName("build-log") - .WithDescription("Specify a file to write a build log to.") - .WithParameter("logFilePath") - .Build(); - -const CommandLineOption* const OPTION_DEFINE = CommandLineOption::Builder::Create() - .WithShortName("d") - .WithLongName("define") - .WithDescription("Adds a define for the templating process. Can be of format define or define=value.") - .WithParameter("defineValue") - .Reusable() - .Build(); + CommandLineOption::Builder::Create() + .WithShortName("v") + .WithLongName("verbose") + .WithDescription("Outputs a lot more and more detailed messages.") + .Build(); + +const CommandLineOption* const OPTION_OUTPUT_FOLDER = + CommandLineOption::Builder::Create() + .WithShortName("o") + .WithLongName("output") + .WithDescription("Specify the folder to save the generated files. Defaults to the current directory.") + .WithParameter("outputPath") + .Build(); + +const CommandLineOption* const OPTION_BUILD_LOG = + CommandLineOption::Builder::Create() + .WithLongName("build-log") + .WithDescription("Specify a file to write a build log to.") + .WithParameter("logFilePath") + .Build(); + +const CommandLineOption* const OPTION_DEFINE = + CommandLineOption::Builder::Create() + .WithShortName("d") + .WithLongName("define") + .WithDescription("Adds a define for the templating process. Can be of format define or define=value.") + .WithParameter("defineValue") + .Reusable() + .Build(); +// clang-format on const CommandLineOption* const COMMAND_LINE_OPTIONS[]{ OPTION_HELP, @@ -52,9 +69,9 @@ RawTemplaterArguments::RawTemplaterArguments() { } -void RawTemplaterArguments::PrintUsage() +void RawTemplaterArguments::PrintUsage() const { - UsageInformation usage("RawTemplater.exe"); + UsageInformation usage(m_argument_parser.GetExecutableName()); for (const auto* commandLineOption : COMMAND_LINE_OPTIONS) { @@ -66,13 +83,13 @@ void RawTemplaterArguments::PrintUsage() void RawTemplaterArguments::PrintVersion() { - std::cout << "OpenAssetTools RawTemplater " << std::string(GIT_VERSION) << "\n"; + std::cout << std::format("OpenAssetTools RawTemplater {}\n", GIT_VERSION); } bool RawTemplaterArguments::ParseArgs(const int argc, const char** argv, bool& shouldContinue) { shouldContinue = true; - if (!m_argument_parser.ParseArguments(argc - 1, &argv[1])) + if (!m_argument_parser.ParseArguments(argc, argv)) { PrintUsage(); return false; @@ -122,9 +139,9 @@ bool RawTemplaterArguments::ParseArgs(const int argc, const char** argv, bool& s const auto separator = arg.find('='); if (separator != std::string::npos) - m_defines.emplace_back(std::make_pair(arg.substr(0, separator), arg.substr(separator + 1))); + m_defines.emplace_back(arg.substr(0, separator), arg.substr(separator + 1)); else - m_defines.emplace_back(std::make_pair(arg, std::string())); + m_defines.emplace_back(arg, std::string()); } } diff --git a/src/RawTemplater/RawTemplaterArguments.h b/src/RawTemplater/RawTemplaterArguments.h index dadb1f88f..cfaac7b3e 100644 --- a/src/RawTemplater/RawTemplaterArguments.h +++ b/src/RawTemplater/RawTemplaterArguments.h @@ -13,7 +13,7 @@ class RawTemplaterArguments /** * \brief Prints a command line usage help text for the RawTemplater tool to stdout. */ - static void PrintUsage(); + void PrintUsage() const; static void PrintVersion(); public: diff --git a/src/Unlinker/Unlinker.cpp b/src/Unlinker/Unlinker.cpp index 7d4b507ab..284bad9fb 100644 --- a/src/Unlinker/Unlinker.cpp +++ b/src/Unlinker/Unlinker.cpp @@ -13,12 +13,12 @@ #include "SearchPath/SearchPathFilesystem.h" #include "SearchPath/SearchPaths.h" #include "UnlinkerArgs.h" -#include "Utils/Arguments/ArgumentParser.h" #include "Utils/ClassUtils.h" #include "Utils/ObjFileStream.h" #include "ZoneLoading.h" #include +#include #include #include #include @@ -35,13 +35,32 @@ const IZoneDefWriter* const ZONE_DEF_WRITERS[]{ class Unlinker::Impl { - UnlinkerArgs m_args; - SearchPaths m_search_paths; - SearchPathFilesystem* m_last_zone_search_path; - std::set m_absolute_search_paths; +public: + /** + * \copydoc Unlinker::Start + */ + bool Start(const int argc, const char** argv) + { + auto shouldContinue = true; + if (!m_args.ParseArgs(argc, argv, shouldContinue)) + return false; - std::vector> m_loaded_zones; + if (!shouldContinue) + return true; + + if (!BuildSearchPaths()) + return false; + + if (!LoadZones()) + return false; + + const auto result = UnlinkZones(); + + UnloadZones(); + return result; + } +private: _NODISCARD bool ShouldLoadObj() const { return m_args.m_task != UnlinkerArgs::ProcessingTask::LIST && !m_args.m_skip_obj; @@ -51,14 +70,12 @@ class Unlinker::Impl * \brief Loads a search path. * \param searchPath The search path to load. */ - void LoadSearchPath(ISearchPath* searchPath) const + void LoadSearchPath(ISearchPath& searchPath) const { if (ShouldLoadObj()) { if (m_args.m_verbose) - { - printf("Loading search path: \"%s\"\n", searchPath->GetPath().c_str()); - } + std::cout << std::format("Loading search path: \"{}\"\n", searchPath.GetPath()); ObjLoading::LoadIWDsInSearchPath(searchPath); } @@ -68,14 +85,12 @@ class Unlinker::Impl * \brief Unloads a search path. * \param searchPath The search path to unload. */ - void UnloadSearchPath(ISearchPath* searchPath) const + void UnloadSearchPath(ISearchPath& searchPath) const { if (ShouldLoadObj()) { if (m_args.m_verbose) - { - printf("Unloading search path: \"%s\"\n", searchPath->GetPath().c_str()); - } + std::cout << std::format("Unloading search path: \"{}\"\n", searchPath.GetPath()); ObjLoading::UnloadIWDsInSearchPath(searchPath); } @@ -93,19 +108,18 @@ class Unlinker::Impl if (m_last_zone_search_path != nullptr && m_last_zone_search_path->GetPath() == absoluteZoneDirectory) { - searchPathsForZone.IncludeSearchPath(m_last_zone_search_path); + searchPathsForZone.IncludeSearchPath(m_last_zone_search_path.get()); } else if (m_absolute_search_paths.find(absoluteZoneDirectory) == m_absolute_search_paths.end()) { - if (m_last_zone_search_path != nullptr) + if (m_last_zone_search_path) { - UnloadSearchPath(m_last_zone_search_path); - delete m_last_zone_search_path; + UnloadSearchPath(*m_last_zone_search_path); } - m_last_zone_search_path = new SearchPathFilesystem(absoluteZoneDirectory); - searchPathsForZone.IncludeSearchPath(m_last_zone_search_path); - LoadSearchPath(m_last_zone_search_path); + m_last_zone_search_path = std::make_unique(absoluteZoneDirectory); + searchPathsForZone.IncludeSearchPath(m_last_zone_search_path.get()); + LoadSearchPath(*m_last_zone_search_path); } for (auto* iwd : IWD::Repository) @@ -128,12 +142,12 @@ class Unlinker::Impl if (!fs::is_directory(absolutePath)) { - printf("Could not find directory of search path: \"%s\"\n", path.c_str()); + std::cerr << std::format("Could not find directory of search path: \"{}\"\n", path); return false; } auto searchPath = std::make_unique(absolutePath.string()); - LoadSearchPath(searchPath.get()); + LoadSearchPath(*searchPath); m_search_paths.CommitSearchPath(std::move(searchPath)); m_absolute_search_paths.insert(absolutePath.string()); @@ -141,16 +155,12 @@ class Unlinker::Impl if (m_args.m_verbose) { - printf("%u SearchPaths%s\n", m_absolute_search_paths.size(), !m_absolute_search_paths.empty() ? ":" : ""); + std::cout << std::format("{} SearchPaths{}\n", m_absolute_search_paths.size(), !m_absolute_search_paths.empty() ? ":" : ""); for (const auto& absoluteSearchPath : m_absolute_search_paths) - { - printf(" \"%s\"\n", absoluteSearchPath.c_str()); - } + std::cout << std::format(" \"{}\"\n", absoluteSearchPath); if (!m_absolute_search_paths.empty()) - { - puts(""); - } + std::cerr << "\n"; } return true; @@ -165,7 +175,7 @@ class Unlinker::Impl std::ofstream zoneDefinitionFile(zoneDefinitionFilePath, std::fstream::out | std::fstream::binary); if (!zoneDefinitionFile.is_open()) { - printf("Failed to open file for zone definition file of zone \"%s\".\n", zone->m_name.c_str()); + std::cerr << std::format("Failed to open file for zone definition file of zone \"{}\".\n", zone->m_name); return false; } @@ -181,9 +191,7 @@ class Unlinker::Impl } if (!result) - { - printf("Failed to find writer for zone definition file of zone \"%s\".\n", zone->m_name.c_str()); - } + std::cerr << std::format("Failed to find writer for zone definition file of zone \"{}\".\n", zone->m_name); zoneDefinitionFile.close(); return result; @@ -202,7 +210,7 @@ class Unlinker::Impl stream = std::ofstream(gdtFilePath, std::fstream::out | std::fstream::binary); if (!stream.is_open()) { - printf("Failed to open file for zone definition file of zone \"%s\".\n", zone->m_name.c_str()); + std::cerr << std::format("Failed to open file for zone definition file of zone \"{}\".\n", zone->m_name); return false; } @@ -236,7 +244,7 @@ class Unlinker::Impl { if (!handledSpecifiedAssets[i]) { - std::cerr << "Unknown asset type \"" << m_args.m_specified_asset_types[i] << "\"\n"; + std::cerr << std::format("Unknown asset type \"{}\"\n", m_args.m_specified_asset_types[i]); anySpecifiedValueInvalid = true; } } @@ -262,10 +270,11 @@ class Unlinker::Impl /** * \brief Performs the tasks specified by the command line arguments on the specified zone. + * \param searchPath The search path for obj data. * \param zone The zone to handle. * \return \c true if handling the zone was successful, otherwise \c false. */ - bool HandleZone(Zone* zone) const + bool HandleZone(ISearchPath& searchPath, Zone* zone) const { if (m_args.m_task == UnlinkerArgs::ProcessingTask::LIST) { @@ -288,6 +297,7 @@ class Unlinker::Impl AssetDumpingContext context; context.m_zone = zone; context.m_base_path = outputFolderPath; + context.m_obj_search_path = &searchPath; if (m_args.m_use_gdt) { @@ -318,7 +328,7 @@ class Unlinker::Impl { if (!fs::is_regular_file(zonePath)) { - printf("Could not find file \"%s\".\n", zonePath.c_str()); + std::cerr << std::format("Could not find file \"{}\".\n", zonePath); continue; } @@ -330,20 +340,15 @@ class Unlinker::Impl auto zone = ZoneLoading::LoadZone(zonePath); if (zone == nullptr) { - printf("Failed to load zone \"%s\".\n", zonePath.c_str()); + std::cerr << std::format("Failed to load zone \"{}\".\n", zonePath); return false; } if (m_args.m_verbose) - { - printf("Loaded zone \"%s\"\n", zone->m_name.c_str()); - } + std::cout << std::format("Loaded zone \"{}\"\n", zone->m_name); if (ShouldLoadObj()) - { - ObjLoading::LoadReferencedContainersForZone(&searchPathsForZone, zone.get()); - ObjLoading::LoadObjDataForZone(&searchPathsForZone, zone.get()); - } + ObjLoading::LoadReferencedContainersForZone(searchPathsForZone, *zone); m_loaded_zones.emplace_back(std::move(zone)); } @@ -356,17 +361,17 @@ class Unlinker::Impl for (auto i = m_loaded_zones.rbegin(); i != m_loaded_zones.rend(); ++i) { auto& loadedZone = *i; - std::string zoneName = loadedZone->m_name; + + // Copy zone name since we deallocate before logging + const auto zoneName = loadedZone->m_name; if (ShouldLoadObj()) - { - ObjLoading::UnloadContainersOfZone(loadedZone.get()); - } + ObjLoading::UnloadContainersOfZone(*loadedZone); loadedZone.reset(); if (m_args.m_verbose) - std::cout << "Unloaded zone \"" << zoneName << "\"\n"; + std::cout << std::format("Unloaded zone \"{}\"\n", zoneName); } m_loaded_zones.clear(); } @@ -377,7 +382,7 @@ class Unlinker::Impl { if (!fs::is_regular_file(zonePath)) { - printf("Could not find file \"%s\".\n", zonePath.c_str()); + std::cerr << std::format("Could not find file \"{}\".\n", zonePath); continue; } @@ -393,63 +398,37 @@ class Unlinker::Impl auto zone = ZoneLoading::LoadZone(zonePath); if (zone == nullptr) { - printf("Failed to load zone \"%s\".\n", zonePath.c_str()); + std::cerr << std::format("Failed to load zone \"{}\".\n", zonePath); return false; } zoneName = zone->m_name; if (m_args.m_verbose) - std::cout << "Loaded zone \"" << zoneName << "\"\n"; + std::cout << std::format("Loaded zone \"{}\"\n", zoneName); if (ShouldLoadObj()) - { - ObjLoading::LoadReferencedContainersForZone(&searchPathsForZone, zone.get()); - ObjLoading::LoadObjDataForZone(&searchPathsForZone, zone.get()); - } + ObjLoading::LoadReferencedContainersForZone(searchPathsForZone, *zone); - if (!HandleZone(zone.get())) + if (!HandleZone(searchPathsForZone, zone.get())) return false; if (ShouldLoadObj()) - ObjLoading::UnloadContainersOfZone(zone.get()); + ObjLoading::UnloadContainersOfZone(*zone); zone.reset(); if (m_args.m_verbose) - std::cout << "Unloaded zone \"" << zoneName << "\"\n"; + std::cout << std::format("Unloaded zone \"{}\"\n", zoneName); } return true; } -public: - Impl() - { - m_last_zone_search_path = nullptr; - } - - /** - * \copydoc Unlinker::Start - */ - bool Start(const int argc, const char** argv) - { - auto shouldContinue = true; - if (!m_args.ParseArgs(argc, argv, shouldContinue)) - return false; - - if (!shouldContinue) - return true; - - if (!BuildSearchPaths()) - return false; - - if (!LoadZones()) - return false; - - const auto result = UnlinkZones(); + UnlinkerArgs m_args; + SearchPaths m_search_paths; + std::unique_ptr m_last_zone_search_path; + std::set m_absolute_search_paths; - UnloadZones(); - return result; - } + std::vector> m_loaded_zones; }; Unlinker::Unlinker() diff --git a/src/Unlinker/UnlinkerArgs.cpp b/src/Unlinker/UnlinkerArgs.cpp index 43aac8f72..ddefb61e0 100644 --- a/src/Unlinker/UnlinkerArgs.cpp +++ b/src/Unlinker/UnlinkerArgs.cpp @@ -7,6 +7,7 @@ #include "Utils/FileUtils.h" #include "Utils/StringUtils.h" +#include #include #include #include @@ -150,9 +151,9 @@ UnlinkerArgs::UnlinkerArgs() { } -void UnlinkerArgs::PrintUsage() +void UnlinkerArgs::PrintUsage() const { - UsageInformation usage("Unlinker.exe"); + UsageInformation usage(m_argument_parser.GetExecutableName()); for (const auto* commandLineOption : COMMAND_LINE_OPTIONS) { @@ -167,7 +168,7 @@ void UnlinkerArgs::PrintUsage() void UnlinkerArgs::PrintVersion() { - std::cout << "OpenAssetTools Unlinker " << std::string(GIT_VERSION) << "\n"; + std::cout << std::format("OpenAssetTools Unlinker {}\n", GIT_VERSION); } void UnlinkerArgs::SetVerbose(const bool isVerbose) @@ -264,7 +265,7 @@ void UnlinkerArgs::ParseCommaSeparatedAssetTypeString(const std::string& input) bool UnlinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue) { shouldContinue = true; - if (!m_argument_parser.ParseArguments(argc - 1, &argv[1])) + if (!m_argument_parser.ParseArguments(argc, argv)) { PrintUsage(); return false; diff --git a/src/Unlinker/UnlinkerArgs.h b/src/Unlinker/UnlinkerArgs.h index 358725661..9e2867e2d 100644 --- a/src/Unlinker/UnlinkerArgs.h +++ b/src/Unlinker/UnlinkerArgs.h @@ -20,7 +20,7 @@ class UnlinkerArgs /** * \brief Prints a command line usage help text for the Unlinker tool to stdout. */ - static void PrintUsage(); + void PrintUsage() const; static void PrintVersion(); void SetVerbose(bool isVerbose); diff --git a/src/Utils/Utils/Arguments/ArgumentParser.cpp b/src/Utils/Utils/Arguments/ArgumentParser.cpp index 9625fd343..1f89a5edd 100644 --- a/src/Utils/Utils/Arguments/ArgumentParser.cpp +++ b/src/Utils/Utils/Arguments/ArgumentParser.cpp @@ -1,9 +1,17 @@ #include "ArgumentParser.h" +#include "Utils/StringUtils.h" + +#include +#include +#include #include +#include + +namespace fs = std::filesystem; -const std::string PREFIX_LONG = "--"; -const std::string PREFIX_SHORT = "-"; +constexpr auto PREFIX_LONG = "--"; +constexpr auto PREFIX_SHORT = "-"; ArgumentParser::ArgumentParser(const CommandLineOption* const* options, const size_t optionCount) { @@ -18,9 +26,7 @@ bool ArgumentParser::ParseArguments(const int argc, const char** argv) std::vector args(argc); for (int arg = 0; arg < argc; arg++) - { args[arg] = argv[arg]; - } return ParseArguments(args); } @@ -30,26 +36,27 @@ bool ArgumentParser::ParseArguments(std::vector& args) m_matched_arguments.clear(); m_matched_options.clear(); - const size_t argCount = args.size(); - for (unsigned argIndex = 0; argIndex < argCount; argIndex++) + if (args.empty()) + return false; + + m_path = args[0]; + + const auto argCount = args.size(); + for (unsigned argIndex = 1u; argIndex < argCount; argIndex++) { - std::string& arg = args[argIndex]; + auto& arg = args[argIndex]; - if (arg.compare(0, PREFIX_SHORT.size(), PREFIX_SHORT) == 0) + if (arg.compare(0, std::char_traits::length(PREFIX_SHORT), PREFIX_SHORT) == 0) { - // Options should be case insensitive. So before comparing we make the argument lower case. - const size_t argStrLen = arg.size(); - for (unsigned argStrIndex = 0; argStrIndex < argStrLen; argStrIndex++) - { - arg[argStrIndex] = tolower(arg[argStrIndex]); - } + // Options should be case-insensitive. So before comparing we make the argument lower case. + utils::MakeStringLowerCase(arg); const CommandLineOption* matchedOption = nullptr; - if (arg.compare(0, PREFIX_LONG.size(), PREFIX_LONG) == 0) + if (arg.compare(0, std::char_traits::length(PREFIX_LONG), PREFIX_LONG) == 0) { - std::string longName = arg.substr(2); + const auto longName = arg.substr(2); - for (auto option : m_command_line_options) + for (const auto& option : m_command_line_options) { if (option->m_long_name == longName) { @@ -60,9 +67,9 @@ bool ArgumentParser::ParseArguments(std::vector& args) } else { - std::string shortName = arg.substr(1); + const auto shortName = arg.substr(1); - for (auto option : m_command_line_options) + for (const auto& option : m_command_line_options) { if (option->m_short_name == shortName) { @@ -74,7 +81,7 @@ bool ArgumentParser::ParseArguments(std::vector& args) if (matchedOption == nullptr) { - printf("Unknown option '%s'.\n", arg.c_str()); + std::cout << std::format("Unknown option '{}'.\n", arg); return false; } @@ -82,7 +89,7 @@ bool ArgumentParser::ParseArguments(std::vector& args) { if (!matchedOption->m_multi_use) { - printf("Option '%s' already specified.\n", arg.c_str()); + std::cout << std::format("Option '{}' already specified.\n", arg); return false; } } @@ -91,21 +98,21 @@ bool ArgumentParser::ParseArguments(std::vector& args) m_matched_options[matchedOption] = std::vector(); } - const size_t parameterCount = matchedOption->m_parameters.size(); + const auto parameterCount = matchedOption->m_parameters.size(); if (argIndex + parameterCount >= argCount) { - printf("Not enough parameters for option '%s'.\n", arg.c_str()); + std::cout << std::format("Not enough parameters for option '{}'.\n", arg); return false; } - std::vector& parameters = m_matched_options[matchedOption]; + auto& parameters = m_matched_options[matchedOption]; for (unsigned parameterIndex = 0; parameterIndex < parameterCount; parameterIndex++) { std::string& param = args[argIndex + parameterIndex + 1]; - if (param.compare(0, PREFIX_SHORT.size(), PREFIX_SHORT) == 0) + if (param.compare(0, std::char_traits::length(PREFIX_SHORT), PREFIX_SHORT) == 0) { - printf("Not enough parameters for option '%s'.\n", arg.c_str()); + std::cout << std::format("Not enough parameters for option '{}'.\n", arg); return false; } @@ -128,18 +135,19 @@ std::vector ArgumentParser::GetArguments() const return m_matched_arguments; } -std::string ArgumentParser::GetValueForOption(const CommandLineOption* option) +std::string ArgumentParser::GetValueForOption(const CommandLineOption* option) const { - if (!IsOptionSpecified(option)) + const auto existingOption = m_matched_options.find(option); + if (existingOption == m_matched_options.end()) return ""; std::stringstream value; bool firstMatch = true; - for (const auto& match : m_matched_options[option]) + for (const auto& match : existingOption->second) { if (!firstMatch) { - value << " " << match; + value << ' ' << match; } else { @@ -151,15 +159,21 @@ std::string ArgumentParser::GetValueForOption(const CommandLineOption* option) return value.str(); } -std::vector ArgumentParser::GetParametersForOption(const CommandLineOption* option) +std::vector ArgumentParser::GetParametersForOption(const CommandLineOption* option) const { - if (!IsOptionSpecified(option)) + const auto existingOption = m_matched_options.find(option); + if (existingOption == m_matched_options.end()) return std::vector(); - return m_matched_options[option]; + return existingOption->second; } -bool ArgumentParser::IsOptionSpecified(const CommandLineOption* option) +bool ArgumentParser::IsOptionSpecified(const CommandLineOption* option) const { return m_matched_options.find(option) != m_matched_options.end(); } + +std::string ArgumentParser::GetExecutableName() const +{ + return fs::path(m_path).filename().string(); +} diff --git a/src/Utils/Utils/Arguments/ArgumentParser.h b/src/Utils/Utils/Arguments/ArgumentParser.h index 1983d2f21..c43269f67 100644 --- a/src/Utils/Utils/Arguments/ArgumentParser.h +++ b/src/Utils/Utils/Arguments/ArgumentParser.h @@ -7,19 +7,23 @@ class ArgumentParser { - std::vector m_command_line_options; - std::map> m_matched_options; - std::vector m_matched_arguments; - public: ArgumentParser(const CommandLineOption* const* options, size_t optionCount); bool ParseArguments(std::vector& args); bool ParseArguments(int argc, const char** argv); - std::vector GetArguments() const; + [[nodiscard]] std::vector GetArguments() const; + + bool IsOptionSpecified(const CommandLineOption* option) const; + std::string GetValueForOption(const CommandLineOption* option) const; + std::vector GetParametersForOption(const CommandLineOption* option) const; - bool IsOptionSpecified(const CommandLineOption* option); - std::string GetValueForOption(const CommandLineOption* option); - std::vector GetParametersForOption(const CommandLineOption* option); + [[nodiscard]] std::string GetExecutableName() const; + +private: + std::vector m_command_line_options; + std::map> m_matched_options; + std::vector m_matched_arguments; + std::string m_path; }; diff --git a/src/ZoneCode/Game/Common.h b/src/ZoneCode/Game/Common.h index b9f554e62..3e10c6f82 100644 --- a/src/ZoneCode/Game/Common.h +++ b/src/ZoneCode/Game/Common.h @@ -44,9 +44,6 @@ typedef void ID3D11VertexShader; typedef void ID3D11InputLayout; typedef void ID3D11Buffer; -// OAT Types -typedef void Texture; - // Unimportant cpp keywords #define __unaligned #define volatile diff --git a/src/ZoneCode/Game/IW3/XAssets/GfxImage.txt b/src/ZoneCode/Game/IW3/XAssets/GfxImage.txt index 38e3bec46..900e9ea3c 100644 --- a/src/ZoneCode/Game/IW3/XAssets/GfxImage.txt +++ b/src/ZoneCode/Game/IW3/XAssets/GfxImage.txt @@ -14,7 +14,6 @@ reorder: use GfxTexture; set reusable loadDef; set block loadDef XFILE_BLOCK_TEMP; -set condition texture never; // GfxImageLoadDef use GfxImageLoadDef; diff --git a/src/ZoneCode/Game/IW4/XAssets/GfxImage.txt b/src/ZoneCode/Game/IW4/XAssets/GfxImage.txt index 38e3bec46..900e9ea3c 100644 --- a/src/ZoneCode/Game/IW4/XAssets/GfxImage.txt +++ b/src/ZoneCode/Game/IW4/XAssets/GfxImage.txt @@ -14,7 +14,6 @@ reorder: use GfxTexture; set reusable loadDef; set block loadDef XFILE_BLOCK_TEMP; -set condition texture never; // GfxImageLoadDef use GfxImageLoadDef; diff --git a/src/ZoneCode/Game/IW5/XAssets/GfxImage.txt b/src/ZoneCode/Game/IW5/XAssets/GfxImage.txt index 38e3bec46..900e9ea3c 100644 --- a/src/ZoneCode/Game/IW5/XAssets/GfxImage.txt +++ b/src/ZoneCode/Game/IW5/XAssets/GfxImage.txt @@ -14,7 +14,6 @@ reorder: use GfxTexture; set reusable loadDef; set block loadDef XFILE_BLOCK_TEMP; -set condition texture never; // GfxImageLoadDef use GfxImageLoadDef; diff --git a/src/ZoneCode/Game/T5/XAssets/GfxImage.txt b/src/ZoneCode/Game/T5/XAssets/GfxImage.txt index 2a43500ad..5a7260e1d 100644 --- a/src/ZoneCode/Game/T5/XAssets/GfxImage.txt +++ b/src/ZoneCode/Game/T5/XAssets/GfxImage.txt @@ -15,7 +15,6 @@ reorder: use GfxTexture; set reusable loadDef; set block loadDef XFILE_BLOCK_TEMP; -set condition texture never; // GfxImageLoadDef use GfxImageLoadDef; diff --git a/src/ZoneCode/Game/T6/XAssets/GfxImage.txt b/src/ZoneCode/Game/T6/XAssets/GfxImage.txt index 63446ba42..0fd5ede54 100644 --- a/src/ZoneCode/Game/T6/XAssets/GfxImage.txt +++ b/src/ZoneCode/Game/T6/XAssets/GfxImage.txt @@ -16,7 +16,6 @@ use GfxTexture; set reusable loadDef; set block loadDef XFILE_BLOCK_TEMP; set condition basemap never; -set condition texture never; // GfxImageLoadDef use GfxImageLoadDef; diff --git a/src/ZoneCodeGeneratorLib/ZoneCodeGeneratorArguments.cpp b/src/ZoneCodeGeneratorLib/ZoneCodeGeneratorArguments.cpp index 7be657fe6..bd19c4fa8 100644 --- a/src/ZoneCodeGeneratorLib/ZoneCodeGeneratorArguments.cpp +++ b/src/ZoneCodeGeneratorLib/ZoneCodeGeneratorArguments.cpp @@ -4,74 +4,83 @@ #include "Utils/Arguments/CommandLineOption.h" #include "Utils/Arguments/UsageInformation.h" +#include #include #include +// clang-format off const CommandLineOption* const OPTION_HELP = - CommandLineOption::Builder::Create().WithShortName("?").WithLongName("help").WithDescription("Displays usage information.").Build(); + CommandLineOption::Builder::Create() + .WithShortName("?") + .WithLongName("help") + .WithDescription("Displays usage information.") + .Build(); const CommandLineOption* const OPTION_VERSION = - CommandLineOption::Builder::Create().WithLongName("version").WithDescription("Prints the application version.").Build(); + CommandLineOption::Builder::Create() + .WithLongName("version") + .WithDescription("Prints the application version.") + .Build(); const CommandLineOption* const OPTION_VERBOSE = - CommandLineOption::Builder::Create().WithShortName("v").WithLongName("verbose").WithDescription("Outputs a lot more and more detailed messages.").Build(); - -// ------ -// INPUT -// ------ - -constexpr const char* CATEGORY_INPUT = "Input"; - -const CommandLineOption* const OPTION_HEADER = CommandLineOption::Builder::Create() - .WithShortName("h") - .WithLongName("header") - .WithDescription("Reads from the specified header file.") - .WithCategory(CATEGORY_INPUT) - .WithParameter("headerFile") - .Reusable() - .Build(); - -const CommandLineOption* const OPTION_COMMANDS_FILE = CommandLineOption::Builder::Create() - .WithShortName("c") - .WithLongName("commands-file") - .WithDescription("Specifies the commands file. Defaults to stdin.") - .WithCategory(CATEGORY_INPUT) - .WithParameter("commandFile") - .Reusable() - .Build(); - -// ------ -// OUTPUT -// ------ -constexpr const char* CATEGORY_OUTPUT = "Output"; + CommandLineOption::Builder::Create() + .WithShortName("v") + .WithLongName("verbose") + .WithDescription("Outputs a lot more and more detailed messages.") + .Build(); + +constexpr auto CATEGORY_INPUT = "Input"; + +const CommandLineOption* const OPTION_HEADER = + CommandLineOption::Builder::Create() + .WithShortName("h") + .WithLongName("header") + .WithDescription("Reads from the specified header file.") + .WithCategory(CATEGORY_INPUT) + .WithParameter("headerFile") + .Reusable() + .Build(); + +const CommandLineOption* const OPTION_COMMANDS_FILE = + CommandLineOption::Builder::Create() + .WithShortName("c") + .WithLongName("commands-file") + .WithDescription("Specifies the commands file. Defaults to stdin.") + .WithCategory(CATEGORY_INPUT) + .WithParameter("commandFile") + .Reusable() + .Build(); + +constexpr auto CATEGORY_OUTPUT = "Output"; const CommandLineOption* const OPTION_OUTPUT_FOLDER = CommandLineOption::Builder::Create() - .WithShortName("o") - .WithLongName("output") - .WithDescription("Specify the folder to save the generate code files to. Defaults to the current directory.") - .WithCategory(CATEGORY_OUTPUT) - .WithParameter("outputPath") - .Build(); - -const CommandLineOption* const OPTION_PRINT = CommandLineOption::Builder::Create() - .WithShortName("p") - .WithLongName("print") - .WithDescription("Print the loaded data.") - .WithCategory(CATEGORY_OUTPUT) - .Build(); + .WithShortName("o") + .WithLongName("output") + .WithDescription("Specify the folder to save the generate code files to. Defaults to the current directory.") + .WithCategory(CATEGORY_OUTPUT) + .WithParameter("outputPath") + .Build(); + +const CommandLineOption* const OPTION_PRINT = + CommandLineOption::Builder::Create() + .WithShortName("p") + .WithLongName("print") + .WithDescription("Print the loaded data.") + .WithCategory(CATEGORY_OUTPUT) + .Build(); const CommandLineOption* const OPTION_GENERATE = CommandLineOption::Builder::Create() - .WithShortName("g") - .WithLongName("generate") - .WithDescription("Generates a specified asset/preset combination. Can be used multiple times. Available presets: " - "ZoneLoad, ZoneWrite, AssetStructTests") - .WithCategory(CATEGORY_OUTPUT) - .WithParameter("assetName") - .WithParameter("preset") - .Reusable() - .Build(); + .WithShortName("g") + .WithLongName("generate") + .WithDescription("Generates a specified asset/preset combination. Can be used multiple times. Available presets: ZoneLoad, ZoneWrite, AssetStructTests") + .WithCategory(CATEGORY_OUTPUT) + .WithParameter("assetName") + .WithParameter("preset") + .Reusable() + .Build(); +// clang-format on const CommandLineOption* const COMMAND_LINE_OPTIONS[]{ OPTION_HELP, @@ -109,9 +118,9 @@ ZoneCodeGeneratorArguments::ZoneCodeGeneratorArguments() m_verbose = false; } -void ZoneCodeGeneratorArguments::PrintUsage() +void ZoneCodeGeneratorArguments::PrintUsage() const { - UsageInformation usage("ZoneCodeGenerator.exe"); + UsageInformation usage(m_argument_parser.GetExecutableName()); for (const auto* commandLineOption : COMMAND_LINE_OPTIONS) { @@ -123,13 +132,13 @@ void ZoneCodeGeneratorArguments::PrintUsage() void ZoneCodeGeneratorArguments::PrintVersion() { - std::cout << "OpenAssetTools ZoneCodeGenerator " << std::string(GIT_VERSION) << "\n"; + std::cout << std::format("OpenAssetTools ZoneCodeGenerator {}\n", GIT_VERSION); } bool ZoneCodeGeneratorArguments::ParseArgs(const int argc, const char** argv, bool& shouldContinue) { shouldContinue = true; - if (!m_argument_parser.ParseArguments(argc - 1, &argv[1])) + if (!m_argument_parser.ParseArguments(argc, argv)) { PrintUsage(); return false; diff --git a/src/ZoneCodeGeneratorLib/ZoneCodeGeneratorArguments.h b/src/ZoneCodeGeneratorLib/ZoneCodeGeneratorArguments.h index 351efc2e3..4a9238fe8 100644 --- a/src/ZoneCodeGeneratorLib/ZoneCodeGeneratorArguments.h +++ b/src/ZoneCodeGeneratorLib/ZoneCodeGeneratorArguments.h @@ -12,7 +12,7 @@ class ZoneCodeGeneratorArguments /** * \brief Prints a command line usage help text for the Unlinker tool to stdout. */ - static void PrintUsage(); + void PrintUsage() const; static void PrintVersion(); public: diff --git a/test/ObjCommonTests.lua b/test/ObjCommonTests.lua index 18dc9201c..a1360e05d 100644 --- a/test/ObjCommonTests.lua +++ b/test/ObjCommonTests.lua @@ -45,9 +45,11 @@ function ObjCommonTests:project() self:include(includes) ObjCommon:include(includes) + ObjImage:include(includes) catch2:include(includes) links:linkto(ObjCommon) + links:linkto(ObjImage) links:linkto(catch2) links:linkall() end diff --git a/test/ObjLoadingTests/Game/IW3/AssetLoaders/AssetLoaderStringTableTest.cpp b/test/ObjLoadingTests/Game/IW3/AssetLoaders/AssetLoaderStringTableTest.cpp index 1663dc9f9..339d28712 100644 --- a/test/ObjLoadingTests/Game/IW3/AssetLoaders/AssetLoaderStringTableTest.cpp +++ b/test/ObjLoadingTests/Game/IW3/AssetLoaders/AssetLoaderStringTableTest.cpp @@ -21,7 +21,7 @@ namespace "lorem,ipsum"); Zone zone("MockZone", 0, &g_GameIW3); - MockAssetLoadingManager assetLoadingManager(&zone, &searchPath); + MockAssetLoadingManager assetLoadingManager(zone, searchPath); AssetLoaderStringTable assetLoader; MemoryManager memory; diff --git a/test/ObjLoadingTests/Game/IW4/AssetLoaders/AssetLoaderStringTableTest.cpp b/test/ObjLoadingTests/Game/IW4/AssetLoaders/AssetLoaderStringTableTest.cpp index 47c1cff40..5feb8ae01 100644 --- a/test/ObjLoadingTests/Game/IW4/AssetLoaders/AssetLoaderStringTableTest.cpp +++ b/test/ObjLoadingTests/Game/IW4/AssetLoaders/AssetLoaderStringTableTest.cpp @@ -22,7 +22,7 @@ namespace "lorem,ipsum"); Zone zone("MockZone", 0, &g_GameIW4); - MockAssetLoadingManager assetLoadingManager(&zone, &searchPath); + MockAssetLoadingManager assetLoadingManager(zone, searchPath); AssetLoaderStringTable assetLoader; MemoryManager memory; diff --git a/test/ObjLoadingTests/Game/IW4/Menu/MenuParsingIW4IT.cpp b/test/ObjLoadingTests/Game/IW4/Menu/MenuParsingIW4IT.cpp index f9b1f4c71..da44d544b 100644 --- a/test/ObjLoadingTests/Game/IW4/Menu/MenuParsingIW4IT.cpp +++ b/test/ObjLoadingTests/Game/IW4/Menu/MenuParsingIW4IT.cpp @@ -29,7 +29,7 @@ namespace test::game::iw4::menu::parsing::it public: MenuParsingItHelper() : m_zone("MockZone", 0, &g_GameIW4), - m_manager(&m_zone, &m_search_path) + m_manager(m_zone, m_search_path) { } diff --git a/test/ObjLoadingTests/Game/IW5/AssetLoaders/AssetLoaderStringTableTest.cpp b/test/ObjLoadingTests/Game/IW5/AssetLoaders/AssetLoaderStringTableTest.cpp index 2dc8f1377..d921b6fe2 100644 --- a/test/ObjLoadingTests/Game/IW5/AssetLoaders/AssetLoaderStringTableTest.cpp +++ b/test/ObjLoadingTests/Game/IW5/AssetLoaders/AssetLoaderStringTableTest.cpp @@ -21,7 +21,7 @@ namespace "lorem,ipsum"); Zone zone("MockZone", 0, &g_GameIW5); - MockAssetLoadingManager assetLoadingManager(&zone, &searchPath); + MockAssetLoadingManager assetLoadingManager(zone, searchPath); AssetLoaderStringTable assetLoader; MemoryManager memory; diff --git a/test/ObjLoadingTests/Game/T5/AssetLoaders/AssetLoaderStringTableTest.cpp b/test/ObjLoadingTests/Game/T5/AssetLoaders/AssetLoaderStringTableTest.cpp index 3a439fd59..0b8b83fe2 100644 --- a/test/ObjLoadingTests/Game/T5/AssetLoaders/AssetLoaderStringTableTest.cpp +++ b/test/ObjLoadingTests/Game/T5/AssetLoaders/AssetLoaderStringTableTest.cpp @@ -21,7 +21,7 @@ namespace "lorem,ipsum"); Zone zone("MockZone", 0, &g_GameT5); - MockAssetLoadingManager assetLoadingManager(&zone, &searchPath); + MockAssetLoadingManager assetLoadingManager(zone, searchPath); AssetLoaderStringTable assetLoader; MemoryManager memory; diff --git a/test/ObjLoadingTests/Game/T6/AssetLoaders/AssetLoaderStringTableTest.cpp b/test/ObjLoadingTests/Game/T6/AssetLoaders/AssetLoaderStringTableTest.cpp index 4ca2edb03..7c4a34611 100644 --- a/test/ObjLoadingTests/Game/T6/AssetLoaders/AssetLoaderStringTableTest.cpp +++ b/test/ObjLoadingTests/Game/T6/AssetLoaders/AssetLoaderStringTableTest.cpp @@ -21,7 +21,7 @@ namespace "lorem,ipsum"); Zone zone("MockZone", 0, &g_GameT6); - MockAssetLoadingManager assetLoadingManager(&zone, &searchPath); + MockAssetLoadingManager assetLoadingManager(zone, searchPath); AssetLoaderStringTable assetLoader; MemoryManager memory; diff --git a/test/ObjLoadingTests/Mock/MockAssetLoadingManager.cpp b/test/ObjLoadingTests/Mock/MockAssetLoadingManager.cpp index 2934ea27f..ee02a702c 100644 --- a/test/ObjLoadingTests/Mock/MockAssetLoadingManager.cpp +++ b/test/ObjLoadingTests/Mock/MockAssetLoadingManager.cpp @@ -1,6 +1,6 @@ #include "MockAssetLoadingManager.h" -MockAssetLoadingManager::MockAssetLoadingManager(Zone* zone, ISearchPath* searchPath) +MockAssetLoadingManager::MockAssetLoadingManager(Zone& zone, ISearchPath& searchPath) : m_zone(zone), m_mock_gdt(std::make_unique()), m_context(std::make_unique(zone, searchPath, std::vector({m_mock_gdt.get()}))) diff --git a/test/ObjLoadingTests/Mock/MockAssetLoadingManager.h b/test/ObjLoadingTests/Mock/MockAssetLoadingManager.h index 5e1121464..197b88cc7 100644 --- a/test/ObjLoadingTests/Mock/MockAssetLoadingManager.h +++ b/test/ObjLoadingTests/Mock/MockAssetLoadingManager.h @@ -7,14 +7,14 @@ class MockAssetLoadingManager final : public IAssetLoadingManager { - Zone* m_zone; + Zone& m_zone; std::unique_ptr m_mock_gdt; std::unique_ptr m_context; std::map> m_added_assets; std::multimap> m_available_dependencies; public: - MockAssetLoadingManager(Zone* zone, ISearchPath* searchPath); + MockAssetLoadingManager(Zone& zone, ISearchPath& searchPath); _NODISCARD AssetLoadingContext* GetAssetLoadingContext() const override; XAssetInfoGeneric* AddAsset(std::unique_ptr xAssetInfo) override;