Merge pull request #272 from Laupetin/feature/iwi-converter

feat: iwi converter tool
This commit is contained in:
Jan 2024-09-27 21:41:47 +02:00 committed by GitHub
commit a8fefbc978
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
139 changed files with 2822 additions and 2451 deletions

View File

@ -112,6 +112,7 @@ group ""
-- ======================== -- ========================
include "src/Common.lua" include "src/Common.lua"
include "src/Crypto.lua" include "src/Crypto.lua"
include "src/ImageConverter.lua"
include "src/Linker.lua" include "src/Linker.lua"
include "src/Parser.lua" include "src/Parser.lua"
include "src/RawTemplater.lua" include "src/RawTemplater.lua"
@ -125,6 +126,7 @@ include "src/ZoneLoading.lua"
include "src/ZoneWriting.lua" include "src/ZoneWriting.lua"
include "src/ZoneCommon.lua" include "src/ZoneCommon.lua"
include "src/ObjCommon.lua" include "src/ObjCommon.lua"
include "src/ObjImage.lua"
include "src/ObjLoading.lua" include "src/ObjLoading.lua"
include "src/ObjWriting.lua" include "src/ObjWriting.lua"
include "tools/scripts/raw.lua" include "tools/scripts/raw.lua"
@ -141,6 +143,7 @@ group "Components"
ZoneLoading:project() ZoneLoading:project()
ZoneWriting:project() ZoneWriting:project()
ObjCommon:project() ObjCommon:project()
ObjImage:project()
ObjLoading:project() ObjLoading:project()
ObjWriting:project() ObjWriting:project()
group "" group ""
@ -155,6 +158,7 @@ group ""
group "Tools" group "Tools"
Linker:project() Linker:project()
Unlinker:project() Unlinker:project()
ImageConverter:project()
group "" group ""
group "Raw" group "Raw"

View File

@ -4,7 +4,6 @@
// #include <d3d9.h> // #include <d3d9.h>
#include "Game/IAsset.h" #include "Game/IAsset.h"
#include "Image/Texture.h"
#include "IW3_Assets.h" #include "IW3_Assets.h"

View File

@ -1326,7 +1326,6 @@ namespace IW3
// void/*IDirect3DTexture9*/* map; // void/*IDirect3DTexture9*/* map;
// void/*IDirect3DVolumeTexture9*/* volmap; // void/*IDirect3DVolumeTexture9*/* volmap;
// void/*IDirect3DCubeTexture9*/* cubemap; // void/*IDirect3DCubeTexture9*/* cubemap;
Texture* texture;
GfxImageLoadDef* loadDef; GfxImageLoadDef* loadDef;
}; };

View File

@ -2,6 +2,8 @@
#include "Utils/Pack.h" #include "Utils/Pack.h"
#include <cctype>
using namespace IW4; using namespace IW4;
int Common::StringTable_HashString(const char* str) int Common::StringTable_HashString(const char* str)

View File

@ -4,7 +4,6 @@
// #include <d3d9.h> // #include <d3d9.h>
#include "Game/IAsset.h" #include "Game/IAsset.h"
#include "Image/Texture.h"
#include "IW4_Assets.h" #include "IW4_Assets.h"

View File

@ -1009,7 +1009,6 @@ namespace IW4
// IDirect3DTexture9* map; // IDirect3DTexture9* map;
// IDirect3DVolumeTexture9* volmap; // IDirect3DVolumeTexture9* volmap;
// IDirect3DCubeTexture9* cubemap; // IDirect3DCubeTexture9* cubemap;
Texture* texture;
GfxImageLoadDef* loadDef; GfxImageLoadDef* loadDef;
}; };

View File

@ -2,6 +2,8 @@
#include "Utils/Pack.h" #include "Utils/Pack.h"
#include <cctype>
using namespace IW5; using namespace IW5;
int Common::StringTable_HashString(const char* str) int Common::StringTable_HashString(const char* str)

View File

@ -4,7 +4,6 @@
// #include <d3d9.h> // #include <d3d9.h>
#include "Game/IAsset.h" #include "Game/IAsset.h"
#include "Image/Texture.h"
#include "IW5_Assets.h" #include "IW5_Assets.h"

View File

@ -1143,9 +1143,6 @@ namespace IW5
// IDirect3DTexture9* map; // IDirect3DTexture9* map;
// IDirect3DVolumeTexture9* volmap; // IDirect3DVolumeTexture9* volmap;
// IDirect3DCubeTexture9* cubemap; // IDirect3DCubeTexture9* cubemap;
#ifndef __ida
Texture* texture;
#endif
GfxImageLoadDef* loadDef; GfxImageLoadDef* loadDef;
}; };

View File

@ -4,7 +4,6 @@
// #include <d3d9.h> // #include <d3d9.h>
#include "Game/IAsset.h" #include "Game/IAsset.h"
#include "Image/Texture.h"
#include "T5_Assets.h" #include "T5_Assets.h"

View File

@ -1024,7 +1024,6 @@ namespace T5
// IDirect3DTexture9* map; // IDirect3DTexture9* map;
// IDirect3DVolumeTexture9* volmap; // IDirect3DVolumeTexture9* volmap;
// IDirect3DCubeTexture9* cubemap; // IDirect3DCubeTexture9* cubemap;
Texture* texture;
GfxImageLoadDef* loadDef; GfxImageLoadDef* loadDef;
}; };

View File

@ -2,62 +2,8 @@
#include "Utils/Pack.h" #include "Utils/Pack.h"
#include <cctype>
using namespace T6; 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]) PackedTexCoords Common::Vec2PackTexCoords(const float (&in)[2])
{ {
return PackedTexCoords{pack32::Vec2PackTexCoordsUV(in)}; return PackedTexCoords{pack32::Vec2PackTexCoordsUV(in)};

View File

@ -2,14 +2,64 @@
#include "T6.h" #include "T6.h"
#include <cctype>
namespace T6 namespace T6
{ {
class Common class Common
{ {
public: public:
static int Com_HashKey(const char* str, int maxLen); static constexpr int Com_HashKey(const char* str, const int maxLen)
static int Com_HashString(const char* str); {
static int Com_HashString(const char* str, int len); 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) static constexpr uint32_t R_HashString(const char* str, uint32_t hash)
{ {

View File

@ -4,7 +4,6 @@
// #include <d3d11.h> // #include <d3d11.h>
#include "Game/IAsset.h" #include "Game/IAsset.h"
#include "Image/Texture.h"
#include "T6_Assets.h" #include "T6_Assets.h"

View File

@ -848,7 +848,6 @@ namespace T6
union GfxTexture union GfxTexture
{ {
void /*ID3D11ShaderResourceView*/* basemap; void /*ID3D11ShaderResourceView*/* basemap;
Texture* texture;
GfxImageLoadDef* loadDef; GfxImageLoadDef* loadDef;
}; };

View File

@ -1,127 +0,0 @@
#pragma once
#include "ImageFormat.h"
#include <cstdint>
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;
};

48
src/ImageConverter.lua Normal file
View File

@ -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

View File

@ -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 <assert.h>
#include <filesystem>
#include <format>
#include <fstream>
#include <iostream>
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<iwi6::IwiWriter>();
break;
case Game::IW4:
case Game::IW5:
m_iwi_writer = std::make_unique<iwi8::IwiWriter>();
break;
case Game::T5:
m_iwi_writer = std::make_unique<iwi13::IwiWriter>();
break;
case Game::T6:
m_iwi_writer = std::make_unique<iwi27::IwiWriter>();
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<IImageWriter> m_iwi_writer;
};
} // namespace image_converter
std::unique_ptr<ImageConverter> ImageConverter::Create()
{
return std::make_unique<image_converter::ImageConverterImpl>();
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <memory>
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<ImageConverter> Create();
};

View File

@ -0,0 +1,149 @@
#include "ImageConverterArgs.h"
#include "GitVersion.h"
#include "Utils/Arguments/UsageInformation.h"
#include <format>
#include <iostream>
#include <type_traits>
// 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<decltype(COMMAND_LINE_OPTIONS)>)
{
}
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;
}

View File

@ -0,0 +1,42 @@
#pragma once
#include "Utils/Arguments/ArgumentParser.h"
#include <cstdint>
#include <string>
#include <vector>
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<std::string> 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;
};

View File

@ -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;
}

View File

@ -79,7 +79,7 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); 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<AssetLoadingContext>(zone.get(), context.m_asset_search_path, CreateGdtList(context)); const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
return nullptr; return nullptr;
@ -92,11 +92,11 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
return nullptr; 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; return nullptr;
} }
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); ObjLoading::FinalizeAssetsForZone(*assetLoadingContext);
return zone; return zone;
} }

View File

@ -78,7 +78,7 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); 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<AssetLoadingContext>(zone.get(), context.m_asset_search_path, CreateGdtList(context)); const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
return nullptr; return nullptr;
@ -91,11 +91,11 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
return nullptr; 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; return nullptr;
} }
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); ObjLoading::FinalizeAssetsForZone(*assetLoadingContext);
return zone; return zone;
} }

View File

@ -78,7 +78,7 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); 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<AssetLoadingContext>(zone.get(), context.m_asset_search_path, CreateGdtList(context)); const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
return nullptr; return nullptr;
@ -91,11 +91,11 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
return nullptr; 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; return nullptr;
} }
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); ObjLoading::FinalizeAssetsForZone(*assetLoadingContext);
return zone; return zone;
} }

View File

@ -79,7 +79,7 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); 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<AssetLoadingContext>(zone.get(), context.m_asset_search_path, CreateGdtList(context)); const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
return nullptr; return nullptr;
@ -92,11 +92,11 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
return nullptr; 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; return nullptr;
} }
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); ObjLoading::FinalizeAssetsForZone(*assetLoadingContext);
return zone; return zone;
} }

View File

@ -128,7 +128,7 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
context.m_ignored_assets.m_entries.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name, assetEntry.m_is_reference); 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<AssetLoadingContext>(zone.get(), context.m_asset_search_path, CreateGdtList(context)); const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(*zone, *context.m_asset_search_path, CreateGdtList(context));
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map)) if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
return nullptr; return nullptr;
@ -143,11 +143,11 @@ std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext&
return nullptr; 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; return nullptr;
} }
ObjLoading::FinalizeAssetsForZone(assetLoadingContext.get()); ObjLoading::FinalizeAssetsForZone(*assetLoadingContext);
return zone; return zone;
} }

View File

@ -7,6 +7,7 @@
#include "Utils/FileUtils.h" #include "Utils/FileUtils.h"
#include <filesystem> #include <filesystem>
#include <format>
#include <iostream> #include <iostream>
#include <regex> #include <regex>
#include <type_traits> #include <type_traits>
@ -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) for (const auto* commandLineOption : COMMAND_LINE_OPTIONS)
{ {
@ -155,7 +156,7 @@ void LinkerArgs::PrintUsage()
void LinkerArgs::PrintVersion() 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) void LinkerArgs::SetBinFolder(const char* argv0)
@ -244,7 +245,7 @@ std::set<std::string> LinkerArgs::GetSearchPathsForProject(const std::set<std::s
bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue) bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContinue)
{ {
shouldContinue = true; shouldContinue = true;
if (!m_argument_parser.ParseArguments(argc - 1, &argv[1])) if (!m_argument_parser.ParseArguments(argc, argv))
{ {
PrintUsage(); PrintUsage();
return false; return false;

View File

@ -59,7 +59,7 @@ private:
/** /**
* \brief Prints a command line usage help text for the Linker tool to stdout. * \brief Prints a command line usage help text for the Linker tool to stdout.
*/ */
static void PrintUsage(); void PrintUsage() const;
static void PrintVersion(); static void PrintVersion();
void SetBinFolder(const char* argv0); void SetBinFolder(const char* argv0);

View File

@ -5,6 +5,7 @@
#include "SearchPath/SearchPathFilesystem.h" #include "SearchPath/SearchPathFilesystem.h"
#include <filesystem> #include <filesystem>
#include <format>
#include <iostream> #include <iostream>
namespace fs = std::filesystem; 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) 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); ObjLoading::LoadIWDsInSearchPath(searchPath);
} }
void LinkerSearchPaths::UnloadSearchPath(ISearchPath* searchPath) const void LinkerSearchPaths::UnloadSearchPath(ISearchPath& searchPath) const
{ {
if (m_args.m_verbose) 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); ObjLoading::UnloadIWDsInSearchPath(searchPath);
@ -45,15 +46,15 @@ SearchPaths LinkerSearchPaths::GetAssetSearchPathsForProject(const std::string&
if (!fs::is_directory(absolutePath)) if (!fs::is_directory(absolutePath))
{ {
if (m_args.m_verbose) 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; continue;
} }
if (m_args.m_verbose) 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<SearchPathFilesystem>(searchPathStr); auto searchPath = std::make_unique<SearchPathFilesystem>(searchPathStr);
LoadSearchPath(searchPath.get()); LoadSearchPath(*searchPath);
searchPathsForProject.IncludeSearchPath(searchPath.get()); searchPathsForProject.IncludeSearchPath(searchPath.get());
m_loaded_project_search_paths.emplace_back(std::move(searchPath)); 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 (!fs::is_directory(absolutePath))
{ {
if (m_args.m_verbose) 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; continue;
} }
if (m_args.m_verbose) 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<SearchPathFilesystem>(searchPathStr)); searchPathsForProject.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathStr));
} }
@ -105,12 +106,12 @@ SearchPaths LinkerSearchPaths::GetSourceSearchPathsForProject(const std::string&
if (!fs::is_directory(absolutePath)) if (!fs::is_directory(absolutePath))
{ {
if (m_args.m_verbose) 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; continue;
} }
if (m_args.m_verbose) 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<SearchPathFilesystem>(searchPathStr)); searchPathsForProject.CommitSearchPath(std::make_unique<SearchPathFilesystem>(searchPathStr));
} }
@ -129,15 +130,15 @@ bool LinkerSearchPaths::BuildProjectIndependentSearchPaths()
if (!fs::is_directory(absolutePath)) if (!fs::is_directory(absolutePath))
{ {
if (m_args.m_verbose) 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; continue;
} }
if (m_args.m_verbose) 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<SearchPathFilesystem>(absolutePath.string()); auto searchPath = std::make_unique<SearchPathFilesystem>(absolutePath.string());
LoadSearchPath(searchPath.get()); LoadSearchPath(*searchPath);
m_asset_search_paths.CommitSearchPath(std::move(searchPath)); m_asset_search_paths.CommitSearchPath(std::move(searchPath));
} }
@ -148,12 +149,12 @@ bool LinkerSearchPaths::BuildProjectIndependentSearchPaths()
if (!fs::is_directory(absolutePath)) if (!fs::is_directory(absolutePath))
{ {
if (m_args.m_verbose) 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; continue;
} }
if (m_args.m_verbose) 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<SearchPathFilesystem>(absolutePath.string())); m_gdt_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absolutePath.string()));
} }
@ -165,12 +166,12 @@ bool LinkerSearchPaths::BuildProjectIndependentSearchPaths()
if (!fs::is_directory(absolutePath)) if (!fs::is_directory(absolutePath))
{ {
if (m_args.m_verbose) 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; continue;
} }
if (m_args.m_verbose) 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<SearchPathFilesystem>(absolutePath.string())); m_source_search_paths.CommitSearchPath(std::make_unique<SearchPathFilesystem>(absolutePath.string()));
} }
@ -182,7 +183,7 @@ void LinkerSearchPaths::UnloadProjectSpecificSearchPaths()
{ {
for (const auto& loadedSearchPath : m_loaded_project_search_paths) for (const auto& loadedSearchPath : m_loaded_project_search_paths)
{ {
UnloadSearchPath(loadedSearchPath.get()); UnloadSearchPath(*loadedSearchPath);
} }
m_loaded_project_search_paths.clear(); m_loaded_project_search_paths.clear();

View File

@ -14,13 +14,13 @@ public:
* \brief Loads a search path. * \brief Loads a search path.
* \param searchPath The search path to load. * \param searchPath The search path to load.
*/ */
void LoadSearchPath(ISearchPath* searchPath) const; void LoadSearchPath(ISearchPath& searchPath) const;
/** /**
* \brief Unloads a search path. * \brief Unloads a search path.
* \param searchPath The search path to unload. * \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); SearchPaths GetAssetSearchPathsForProject(const std::string& gameName, const std::string& projectName);

47
src/ObjImage.lua Normal file
View File

@ -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

View File

@ -0,0 +1,271 @@
#include "DdsLoader.h"
#include "Image/DdsTypes.h"
#include "Utils/ClassUtils.h"
#include "Utils/FileUtils.h"
#include <format>
#include <iostream>
#include <memory>
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<char*>(&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<char*>(&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<unsigned>(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<unsigned>(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<const ImageFormatUnsigned*>(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<char*>(&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<Texture> ReadTextureData() const
{
std::unique_ptr<Texture> result;
switch (m_texture_type)
{
case TextureType::T_2D:
result = std::make_unique<Texture2D>(m_format, m_width, m_height, m_has_mip_maps);
break;
case TextureType::T_3D:
result = std::make_unique<Texture3D>(m_format, m_width, m_height, m_depth, m_has_mip_maps);
break;
case TextureType::T_CUBE:
result = std::make_unique<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<char*>(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<Texture> LoadDds()
{
if (!ReadMagic() || !ReadHeader())
return nullptr;
return ReadTextureData();
}
};
std::unique_ptr<Texture> LoadDds(std::istream& stream)
{
DdsLoaderInternal internal(stream);
return internal.LoadDds();
}
} // namespace dds

View File

@ -0,0 +1,11 @@
#pragma once
#include "Image/Texture.h"
#include <istream>
#include <memory>
namespace dds
{
std::unique_ptr<Texture> LoadDds(std::istream& stream);
}

View File

@ -13,10 +13,51 @@ const std::map<ImageFormatId, ImageFormatId> DDS_CONVERSION_TABLE{
class DdsWriterInternal class DdsWriterInternal
{ {
std::ostream& m_stream; public:
Texture* m_texture; static bool SupportsImageFormat(const ImageFormat* imageFormat)
std::unique_ptr<Texture> m_converted_texture; {
bool m_use_dx10_extension; 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<const char*>(&magic), sizeof(magic));
m_stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
if (m_use_dx10_extension)
{
DDS_HEADER_DXT10 dxt10{};
PopulateDxt10Header(dxt10);
m_stream.write(reinterpret_cast<const char*>(&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<const char*>(buffer), mipLevelSize);
}
}
static constexpr unsigned Mask1(const unsigned length) static constexpr unsigned Mask1(const unsigned length)
{ {
@ -164,61 +205,20 @@ class DdsWriterInternal
void ConvertTextureIfNecessary() 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()) if (entry != DDS_CONVERSION_TABLE.end())
{ {
TextureConverter converter(m_texture, ImageFormat::ALL_FORMATS[static_cast<unsigned>(entry->second)]); TextureConverter converter(m_texture, ImageFormat::ALL_FORMATS[static_cast<unsigned>(entry->second)]);
m_converted_texture = std::unique_ptr<Texture>(converter.Convert()); m_converted_texture = converter.Convert();
m_texture = m_converted_texture.get(); m_texture = m_converted_texture.get();
} }
} }
public: std::ostream& m_stream;
static bool SupportsImageFormat(const ImageFormat* imageFormat) const Texture* m_texture;
{ std::unique_ptr<Texture> m_converted_texture;
return true; bool m_use_dx10_extension;
}
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<const char*>(&magic), sizeof(magic));
m_stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
if (m_use_dx10_extension)
{
DDS_HEADER_DXT10 dxt10{};
PopulateDxt10Header(dxt10);
m_stream.write(reinterpret_cast<const char*>(&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<const char*>(buffer), mipLevelSize);
}
}
}; };
DdsWriter::~DdsWriter() = default; DdsWriter::~DdsWriter() = default;
@ -233,7 +233,7 @@ std::string DdsWriter::GetFileExtension()
return DdsWriterInternal::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); DdsWriterInternal internal(stream, texture);
internal.DumpImage(); internal.DumpImage();

View File

@ -8,5 +8,5 @@ public:
bool SupportsImageFormat(const ImageFormat* imageFormat) override; bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override; std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, Texture* texture) override; void DumpImage(std::ostream& stream, const Texture* texture) override;
}; };

View File

@ -2,9 +2,8 @@
#include <cstring> #include <cstring>
Dx12TextureLoader::Dx12TextureLoader(MemoryManager* memoryManager) Dx12TextureLoader::Dx12TextureLoader()
: m_memory_manager(memoryManager), : m_format(oat::DXGI_FORMAT_UNKNOWN),
m_format(oat::DXGI_FORMAT_UNKNOWN),
m_type(TextureType::T_2D), m_type(TextureType::T_2D),
m_has_mip_maps(false), m_has_mip_maps(false),
m_width(1u), m_width(1u),
@ -60,26 +59,26 @@ Dx12TextureLoader& Dx12TextureLoader::Depth(const size_t depth)
return *this; return *this;
} }
Texture* Dx12TextureLoader::LoadTexture(const void* data) std::unique_ptr<Texture> Dx12TextureLoader::LoadTexture(const void* data)
{ {
const auto* format = GetFormatForDx12Format(); const auto* format = GetFormatForDx12Format();
if (format == nullptr) if (format == nullptr)
return nullptr; return nullptr;
Texture* texture; std::unique_ptr<Texture> texture;
switch (m_type) switch (m_type)
{ {
case TextureType::T_2D: case TextureType::T_2D:
texture = m_memory_manager->Create<Texture2D>(format, m_width, m_height, m_has_mip_maps); texture = std::make_unique<Texture2D>(format, m_width, m_height, m_has_mip_maps);
break; break;
case TextureType::T_3D: case TextureType::T_3D:
texture = m_memory_manager->Create<Texture3D>(format, m_width, m_height, m_depth, m_has_mip_maps); texture = std::make_unique<Texture3D>(format, m_width, m_height, m_depth, m_has_mip_maps);
break; break;
case TextureType::T_CUBE: case TextureType::T_CUBE:
texture = m_memory_manager->Create<TextureCube>(format, m_width, m_width, m_has_mip_maps); texture = std::make_unique<TextureCube>(format, m_width, m_width, m_has_mip_maps);
break; break;
default: default:

View File

@ -5,24 +5,13 @@
#include "Utils/ClassUtils.h" #include "Utils/ClassUtils.h"
#include "Utils/MemoryManager.h" #include "Utils/MemoryManager.h"
#include <memory>
#include <unordered_map> #include <unordered_map>
class Dx12TextureLoader class Dx12TextureLoader
{ {
static std::unordered_map<ImageFormatId, ImageFormatId> 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: public:
explicit Dx12TextureLoader(MemoryManager* memoryManager); Dx12TextureLoader();
Dx12TextureLoader& Format(oat::DXGI_FORMAT format); Dx12TextureLoader& Format(oat::DXGI_FORMAT format);
Dx12TextureLoader& Type(TextureType textureType); Dx12TextureLoader& Type(TextureType textureType);
@ -31,5 +20,17 @@ public:
Dx12TextureLoader& Height(size_t height); Dx12TextureLoader& Height(size_t height);
Dx12TextureLoader& Depth(size_t depth); Dx12TextureLoader& Depth(size_t depth);
Texture* LoadTexture(const void* data); std::unique_ptr<Texture> LoadTexture(const void* data);
private:
_NODISCARD const ImageFormat* GetFormatForDx12Format() const;
static std::unordered_map<ImageFormatId, ImageFormatId> 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;
}; };

View File

@ -2,9 +2,8 @@
#include <cstring> #include <cstring>
Dx9TextureLoader::Dx9TextureLoader(MemoryManager* memoryManager) Dx9TextureLoader::Dx9TextureLoader()
: m_memory_manager(memoryManager), : m_format(oat::D3DFMT_UNKNOWN),
m_format(oat::D3DFMT_UNKNOWN),
m_type(TextureType::T_2D), m_type(TextureType::T_2D),
m_has_mip_maps(false), m_has_mip_maps(false),
m_width(1u), m_width(1u),
@ -15,7 +14,7 @@ Dx9TextureLoader::Dx9TextureLoader(MemoryManager* memoryManager)
const ImageFormat* Dx9TextureLoader::GetFormatForDx9Format() const const ImageFormat* Dx9TextureLoader::GetFormatForDx9Format() const
{ {
for (auto i : ImageFormat::ALL_FORMATS) for (const auto* i : ImageFormat::ALL_FORMATS)
{ {
if (i->GetD3DFormat() == m_format) if (i->GetD3DFormat() == m_format)
return i; return i;
@ -60,26 +59,26 @@ Dx9TextureLoader& Dx9TextureLoader::Depth(const size_t depth)
return *this; return *this;
} }
Texture* Dx9TextureLoader::LoadTexture(const void* data) std::unique_ptr<Texture> Dx9TextureLoader::LoadTexture(const void* data)
{ {
const auto* format = GetFormatForDx9Format(); const auto* format = GetFormatForDx9Format();
if (format == nullptr) if (format == nullptr)
return nullptr; return nullptr;
Texture* texture; std::unique_ptr<Texture> texture;
switch (m_type) switch (m_type)
{ {
case TextureType::T_2D: case TextureType::T_2D:
texture = m_memory_manager->Create<Texture2D>(format, m_width, m_height, m_has_mip_maps); texture = std::make_unique<Texture2D>(format, m_width, m_height, m_has_mip_maps);
break; break;
case TextureType::T_3D: case TextureType::T_3D:
texture = m_memory_manager->Create<Texture3D>(format, m_width, m_height, m_depth, m_has_mip_maps); texture = std::make_unique<Texture3D>(format, m_width, m_height, m_depth, m_has_mip_maps);
break; break;
case TextureType::T_CUBE: case TextureType::T_CUBE:
texture = m_memory_manager->Create<TextureCube>(format, m_width, m_width, m_has_mip_maps); texture = std::make_unique<TextureCube>(format, m_width, m_width, m_has_mip_maps);
break; break;
default: default:

View File

@ -5,22 +5,13 @@
#include "Utils/ClassUtils.h" #include "Utils/ClassUtils.h"
#include "Utils/MemoryManager.h" #include "Utils/MemoryManager.h"
#include <memory>
#include <unordered_map> #include <unordered_map>
class Dx9TextureLoader 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: public:
explicit Dx9TextureLoader(MemoryManager* memoryManager); Dx9TextureLoader();
Dx9TextureLoader& Format(oat::D3DFORMAT format); Dx9TextureLoader& Format(oat::D3DFORMAT format);
Dx9TextureLoader& Type(TextureType textureType); Dx9TextureLoader& Type(TextureType textureType);
@ -29,5 +20,15 @@ public:
Dx9TextureLoader& Height(size_t height); Dx9TextureLoader& Height(size_t height);
Dx9TextureLoader& Depth(size_t depth); Dx9TextureLoader& Depth(size_t depth);
Texture* LoadTexture(const void* data); std::unique_ptr<Texture> 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;
}; };

View File

@ -0,0 +1,21 @@
#pragma once
#include "Image/Texture.h"
#include <ostream>
#include <string>
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;
};

View File

@ -0,0 +1,443 @@
#include "IwiLoader.h"
#include "Image/IwiTypes.h"
#include <cassert>
#include <format>
#include <iostream>
#include <type_traits>
namespace iwi
{
const ImageFormat* GetFormat6(int8_t format)
{
switch (static_cast<iwi6::IwiFormat>(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<Texture> LoadIwi6(std::istream& stream)
{
iwi6::IwiHeader header{};
stream.read(reinterpret_cast<char*>(&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> texture;
if (header.flags & iwi6::IwiFlags::IMG_FLAG_CUBEMAP)
texture = std::make_unique<TextureCube>(format, width, height, hasMipMaps);
else if (header.flags & iwi6::IwiFlags::IMG_FLAG_VOLMAP)
texture = std::make_unique<Texture3D>(format, width, height, depth, hasMipMaps);
else
texture = std::make_unique<Texture2D>(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<int>(std::extent_v<decltype(iwi6::IwiHeader::fileSizeForPicmip)>)
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
std::cerr << std::format("Iwi has invalid file size for picmip {}\n", currentMipLevel);
return nullptr;
}
stream.read(reinterpret_cast<char*>(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<iwi8::IwiFormat>(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<Texture> LoadIwi8(std::istream& stream)
{
iwi8::IwiHeader header{};
stream.read(reinterpret_cast<char*>(&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> texture;
if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_CUBE)
{
texture = std::make_unique<TextureCube>(format, width, height, hasMipMaps);
}
else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_3D)
{
texture = std::make_unique<Texture3D>(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<Texture2D>(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<int>(std::extent_v<decltype(iwi8::IwiHeader::fileSizeForPicmip)>)
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
std::cerr << std::format("Iwi has invalid file size for picmip {}\n", currentMipLevel);
return nullptr;
}
stream.read(reinterpret_cast<char*>(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<iwi13::IwiFormat>(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<Texture> LoadIwi13(std::istream& stream)
{
iwi13::IwiHeader header{};
stream.read(reinterpret_cast<char*>(&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> texture;
if (header.flags & iwi13::IwiFlags::IMG_FLAG_CUBEMAP)
texture = std::make_unique<TextureCube>(format, width, height, hasMipMaps);
else if (header.flags & iwi13::IwiFlags::IMG_FLAG_VOLMAP)
texture = std::make_unique<Texture3D>(format, width, height, depth, hasMipMaps);
else
texture = std::make_unique<Texture2D>(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<int>(std::extent_v<decltype(iwi13::IwiHeader::fileSizeForPicmip)>)
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
std::cerr << std::format("Iwi has invalid file size for picmip {}\n", currentMipLevel);
return nullptr;
}
stream.read(reinterpret_cast<char*>(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<iwi27::IwiFormat>(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<Texture> LoadIwi27(std::istream& stream)
{
iwi27::IwiHeader header{};
stream.read(reinterpret_cast<char*>(&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> texture;
if (header.flags & iwi27::IwiFlags::IMG_FLAG_CUBEMAP)
texture = std::make_unique<TextureCube>(format, width, height, hasMipMaps);
else if (header.flags & iwi27::IwiFlags::IMG_FLAG_VOLMAP)
texture = std::make_unique<Texture3D>(format, width, height, depth, hasMipMaps);
else
texture = std::make_unique<Texture2D>(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<int>(std::extent_v<decltype(iwi27::IwiHeader::fileSizeForPicmip)>)
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
std::cerr << std::format("Iwi has invalid file size for picmip {}\n", currentMipLevel);
return nullptr;
}
stream.read(reinterpret_cast<char*>(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<Texture> LoadIwi(std::istream& stream)
{
IwiVersion iwiVersion{};
stream.read(reinterpret_cast<char*>(&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

View File

@ -0,0 +1,11 @@
#pragma once
#include "Image/Texture.h"
#include <istream>
#include <memory>
namespace iwi
{
std::unique_ptr<Texture> LoadIwi(std::istream& stream);
}; // namespace iwi

View File

@ -0,0 +1,141 @@
#include "IwiWriter13.h"
#include <cassert>
#include <ostream>
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<char*>(&version), sizeof(IwiVersion));
}
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
{
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header.dimensions[2] = 1;
}
void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
{
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header.dimensions[2] = 1;
header.flags |= IMG_FLAG_CUBEMAP;
}
void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture)
{
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header.dimensions[2] = static_cast<uint16_t>(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<int8_t>(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<int>(std::extent_v<decltype(IwiHeader::fileSizeForPicmip)>))
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
}
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
{
FillHeader2D(header, *texture2D);
}
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
{
FillHeaderCube(header, *textureCube);
}
else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
{
FillHeader3D(header, *texture3D);
}
else
{
assert(false);
return;
}
stream.write(reinterpret_cast<char*>(&header), sizeof(IwiHeader));
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
}
}

View File

@ -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

View File

@ -63,30 +63,30 @@ void IwiWriter::WriteVersion(std::ostream& stream)
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion)); stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
} }
void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture) void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
{ {
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = 1; header.dimensions[2] = 1;
} }
void IwiWriter::FillHeaderCube(IwiHeader* header, TextureCube* texture) void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
{ {
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = 1; header.dimensions[2] = 1;
header->flags |= IMG_FLAG_CUBEMAP; 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<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = static_cast<uint16_t>(texture->GetDepth()); header.dimensions[2] = static_cast<uint16_t>(texture.GetDepth());
header->flags |= IMG_FLAG_VOLMAP; 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); assert(texture != nullptr);
@ -116,17 +116,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
header.fileSizeForPicmip[currentMipLevel] = currentFileSize; header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
} }
if (auto* texture2D = dynamic_cast<Texture2D*>(texture)) if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
{ {
FillHeader2D(&header, texture2D); FillHeader2D(header, *texture2D);
} }
else if (auto* textureCube = dynamic_cast<TextureCube*>(texture)) else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
{ {
FillHeaderCube(&header, textureCube); FillHeaderCube(header, *textureCube);
} }
else if (auto* texture3D = dynamic_cast<Texture3D*>(texture)) else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
{ {
FillHeader3D(&header, texture3D); FillHeader3D(header, *texture3D);
} }
else else
{ {
@ -139,6 +139,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{ {
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
stream.write(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
} }
} }

View File

@ -10,9 +10,9 @@ namespace iwi27
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
static void WriteVersion(std::ostream& stream); static void WriteVersion(std::ostream& stream);
static void FillHeader2D(IwiHeader* header, Texture2D* texture); static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
static void FillHeaderCube(IwiHeader* header, TextureCube* texture); static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
static void FillHeader3D(IwiHeader* header, Texture3D* texture); static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
public: public:
IwiWriter(); IwiWriter();
@ -25,6 +25,6 @@ namespace iwi27
bool SupportsImageFormat(const ImageFormat* imageFormat) override; bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override; std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, Texture* texture) override; void DumpImage(std::ostream& stream, const Texture* texture) override;
}; };
} // namespace iwi27 } // namespace iwi27

View File

@ -49,27 +49,27 @@ void IwiWriter::WriteVersion(std::ostream& stream)
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion)); stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
} }
void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture) void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
{ {
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = 1u; header.dimensions[2] = 1u;
} }
void IwiWriter::FillHeaderCube(IwiHeader* header, TextureCube* texture) void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
{ {
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = 1u; header.dimensions[2] = 1u;
header->flags |= IMG_FLAG_CUBEMAP; 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<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = static_cast<uint16_t>(texture->GetDepth()); header.dimensions[2] = static_cast<uint16_t>(texture.GetDepth());
header->flags |= IMG_FLAG_VOLMAP; header.flags |= IMG_FLAG_VOLMAP;
} }
bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat) bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat)
@ -82,7 +82,7 @@ std::string IwiWriter::GetFileExtension()
return ".iwi"; return ".iwi";
} }
void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
{ {
assert(texture != nullptr); assert(texture != nullptr);
@ -108,17 +108,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
header.fileSizeForPicmip[currentMipLevel] = currentFileSize; header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
} }
if (auto* texture2D = dynamic_cast<Texture2D*>(texture)) if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
{ {
FillHeader2D(&header, texture2D); FillHeader2D(header, *texture2D);
} }
else if (auto* textureCube = dynamic_cast<TextureCube*>(texture)) else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
{ {
FillHeaderCube(&header, textureCube); FillHeaderCube(header, *textureCube);
} }
else if (auto* texture3D = dynamic_cast<Texture3D*>(texture)) else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
{ {
FillHeader3D(&header, texture3D); FillHeader3D(header, *texture3D);
} }
else else
{ {
@ -131,6 +131,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{ {
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
stream.write(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
} }
} }

View File

@ -10,9 +10,9 @@ namespace iwi6
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
static void WriteVersion(std::ostream& stream); static void WriteVersion(std::ostream& stream);
static void FillHeader2D(IwiHeader* header, Texture2D* texture); static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
static void FillHeaderCube(IwiHeader* header, TextureCube* texture); static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
static void FillHeader3D(IwiHeader* header, Texture3D* texture); static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
public: public:
IwiWriter(); IwiWriter();
@ -25,6 +25,6 @@ namespace iwi6
bool SupportsImageFormat(const ImageFormat* imageFormat) override; bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override; std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, Texture* texture) override; void DumpImage(std::ostream& stream, const Texture* texture) override;
}; };
} // namespace iwi6 } // namespace iwi6

View File

@ -49,27 +49,27 @@ void IwiWriter::WriteVersion(std::ostream& stream)
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion)); stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
} }
void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture) void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
{ {
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = 1u; header.dimensions[2] = 1u;
} }
void IwiWriter::FillHeaderCube(IwiHeader* header, TextureCube* texture) void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
{ {
header->dimensions[0] = static_cast<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = 1u; header.dimensions[2] = 1u;
header->flags |= IMG_FLAG_MAPTYPE_CUBE; 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<uint16_t>(texture->GetWidth()); header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
header->dimensions[1] = static_cast<uint16_t>(texture->GetHeight()); header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
header->dimensions[2] = static_cast<uint16_t>(texture->GetDepth()); header.dimensions[2] = static_cast<uint16_t>(texture.GetDepth());
header->flags |= IMG_FLAG_MAPTYPE_3D; header.flags |= IMG_FLAG_MAPTYPE_3D;
} }
bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat) bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat)
@ -82,7 +82,7 @@ std::string IwiWriter::GetFileExtension()
return ".iwi"; return ".iwi";
} }
void IwiWriter::DumpImage(std::ostream& stream, Texture* texture) void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
{ {
assert(texture != nullptr); assert(texture != nullptr);
@ -108,17 +108,17 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
header.fileSizeForPicmip[currentMipLevel] = currentFileSize; header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
} }
if (auto* texture2D = dynamic_cast<Texture2D*>(texture)) if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
{ {
FillHeader2D(&header, texture2D); FillHeader2D(header, *texture2D);
} }
else if (auto* textureCube = dynamic_cast<TextureCube*>(texture)) else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
{ {
FillHeaderCube(&header, textureCube); FillHeaderCube(header, *textureCube);
} }
else if (auto* texture3D = dynamic_cast<Texture3D*>(texture)) else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
{ {
FillHeader3D(&header, texture3D); FillHeader3D(header, *texture3D);
} }
else else
{ {
@ -131,6 +131,6 @@ void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{ {
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
stream.write(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize); stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
} }
} }

View File

@ -10,9 +10,9 @@ namespace iwi8
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
static void WriteVersion(std::ostream& stream); static void WriteVersion(std::ostream& stream);
static void FillHeader2D(IwiHeader* header, Texture2D* texture); static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
static void FillHeaderCube(IwiHeader* header, TextureCube* texture); static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
static void FillHeader3D(IwiHeader* header, Texture3D* texture); static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
public: public:
IwiWriter(); IwiWriter();
@ -25,6 +25,6 @@ namespace iwi8
bool SupportsImageFormat(const ImageFormat* imageFormat) override; bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override; std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, Texture* texture) override; void DumpImage(std::ostream& stream, const Texture* texture) override;
}; };
} // namespace iwi8 } // namespace iwi8

View File

@ -77,6 +77,11 @@ uint8_t* Texture::GetBufferForMipLevel(const int mipLevel)
return GetBufferForMipLevel(mipLevel, 0); return GetBufferForMipLevel(mipLevel, 0);
} }
const uint8_t* Texture::GetBufferForMipLevel(const int mipLevel) const
{
return GetBufferForMipLevel(mipLevel, 0);
}
// ============================================== // ==============================================
// ================ Texture2D =================== // ================ Texture2D ===================
// ============================================== // ==============================================
@ -183,6 +188,31 @@ uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face)
return &m_data[bufferOffset]; 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 ================== // =============== TextureCube ==================
// ============================================== // ==============================================
@ -251,6 +281,32 @@ uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face)
return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * 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 =================== // ================ Texture3D ===================
// ============================================== // ==============================================
@ -360,3 +416,28 @@ uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face)
return &m_data[bufferOffset]; 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];
}

View File

@ -0,0 +1,132 @@
#pragma once
#include "ImageFormat.h"
#include <cstdint>
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;
};

View File

@ -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_input_texture(inputTexture),
m_output_texture(nullptr), m_output_texture(nullptr),
m_input_format(inputTexture->GetFormat()), m_input_format(inputTexture->GetFormat()),
@ -117,15 +117,17 @@ void TextureConverter::CreateOutputTexture()
switch (m_input_texture->GetTextureType()) switch (m_input_texture->GetTextureType())
{ {
case TextureType::T_2D: 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<Texture2D>(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps());
break; break;
case TextureType::T_CUBE: 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<TextureCube>(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps());
break; break;
case TextureType::T_3D: case TextureType::T_3D:
m_output_texture = new Texture3D( m_output_texture = std::make_unique<Texture3D>(
m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->GetDepth(), m_input_texture->HasMipMaps()); m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->GetDepth(), m_input_texture->HasMipMaps());
break; break;
default: default:
@ -202,7 +204,7 @@ void TextureConverter::ConvertUnsignedToUnsigned()
} }
} }
Texture* TextureConverter::Convert() std::unique_ptr<Texture> TextureConverter::Convert()
{ {
CreateOutputTexture(); CreateOutputTexture();
@ -216,5 +218,5 @@ Texture* TextureConverter::Convert()
assert(false); assert(false);
} }
return m_output_texture; return std::move(m_output_texture);
} }

View File

@ -3,17 +3,16 @@
#include "Texture.h" #include "Texture.h"
#include <functional> #include <functional>
#include <memory>
class TextureConverter class TextureConverter
{ {
Texture* m_input_texture; public:
Texture* m_output_texture; TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat);
const ImageFormat* m_input_format;
const ImageFormat* m_output_format;
std::function<uint64_t(const void* offset, unsigned bitCount)> m_read_pixel_func; std::unique_ptr<Texture> Convert();
std::function<void(void* offset, uint64_t pixel, unsigned bitCount)> m_write_pixel_func;
private:
static constexpr uint64_t Mask1(unsigned length); static constexpr uint64_t Mask1(unsigned length);
void SetPixelFunctions(unsigned inBitCount, unsigned outBitCount); void SetPixelFunctions(unsigned inBitCount, unsigned outBitCount);
@ -22,8 +21,11 @@ class TextureConverter
void ReorderUnsignedToUnsigned() const; void ReorderUnsignedToUnsigned() const;
void ConvertUnsignedToUnsigned(); void ConvertUnsignedToUnsigned();
public: std::function<uint64_t(const void* offset, unsigned bitCount)> m_read_pixel_func;
TextureConverter(Texture* inputTexture, const ImageFormat* targetFormat); std::function<void(void* offset, uint64_t pixel, unsigned bitCount)> m_write_pixel_func;
Texture* Convert(); const Texture* m_input_texture;
std::unique_ptr<Texture> m_output_texture;
const ImageFormat* m_input_format;
const ImageFormat* m_output_format;
}; };

View File

@ -3,6 +3,7 @@ ObjLoading = {}
function ObjLoading:include(includes) function ObjLoading:include(includes)
if includes:handle(self:name()) then if includes:handle(self:name()) then
ObjCommon:include(includes) ObjCommon:include(includes)
ObjImage:include(includes)
ZoneCommon:include(includes) ZoneCommon:include(includes)
includedirs { includedirs {
path.join(ProjectFolder(), "ObjLoading") path.join(ProjectFolder(), "ObjLoading")
@ -14,6 +15,7 @@ function ObjLoading:link(links)
links:add(self:name()) links:add(self:name())
links:linkto(Utils) links:linkto(Utils)
links:linkto(ObjCommon) links:linkto(ObjCommon)
links:linkto(ObjImage)
links:linkto(ZoneCommon) links:linkto(ZoneCommon)
links:linkto(minilzo) links:linkto(minilzo)
links:linkto(minizip) links:linkto(minizip)

View File

@ -1,6 +1,6 @@
#include "AssetLoadingContext.h" #include "AssetLoadingContext.h"
AssetLoadingContext::AssetLoadingContext(Zone* zone, ISearchPath* rawSearchPath, std::vector<Gdt*> gdtFiles) AssetLoadingContext::AssetLoadingContext(Zone& zone, ISearchPath& rawSearchPath, std::vector<Gdt*> gdtFiles)
: m_zone(zone), : m_zone(zone),
m_raw_search_path(rawSearchPath), m_raw_search_path(rawSearchPath),
m_gdt_files(std::move(gdtFiles)) m_gdt_files(std::move(gdtFiles))
@ -10,7 +10,7 @@ AssetLoadingContext::AssetLoadingContext(Zone* zone, ISearchPath* rawSearchPath,
void AssetLoadingContext::BuildGdtEntryCache() void AssetLoadingContext::BuildGdtEntryCache()
{ {
for (auto* gdt : m_gdt_files) for (const auto* gdt : m_gdt_files)
{ {
for (const auto& entry : gdt->m_entries) for (const auto& entry : gdt->m_entries)
{ {

View File

@ -12,18 +12,8 @@
class AssetLoadingContext final : public IGdtQueryable class AssetLoadingContext final : public IGdtQueryable
{ {
std::unordered_map<std::string, std::unordered_map<std::string, GdtEntry*>> m_entries_by_gdf_and_by_name;
std::unordered_map<std::type_index, std::unique_ptr<IZoneAssetLoaderState>> m_zone_asset_loader_states;
void BuildGdtEntryCache();
public: public:
Zone* const m_zone; AssetLoadingContext(Zone& zone, ISearchPath& rawSearchPath, std::vector<Gdt*> gdtFiles);
ISearchPath* const m_raw_search_path;
const std::vector<Gdt*> m_gdt_files;
std::unordered_map<std::string, asset_type_t> m_ignored_asset_map;
AssetLoadingContext(Zone* zone, ISearchPath* rawSearchPath, std::vector<Gdt*> gdtFiles);
GdtEntry* GetGdtEntryByGdfAndName(const std::string& gdfName, const std::string& entryName) override; GdtEntry* GetGdtEntryByGdfAndName(const std::string& gdfName, const std::string& entryName) override;
template<typename T> T* GetZoneAssetLoaderState() template<typename T> T* GetZoneAssetLoaderState()
@ -36,9 +26,21 @@ public:
return dynamic_cast<T*>(foundEntry->second.get()); return dynamic_cast<T*>(foundEntry->second.get());
auto newState = std::make_unique<T>(); auto newState = std::make_unique<T>();
newState->SetZone(m_zone); newState->SetZone(&m_zone);
auto* newStatePtr = newState.get(); auto* newStatePtr = newState.get();
m_zone_asset_loader_states.emplace(std::make_pair<std::type_index, std::unique_ptr<IZoneAssetLoaderState>>(typeid(T), std::move(newState))); m_zone_asset_loader_states.emplace(std::make_pair<std::type_index, std::unique_ptr<IZoneAssetLoaderState>>(typeid(T), std::move(newState)));
return newStatePtr; return newStatePtr;
} }
private:
void BuildGdtEntryCache();
public:
Zone& m_zone;
ISearchPath& m_raw_search_path;
const std::vector<Gdt*> m_gdt_files;
std::unordered_map<std::string, asset_type_t> m_ignored_asset_map;
std::unordered_map<std::string, std::unordered_map<std::string, GdtEntry*>> m_entries_by_gdf_and_by_name;
std::unordered_map<std::type_index, std::unique_ptr<IZoneAssetLoaderState>> m_zone_asset_loader_states;
}; };

View File

@ -6,7 +6,8 @@
#include <format> #include <format>
#include <iostream> #include <iostream>
AssetLoadingManager::AssetLoadingManager(const std::map<asset_type_t, std::unique_ptr<IAssetLoader>>& assetLoadersByType, AssetLoadingContext& context) AssetLoadingManager::AssetLoadingManager(const std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>>& assetLoadersByType,
AssetLoadingContext& context)
: m_asset_loaders_by_type(assetLoadersByType), : m_asset_loaders_by_type(assetLoadersByType),
m_context(context), m_context(context),
m_last_dependency_loaded(nullptr) m_last_dependency_loaded(nullptr)
@ -28,26 +29,26 @@ XAssetInfoGeneric* AssetLoadingManager::AddAssetInternal(std::unique_ptr<XAssetI
const auto assetType = xAssetInfo->m_type; const auto assetType = xAssetInfo->m_type;
const auto* pAssetName = xAssetInfo->m_name.c_str(); 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) 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; return m_last_dependency_loaded;
} }
XAssetInfoGeneric* AssetLoadingManager::AddAsset(std::unique_ptr<XAssetInfoGeneric> xAssetInfo) XAssetInfoGeneric* AssetLoadingManager::AddAsset(std::unique_ptr<XAssetInfoGeneric> xAssetInfo)
{ {
xAssetInfo->m_zone = m_context.m_zone; xAssetInfo->m_zone = &m_context.m_zone;
return AddAssetInternal(std::move(xAssetInfo)); return AddAssetInternal(std::move(xAssetInfo));
} }
XAssetInfoGeneric* AssetLoadingManager::LoadIgnoredDependency(const asset_type_t assetType, const std::string& assetName, IAssetLoader* loader) 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) if (alreadyLoadedAsset)
return 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) if (linkAsset)
{ {
AddAsset(std::make_unique<XAssetInfoGeneric>(assetType, assetName, linkAsset)); AddAsset(std::make_unique<XAssetInfoGeneric>(assetType, assetName, linkAsset));
@ -65,21 +66,21 @@ XAssetInfoGeneric* AssetLoadingManager::LoadIgnoredDependency(const asset_type_t
return lastDependency; 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; return nullptr;
} }
XAssetInfoGeneric* AssetLoadingManager::LoadAssetDependency(const asset_type_t assetType, const std::string& assetName, const IAssetLoader* loader) XAssetInfoGeneric* AssetLoadingManager::LoadAssetDependency(const asset_type_t assetType, const std::string& assetName, const IAssetLoader* loader)
{ {
if (loader->CanLoadFromGdt() && !m_context.m_gdt_files.empty() 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; auto* lastDependency = m_last_dependency_loaded;
m_last_dependency_loaded = nullptr; m_last_dependency_loaded = nullptr;
return lastDependency; 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; auto* lastDependency = m_last_dependency_loaded;
m_last_dependency_loaded = nullptr; 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 // 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 // The replacement of the scr_string_t values will be done upon writing
for (const auto scrString : existingAsset->m_used_script_strings) 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<XAssetInfoGeneric>(existingAsset->m_type, AddAssetInternal(std::make_unique<XAssetInfoGeneric>(existingAsset->m_type,
existingAsset->m_name, existingAsset->m_name,
@ -125,13 +126,13 @@ XAssetInfoGeneric* AssetLoadingManager::LoadAssetDependency(const asset_type_t a
return lastDependency; 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; return nullptr;
} }
XAssetInfoGeneric* AssetLoadingManager::LoadDependency(const asset_type_t assetType, const std::string& assetName) 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) if (alreadyLoadedAsset)
return alreadyLoadedAsset; return alreadyLoadedAsset;
@ -149,13 +150,13 @@ XAssetInfoGeneric* AssetLoadingManager::LoadDependency(const asset_type_t assetT
return LoadAssetDependency(assetType, assetName, loader->second.get()); 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; return nullptr;
} }
IndirectAssetReference AssetLoadingManager::LoadIndirectAssetReference(const asset_type_t assetType, const std::string& assetName) 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) if (alreadyLoadedAsset)
return IndirectAssetReference(assetType, assetName); return IndirectAssetReference(assetType, assetName);
@ -170,6 +171,6 @@ IndirectAssetReference AssetLoadingManager::LoadIndirectAssetReference(const ass
return IndirectAssetReference(assetType, assetName); 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); return IndirectAssetReference(assetType, assetName);
} }

View File

@ -4,12 +4,12 @@
#include "IAssetLoader.h" #include "IAssetLoader.h"
#include "IAssetLoadingManager.h" #include "IAssetLoadingManager.h"
#include <map> #include <unordered_map>
class AssetLoadingManager final : public IAssetLoadingManager class AssetLoadingManager final : public IAssetLoadingManager
{ {
public: public:
AssetLoadingManager(const std::map<asset_type_t, std::unique_ptr<IAssetLoader>>& assetLoadersByType, AssetLoadingContext& context); AssetLoadingManager(const std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>>& assetLoadersByType, AssetLoadingContext& context);
bool LoadAssetFromLoader(asset_type_t assetType, const std::string& assetName); bool LoadAssetFromLoader(asset_type_t assetType, const std::string& assetName);
@ -25,7 +25,7 @@ private:
XAssetInfoGeneric* AddAssetInternal(std::unique_ptr<XAssetInfoGeneric> xAssetInfo); XAssetInfoGeneric* AddAssetInternal(std::unique_ptr<XAssetInfoGeneric> xAssetInfo);
const std::map<asset_type_t, std::unique_ptr<IAssetLoader>>& m_asset_loaders_by_type; const std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>>& m_asset_loaders_by_type;
AssetLoadingContext& m_context; AssetLoadingContext& m_context;
XAssetInfoGeneric* m_last_dependency_loaded; XAssetInfoGeneric* m_last_dependency_loaded;
}; };

View File

@ -46,7 +46,7 @@ public:
return false; return false;
} }
virtual void FinalizeAssetsForZone(AssetLoadingContext* context) const virtual void FinalizeAssetsForZone(AssetLoadingContext& context) const
{ {
// Do nothing by default // Do nothing by default
} }

View File

@ -5,7 +5,9 @@
#include "Image/IwiTypes.h" #include "Image/IwiTypes.h"
#include "Pool/GlobalAssetPool.h" #include "Pool/GlobalAssetPool.h"
#include <algorithm>
#include <cstring> #include <cstring>
#include <format>
#include <iostream> #include <iostream>
using namespace IW3; using namespace IW3;
@ -32,29 +34,16 @@ bool AssetLoaderGfxImage::LoadFromRaw(
return false; return false;
std::string safeAssetName = assetName; std::string safeAssetName = assetName;
for (auto& c : safeAssetName) std::ranges::replace(safeAssetName, '*', '_');
{
switch (c)
{
case '*':
c = '_';
break;
default: const auto file = searchPath->Open(std::format("images/{}.dds", safeAssetName));
break;
}
}
const auto file = searchPath->Open("images/" + safeAssetName + ".dds");
if (!file.IsOpen()) if (!file.IsOpen())
return false; return false;
const DdsLoader ddsLoader(zone->GetMemory()); const auto texture = dds::LoadDds(*file.m_stream);
auto* texture = ddsLoader.LoadDds(*file.m_stream); if (!texture)
if (texture == nullptr)
{ {
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; return false;
} }

View File

@ -4,13 +4,7 @@
#include "AssetLoaders/AssetLoaderLocalizeEntry.h" #include "AssetLoaders/AssetLoaderLocalizeEntry.h"
#include "AssetLoaders/AssetLoaderRawFile.h" #include "AssetLoaders/AssetLoaderRawFile.h"
#include "AssetLoading/AssetLoadingManager.h" #include "AssetLoading/AssetLoadingManager.h"
#include "Game/IW3/GameAssetPoolIW3.h"
#include "Game/IW3/GameIW3.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" #include "ObjLoading.h"
using namespace IW3; using namespace IW3;
@ -54,129 +48,32 @@ ObjLoader::ObjLoader()
#undef REGISTER_ASSET_LOADER #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; AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);
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<oat::D3DFORMAT>(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<int>(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<int>(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<GameAssetPoolIW3*>(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);
return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); 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) for (const auto& [type, loader] : m_asset_loaders_by_type)
loader->FinalizeAssetsForZone(context); loader->FinalizeAssetsForZone(context);

View File

@ -1,37 +1,30 @@
#pragma once #pragma once
#include "AssetLoading/IAssetLoader.h" #include "AssetLoading/IAssetLoader.h"
#include "Game/IW3/IW3.h"
#include "IObjLoader.h" #include "IObjLoader.h"
#include "SearchPath/ISearchPath.h" #include "SearchPath/ISearchPath.h"
#include <map>
#include <memory> #include <memory>
#include <unordered_map>
namespace IW3 namespace IW3
{ {
class ObjLoader final : public IObjLoader class ObjLoader final : public IObjLoader
{ {
std::map<asset_type_t, std::unique_ptr<IAssetLoader>> m_asset_loaders_by_type; std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>> m_asset_loaders_by_type;
static void LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone); static bool IsMpZone(const Zone& zone);
static void LoadImageFromLoadDef(GfxImage* image, Zone* zone); static bool IsZmZone(const Zone& zone);
static void LoadImageData(ISearchPath* searchPath, Zone* zone);
static bool IsMpZone(Zone* zone);
static bool IsZmZone(Zone* zone);
public: public:
ObjLoader(); ObjLoader();
bool SupportsZone(Zone* zone) const override; [[nodiscard]] bool SupportsZone(const Zone& zone) const override;
void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone* zone) const override; void UnloadContainersOfZone(Zone& zone) const override;
void LoadObjDataForZone(ISearchPath* searchPath, 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 } // namespace IW3

View File

@ -820,10 +820,10 @@ namespace IW4
m_material->techniqueSet = techset->Asset(); m_material->techniqueSet = techset->Asset();
auto* loadingContext = m_manager->GetAssetLoadingContext(); auto* loadingContext = m_manager->GetAssetLoadingContext();
auto* searchPath = loadingContext->m_raw_search_path; auto& searchPath = loadingContext->m_raw_search_path;
auto* definitionCache = loadingContext->GetZoneAssetLoaderState<techset::TechsetDefinitionCache>(); auto* definitionCache = loadingContext->GetZoneAssetLoaderState<techset::TechsetDefinitionCache>();
const auto* techsetDefinition = AssetLoaderTechniqueSet::LoadTechsetDefinition(techsetName, searchPath, definitionCache); const auto* techsetDefinition = AssetLoaderTechniqueSet::LoadTechsetDefinition(techsetName, &searchPath, definitionCache);
if (techsetDefinition == nullptr) if (techsetDefinition == nullptr)
{ {
std::ostringstream ss; std::ostringstream ss;
@ -1375,7 +1375,7 @@ bool AssetLoaderMaterial::LoadFromGdt(
if (!entry) if (!entry)
return false; 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 try
{ {

View File

@ -227,7 +227,7 @@ bool AssetLoaderMenuList::LoadFromRaw(
return true; return true;
} }
void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext* context) const void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext& context) const
{ {
context->GetZoneAssetLoaderState<MenuConversionZoneState>()->FinalizeSupportingData(); context.GetZoneAssetLoaderState<MenuConversionZoneState>()->FinalizeSupportingData();
} }

View File

@ -14,6 +14,6 @@ namespace IW4
_NODISCARD bool CanLoadFromRaw() const override; _NODISCARD bool CanLoadFromRaw() const override;
bool bool
LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; 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 } // namespace IW4

View File

@ -3,6 +3,8 @@
#include "Game/IW4/IW4.h" #include "Game/IW4/IW4.h"
#include "Utils/MemoryManager.h" #include "Utils/MemoryManager.h"
#include <istream>
namespace IW4 namespace IW4
{ {
bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager* memory); bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager* memory);

View File

@ -37,14 +37,9 @@
#include "AssetLoaders/AssetLoaderXModel.h" #include "AssetLoaders/AssetLoaderXModel.h"
#include "AssetLoaders/AssetLoaderXModelSurfs.h" #include "AssetLoaders/AssetLoaderXModelSurfs.h"
#include "AssetLoading/AssetLoadingManager.h" #include "AssetLoading/AssetLoadingManager.h"
#include "Game/IW4/GameAssetPoolIW4.h"
#include "Game/IW4/GameIW4.h" #include "Game/IW4/GameIW4.h"
#include "Image/Dx9TextureLoader.h"
#include "Image/IwiLoader.h" #include "Image/IwiLoader.h"
#include "Image/IwiTypes.h"
#include "Image/Texture.h"
#include "ObjContainer/IPak/IPak.h" #include "ObjContainer/IPak/IPak.h"
#include "ObjLoading.h"
using namespace IW4; using namespace IW4;
@ -97,129 +92,32 @@ ObjLoader::ObjLoader()
#undef REGISTER_ASSET_LOADER #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; AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);
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<oat::D3DFORMAT>(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<int>(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<int>(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<GameAssetPoolIW4*>(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);
return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); 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) for (const auto& [type, loader] : m_asset_loaders_by_type)
loader->FinalizeAssetsForZone(context); loader->FinalizeAssetsForZone(context);

View File

@ -1,37 +1,31 @@
#pragma once #pragma once
#include "AssetLoading/IAssetLoader.h" #include "AssetLoading/IAssetLoader.h"
#include "Game/IW4/IW4.h"
#include "IObjLoader.h" #include "IObjLoader.h"
#include "SearchPath/ISearchPath.h" #include "SearchPath/ISearchPath.h"
#include <map>
#include <memory> #include <memory>
#include <unordered_map>
namespace IW4 namespace IW4
{ {
class ObjLoader final : public IObjLoader class ObjLoader final : public IObjLoader
{ {
std::map<asset_type_t, std::unique_ptr<IAssetLoader>> 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: public:
ObjLoader(); ObjLoader();
bool SupportsZone(Zone* zone) const override; [[nodiscard]] bool SupportsZone(const Zone& zone) const override;
void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone* zone) const override; void UnloadContainersOfZone(Zone& zone) const override;
void LoadObjDataForZone(ISearchPath* searchPath, 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; private:
void FinalizeAssetsForZone(AssetLoadingContext* context) const override; static bool IsMpZone(const Zone& zone);
static bool IsZmZone(const Zone& zone);
std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>> m_asset_loaders_by_type;
}; };
} // namespace IW4 } // namespace IW4

View File

@ -35,10 +35,8 @@ bool AssetLoaderGfxImage::LoadFromRaw(
const auto fileData = std::make_unique<char[]>(fileSize); const auto fileData = std::make_unique<char[]>(fileSize);
file.m_stream->read(fileData.get(), fileSize); file.m_stream->read(fileData.get(), fileSize);
MemoryManager tempMemory;
IwiLoader iwiLoader(&tempMemory);
std::istringstream ss(std::string(fileData.get(), fileSize)); std::istringstream ss(std::string(fileData.get(), fileSize));
const auto texture = iwiLoader.LoadIwi(ss); const auto texture = iwi::LoadIwi(ss);
if (!texture) if (!texture)
{ {
std::cerr << std::format("Failed to load texture from: {}\n", fileName); std::cerr << std::format("Failed to load texture from: {}\n", fileName);

View File

@ -227,7 +227,7 @@ bool AssetLoaderMenuList::LoadFromRaw(
return true; return true;
} }
void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext* context) const void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext& context) const
{ {
context->GetZoneAssetLoaderState<MenuConversionZoneState>()->FinalizeSupportingData(); context.GetZoneAssetLoaderState<MenuConversionZoneState>()->FinalizeSupportingData();
} }

View File

@ -14,6 +14,6 @@ namespace IW5
_NODISCARD bool CanLoadFromRaw() const override; _NODISCARD bool CanLoadFromRaw() const override;
bool bool
LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; 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 } // namespace IW5

View File

@ -3,6 +3,8 @@
#include "Game/IW5/IW5.h" #include "Game/IW5/IW5.h"
#include "Utils/MemoryManager.h" #include "Utils/MemoryManager.h"
#include <istream>
namespace IW5 namespace IW5
{ {
bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager* memory); bool LoadLeaderboardAsJson(std::istream& stream, LeaderboardDef& leaderboard, MemoryManager* memory);

View File

@ -41,14 +41,9 @@
#include "AssetLoaders/AssetLoaderXModel.h" #include "AssetLoaders/AssetLoaderXModel.h"
#include "AssetLoaders/AssetLoaderXModelSurfs.h" #include "AssetLoaders/AssetLoaderXModelSurfs.h"
#include "AssetLoading/AssetLoadingManager.h" #include "AssetLoading/AssetLoadingManager.h"
#include "Game/IW5/GameAssetPoolIW5.h"
#include "Game/IW5/GameIW5.h" #include "Game/IW5/GameIW5.h"
#include "Image/Dx9TextureLoader.h"
#include "Image/IwiLoader.h" #include "Image/IwiLoader.h"
#include "Image/IwiTypes.h"
#include "Image/Texture.h"
#include "ObjContainer/IPak/IPak.h" #include "ObjContainer/IPak/IPak.h"
#include "ObjLoading.h"
using namespace IW5; using namespace IW5;
@ -104,129 +99,32 @@ ObjLoader::ObjLoader()
#undef REGISTER_ASSET_LOADER #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; AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);
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<oat::D3DFORMAT>(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<int>(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<int>(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<GameAssetPoolIW5*>(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);
return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); 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) for (const auto& [type, loader] : m_asset_loaders_by_type)
loader->FinalizeAssetsForZone(context); loader->FinalizeAssetsForZone(context);

View File

@ -1,37 +1,31 @@
#pragma once #pragma once
#include "AssetLoading/IAssetLoader.h" #include "AssetLoading/IAssetLoader.h"
#include "Game/IW5/IW5.h"
#include "IObjLoader.h" #include "IObjLoader.h"
#include "SearchPath/ISearchPath.h" #include "SearchPath/ISearchPath.h"
#include <map>
#include <memory> #include <memory>
#include <unordered_map>
namespace IW5 namespace IW5
{ {
class ObjLoader final : public IObjLoader class ObjLoader final : public IObjLoader
{ {
std::map<asset_type_t, std::unique_ptr<IAssetLoader>> 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: public:
ObjLoader(); ObjLoader();
bool SupportsZone(Zone* zone) const override; [[nodiscard]] bool SupportsZone(const Zone& zone) const override;
void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone* zone) const override; void UnloadContainersOfZone(Zone& zone) const override;
void LoadObjDataForZone(ISearchPath* searchPath, 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; private:
void FinalizeAssetsForZone(AssetLoadingContext* context) const override; static bool IsMpZone(const Zone& zone);
static bool IsZmZone(const Zone& zone);
std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>> m_asset_loaders_by_type;
}; };
} // namespace IW5 } // namespace IW5

View File

@ -5,14 +5,9 @@
#include "AssetLoaders/AssetLoaderStringTable.h" #include "AssetLoaders/AssetLoaderStringTable.h"
#include "AssetLoaders/AssetLoaderXModel.h" #include "AssetLoaders/AssetLoaderXModel.h"
#include "AssetLoading/AssetLoadingManager.h" #include "AssetLoading/AssetLoadingManager.h"
#include "Game/T5/GameAssetPoolT5.h"
#include "Game/T5/GameT5.h" #include "Game/T5/GameT5.h"
#include "Image/Dx9TextureLoader.h"
#include "Image/IwiLoader.h" #include "Image/IwiLoader.h"
#include "Image/IwiTypes.h"
#include "Image/Texture.h"
#include "ObjContainer/IPak/IPak.h" #include "ObjContainer/IPak/IPak.h"
#include "ObjLoading.h"
using namespace T5; using namespace T5;
@ -61,129 +56,32 @@ ObjLoader::ObjLoader()
#undef REGISTER_ASSET_LOADER #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; AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);
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<oat::D3DFORMAT>(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<int>(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<int>(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<GameAssetPoolT5*>(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);
return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); 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) for (const auto& [type, loader] : m_asset_loaders_by_type)
loader->FinalizeAssetsForZone(context); loader->FinalizeAssetsForZone(context);

View File

@ -1,37 +1,31 @@
#pragma once #pragma once
#include "AssetLoading/IAssetLoader.h" #include "AssetLoading/IAssetLoader.h"
#include "Game/T5/T5.h"
#include "IObjLoader.h" #include "IObjLoader.h"
#include "SearchPath/ISearchPath.h" #include "SearchPath/ISearchPath.h"
#include <map>
#include <memory> #include <memory>
#include <unordered_map>
namespace T5 namespace T5
{ {
class ObjLoader final : public IObjLoader class ObjLoader final : public IObjLoader
{ {
std::map<asset_type_t, std::unique_ptr<IAssetLoader>> 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: public:
ObjLoader(); ObjLoader();
bool SupportsZone(Zone* zone) const override; bool SupportsZone(const Zone& zone) const override;
void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone* zone) const override; void UnloadContainersOfZone(Zone& zone) const override;
void LoadObjDataForZone(ISearchPath* searchPath, 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; private:
void FinalizeAssetsForZone(AssetLoadingContext* context) const override; static bool IsMpZone(const Zone& zone);
static bool IsZmZone(const Zone& zone);
std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>> m_asset_loaders_by_type;
}; };
} // namespace T5 } // namespace T5

View File

@ -6,6 +6,7 @@
#include "Pool/GlobalAssetPool.h" #include "Pool/GlobalAssetPool.h"
#include <cstring> #include <cstring>
#include <format>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <zlib.h> #include <zlib.h>
@ -27,7 +28,7 @@ bool AssetLoaderGfxImage::CanLoadFromRaw() const
bool AssetLoaderGfxImage::LoadFromRaw( bool AssetLoaderGfxImage::LoadFromRaw(
const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const 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); const auto file = searchPath->Open(fileName);
if (!file.IsOpen()) if (!file.IsOpen())
return false; return false;
@ -37,13 +38,11 @@ bool AssetLoaderGfxImage::LoadFromRaw(
file.m_stream->read(fileData.get(), fileSize); file.m_stream->read(fileData.get(), fileSize);
const auto dataHash = static_cast<unsigned>(crc32(0u, reinterpret_cast<const Bytef*>(fileData.get()), fileSize)); const auto dataHash = static_cast<unsigned>(crc32(0u, reinterpret_cast<const Bytef*>(fileData.get()), fileSize));
MemoryManager tempMemory;
IwiLoader iwiLoader(&tempMemory);
std::istringstream ss(std::string(fileData.get(), fileSize)); std::istringstream ss(std::string(fileData.get(), fileSize));
const auto texture = iwiLoader.LoadIwi(ss); const auto texture = iwi::LoadIwi(ss);
if (!texture) if (!texture)
{ {
std::cerr << "Failed to load texture from: " << fileName << "\n"; std::cerr << std::format("Failed to load texture from: {}\n", fileName);
return false; return false;
} }

View File

@ -58,12 +58,12 @@
#include "ObjContainer/IPak/IPak.h" #include "ObjContainer/IPak/IPak.h"
#include "ObjLoading.h" #include "ObjLoading.h"
#include <sstream> #include <format>
namespace T6 namespace T6
{ {
const int ObjLoader::IPAK_READ_HASH = Common::Com_HashKey("ipak_read", 64); constexpr auto IPAK_READ_HASH = Common::Com_HashKey("ipak_read", 64);
const int ObjLoader::GLOBAL_HASH = Common::Com_HashKey("GLOBAL", 64); constexpr auto GLOBAL_HASH = Common::Com_HashKey("GLOBAL", 64);
ObjLoader::ObjLoader() ObjLoader::ObjLoader()
{ {
@ -125,37 +125,37 @@ namespace T6
#undef REGISTER_ASSET_LOADER #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{}; SoundAssetBankChecksum checksum{};
static_assert(sizeof(SoundAssetBankChecksum::checksumBytes) == sizeof(SndRuntimeAssetBank::linkTimeChecksum)); static_assert(sizeof(SoundAssetBankChecksum::checksumBytes) == sizeof(SndRuntimeAssetBank::linkTimeChecksum));
for (auto i = 0u; i < sizeof(SoundAssetBankChecksum::checksumBytes); i++) for (auto i = 0u; i < sizeof(SoundAssetBankChecksum::checksumBytes); i++)
checksum.checksumBytes[i] = sndRuntimeAssetBank.linkTimeChecksum[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) 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); auto* existingSoundBank = SoundBank::Repository.GetContainerByName(soundBankFileName);
if (existingSoundBank != nullptr) if (existingSoundBank != nullptr)
{ {
if (ObjLoading::Configuration.Verbose) 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; return existingSoundBank;
} }
auto file = searchPath->Open(soundBankFileName); auto file = searchPath.Open(soundBankFileName);
if (file.IsOpen()) if (file.IsOpen())
{ {
auto sndBank = std::make_unique<SoundBank>(soundBankFileName, std::move(file.m_stream), file.m_length); auto sndBank = std::make_unique<SoundBank>(soundBankFileName, std::move(file.m_stream), file.m_length);
@ -163,26 +163,26 @@ namespace T6
if (!sndBank->Initialize()) 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; return nullptr;
} }
SoundBank::Repository.AddContainer(std::move(sndBank), zone); SoundBank::Repository.AddContainer(std::move(sndBank), &zone);
if (ObjLoading::Configuration.Verbose) 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; return sndBankPtr;
} }
std::cout << "Failed to load sound bank '" << soundBankFileName << "'\n"; std::cerr << std::format("Failed to load sound bank '{}'\n", soundBankFileName);
return nullptr; return nullptr;
} }
void ObjLoader::LoadSoundBankFromLinkedInfo(ISearchPath* searchPath, void ObjLoader::LoadSoundBankFromLinkedInfo(ISearchPath& searchPath,
const std::string& soundBankFileName, const std::string& soundBankFileName,
const SndRuntimeAssetBank* sndBankLinkedInfo, const SndRuntimeAssetBank& sndBankLinkedInfo,
Zone* zone, Zone& zone,
std::set<std::string>& loadedBanksForZone, std::set<std::string>& loadedBanksForZone,
std::stack<std::string>& dependenciesToLoad) std::stack<std::string>& dependenciesToLoad)
{ {
@ -192,10 +192,9 @@ namespace T6
if (soundBank) if (soundBank)
{ {
if (!VerifySoundBankChecksum(soundBank, *sndBankLinkedInfo)) if (!VerifySoundBankChecksum(*soundBank, sndBankLinkedInfo))
{ std::cout << std::format("Checksum of sound bank does not match link time checksum for '{}'\n", soundBankFileName);
std::cout << "Checksum of sound bank does not match link time checksum for '" << soundBankFileName << "'\n";
}
loadedBanksForZone.emplace(soundBankFileName); loadedBanksForZone.emplace(soundBankFileName);
for (const auto& dependency : soundBank->GetDependencies()) for (const auto& dependency : soundBank->GetDependencies())
@ -206,20 +205,20 @@ namespace T6
} }
} }
void ObjLoader::LoadSoundBanksFromAsset(ISearchPath* searchPath, const SndBank* sndBank, Zone* zone, std::set<std::string>& loadedBanksForZone) void ObjLoader::LoadSoundBanksFromAsset(ISearchPath& searchPath, const SndBank& sndBank, Zone& zone, std::set<std::string>& loadedBanksForZone)
{ {
std::stack<std::string> dependenciesToLoad; std::stack<std::string> dependenciesToLoad;
if (sndBank->streamAssetBank.zone) if (sndBank.streamAssetBank.zone)
{ {
const auto soundBankFileName = SoundBank::GetFileNameForDefinition(true, sndBank->streamAssetBank.zone, sndBank->streamAssetBank.language); const auto soundBankFileName = SoundBank::GetFileNameForDefinition(true, sndBank.streamAssetBank.zone, sndBank.streamAssetBank.language);
LoadSoundBankFromLinkedInfo(searchPath, soundBankFileName, &sndBank->streamAssetBank, zone, loadedBanksForZone, dependenciesToLoad); 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); const auto soundBankFileName = SoundBank::GetFileNameForDefinition(false, sndBank.loadAssetBank.zone, sndBank.loadAssetBank.language);
LoadSoundBankFromLinkedInfo(searchPath, soundBankFileName, &sndBank->loadAssetBank, zone, loadedBanksForZone, dependenciesToLoad); LoadSoundBankFromLinkedInfo(searchPath, soundBankFileName, sndBank.loadAssetBank, zone, loadedBanksForZone, dependenciesToLoad);
} }
while (!dependenciesToLoad.empty()) while (!dependenciesToLoad.empty())
@ -236,76 +235,72 @@ namespace T6
loadedBanksForZone.emplace(dependencyFileName); loadedBanksForZone.emplace(dependencyFileName);
for (const auto& dependency : soundBank->GetDependencies()) for (const auto& dependency : soundBank->GetDependencies())
{
dependenciesToLoad.emplace(dependency); 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) 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); auto* existingIPak = IPak::Repository.GetContainerByName(ipakName);
if (existingIPak != nullptr) if (existingIPak != nullptr)
{ {
if (ObjLoading::Configuration.Verbose) 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; 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()) if (file.IsOpen())
{ {
auto ipak = std::make_unique<IPak>(ipakFilename, std::move(file.m_stream)); auto ipak = std::make_unique<IPak>(ipakFilename, std::move(file.m_stream));
if (ipak->Initialize()) if (ipak->Initialize())
{ {
IPak::Repository.AddContainer(std::move(ipak), zone); IPak::Repository.AddContainer(std::move(ipak), &zone);
if (ObjLoading::Configuration.Verbose) 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 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) 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); LoadIPakForZone(searchPath, "base", zone);
auto languagePrefixes = g_GameT6.GetLanguagePrefixes(); const auto languagePrefixes = g_GameT6.GetLanguagePrefixes();
for (const auto& languagePrefix : languagePrefixes) for (const auto& languagePrefix : languagePrefixes)
{ LoadIPakForZone(searchPath, std::format("{}base", languagePrefix.m_prefix), zone);
LoadIPakForZone(searchPath, languagePrefix.m_prefix + "base", zone);
}
if (IsMpZone(zone)) if (IsMpZone(zone))
{ {
if (ObjLoading::Configuration.Verbose) 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, "mp", zone);
LoadIPakForZone(searchPath, "so", zone); LoadIPakForZone(searchPath, "so", zone);
@ -313,23 +308,23 @@ namespace T6
else if (IsZmZone(zone)) else if (IsZmZone(zone))
{ {
if (ObjLoading::Configuration.Verbose) 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); LoadIPakForZone(searchPath, "zm", zone);
} }
else else
{ {
if (ObjLoading::Configuration.Verbose) 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); LoadIPakForZone(searchPath, "sp", zone);
} }
} }
void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const
{ {
auto* assetPoolT6 = dynamic_cast<GameAssetPoolT6*>(zone->m_pools.get()); const auto* assetPoolT6 = dynamic_cast<GameAssetPoolT6*>(zone.m_pools.get());
const auto zoneNameHash = Common::Com_HashKey(zone->m_name.c_str(), 64); const auto zoneNameHash = Common::Com_HashKey(zone.m_name.c_str(), 64);
LoadCommonIPaks(searchPath, zone); LoadCommonIPaks(searchPath, zone);
@ -337,7 +332,7 @@ namespace T6
{ {
for (auto* keyValuePairsEntry : *assetPoolT6->m_key_value_pairs) 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++) for (auto variableIndex = 0; variableIndex < keyValuePairs->numVariables; variableIndex++)
{ {
auto* variable = &keyValuePairs->keyValuePairs[variableIndex]; auto* variable = &keyValuePairs->keyValuePairs[variableIndex];
@ -356,143 +351,23 @@ namespace T6
for (auto* sndBankAssetInfo : *assetPoolT6->m_sound_bank) for (auto* sndBankAssetInfo : *assetPoolT6->m_sound_bank)
{ {
LoadSoundBanksFromAsset(searchPath, sndBankAssetInfo->Asset(), zone, loadedSoundBanksForZone); LoadSoundBanksFromAsset(searchPath, *sndBankAssetInfo->Asset(), zone, loadedSoundBanksForZone);
} }
} }
} }
void ObjLoader::UnloadContainersOfZone(Zone* zone) const void ObjLoader::UnloadContainersOfZone(Zone& zone) const
{ {
IPak::Repository.RemoveContainerReferences(zone); IPak::Repository.RemoveContainerReferences(&zone);
} }
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; AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, context);
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<oat::DXGI_FORMAT>(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<int>(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<GameAssetPoolT6*>(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);
}
}
}
}
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);
return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); 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) for (const auto& [type, loader] : m_asset_loaders_by_type)
loader->FinalizeAssetsForZone(context); loader->FinalizeAssetsForZone(context);

View File

@ -6,52 +6,44 @@
#include "ObjContainer/SoundBank/SoundBank.h" #include "ObjContainer/SoundBank/SoundBank.h"
#include "SearchPath/ISearchPath.h" #include "SearchPath/ISearchPath.h"
#include <map>
#include <memory> #include <memory>
#include <set> #include <set>
#include <stack> #include <stack>
#include <string> #include <string>
#include <unordered_map>
namespace T6 namespace T6
{ {
class ObjLoader final : public IObjLoader class ObjLoader final : public IObjLoader
{ {
static const int IPAK_READ_HASH;
static const int GLOBAL_HASH;
std::map<asset_type_t, std::unique_ptr<IAssetLoader>> m_asset_loaders_by_type;
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,
std::set<std::string>& loadedBanksForZone,
std::stack<std::string>& dependenciesToLoad);
static void LoadSoundBanksFromAsset(ISearchPath* searchPath, const SndBank* sndBank, Zone* zone, std::set<std::string>& 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: public:
ObjLoader(); ObjLoader();
bool SupportsZone(Zone* zone) const override; [[nodiscard]] bool SupportsZone(const Zone& zone) const override;
void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override;
void UnloadContainersOfZone(Zone* zone) const override; void UnloadContainersOfZone(Zone& zone) const override;
void LoadObjDataForZone(ISearchPath* searchPath, 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; private:
void FinalizeAssetsForZone(AssetLoadingContext* context) 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,
const std::string& soundBankFileName,
const SndRuntimeAssetBank& sndBankLinkedInfo,
Zone& zone,
std::set<std::string>& loadedBanksForZone,
std::stack<std::string>& dependenciesToLoad);
static void LoadSoundBanksFromAsset(ISearchPath& searchPath, const SndBank& sndBank, Zone& zone, std::set<std::string>& loadedBanksForZone);
static void LoadIPakForZone(ISearchPath& searchPath, const std::string& ipakName, Zone& zone);
static void LoadCommonIPaks(ISearchPath& searchPath, Zone& zone);
static bool IsMpZone(const Zone& zone);
static bool IsZmZone(const Zone& zone);
std::unordered_map<asset_type_t, std::unique_ptr<IAssetLoader>> m_asset_loaders_by_type;
}; };
} // namespace T6 } // namespace T6

View File

@ -7,35 +7,33 @@
class IObjLoader class IObjLoader
{ {
public: public:
IObjLoader() = default;
virtual ~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. * \brief Checks whether this ObjLoader supports a specified zone.
* \param zone The zone to check. * \param zone The zone to check.
* \return \c true if the specified zone is supported. * \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. * \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 searchPath The search path object to use to find the referenced containers.
* \param zone The zone to check for 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 * \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. * unloaded. \param zone The zone to unload all containers for.
*/ */
virtual void UnloadContainersOfZone(Zone* zone) const = 0; virtual void UnloadContainersOfZone(Zone& zone) const = 0;
/** virtual bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName) const = 0;
* \brief Loads the obj data for all assets of a specified zone. virtual void FinalizeAssetsForZone(AssetLoadingContext& context) const = 0;
* \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;
}; };

View File

@ -1,276 +0,0 @@
#include "DdsLoader.h"
#include "Image/DdsTypes.h"
#include "Utils/ClassUtils.h"
#include "Utils/FileUtils.h"
#include <iostream>
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<char*>(&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<char*>(&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<const ImageFormatUnsigned*>(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<char*>(&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<char*>(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();
}

View File

@ -1,16 +0,0 @@
#pragma once
#include "Image/Texture.h"
#include "Utils/MemoryManager.h"
#include <istream>
class DdsLoader
{
MemoryManager* m_memory_manager;
public:
explicit DdsLoader(MemoryManager* memoryManager);
Texture* LoadDds(std::istream& stream) const;
};

View File

@ -1,476 +0,0 @@
#include "IwiLoader.h"
#include "Image/IwiTypes.h"
#include <cassert>
#include <type_traits>
IwiLoader::IwiLoader(MemoryManager* memoryManager)
{
m_memory_manager = memoryManager;
}
const ImageFormat* IwiLoader::GetFormat6(int8_t format)
{
switch (static_cast<iwi6::IwiFormat>(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<char*>(&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<TextureCube>(format, width, height, hasMipMaps);
}
else if (header.flags & iwi6::IwiFlags::IMG_FLAG_VOLMAP)
{
texture = m_memory_manager->Create<Texture3D>(format, width, height, depth, hasMipMaps);
}
else
{
texture = m_memory_manager->Create<Texture2D>(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<int>(std::extent_v<decltype(iwi6::IwiHeader::fileSizeForPicmip)>)
&& 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<char*>(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<iwi8::IwiFormat>(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<char*>(&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<TextureCube>(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<Texture3D>(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<Texture2D>(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<int>(std::extent_v<decltype(iwi8::IwiHeader::fileSizeForPicmip)>)
&& 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<char*>(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<iwi13::IwiFormat>(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<char*>(&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<TextureCube>(format, width, height, hasMipMaps);
}
else if (header.flags & iwi13::IwiFlags::IMG_FLAG_VOLMAP)
{
texture = m_memory_manager->Create<Texture3D>(format, width, height, depth, hasMipMaps);
}
else
{
texture = m_memory_manager->Create<Texture2D>(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<int>(std::extent_v<decltype(iwi13::IwiHeader::fileSizeForPicmip)>)
&& 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<char*>(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<iwi27::IwiFormat>(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<char*>(&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<TextureCube>(format, width, height, hasMipMaps);
}
else if (header.flags & iwi27::IwiFlags::IMG_FLAG_VOLMAP)
{
texture = m_memory_manager->Create<Texture3D>(format, width, height, depth, hasMipMaps);
}
else
{
texture = m_memory_manager->Create<Texture2D>(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<int>(std::extent_v<decltype(iwi27::IwiHeader::fileSizeForPicmip)>)
&& 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<char*>(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<char*>(&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;
}

View File

@ -1,28 +0,0 @@
#pragma once
#include "Image/Texture.h"
#include "Utils/MemoryManager.h"
#include <istream>
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);
};

View File

@ -29,8 +29,6 @@ template<typename ContainerType, typename ReferencerType> class ObjContainerRepo
ObjContainerEntry& operator=(ObjContainerEntry&& other) noexcept = default; ObjContainerEntry& operator=(ObjContainerEntry&& other) noexcept = default;
}; };
std::vector<ObjContainerEntry> m_containers;
public: public:
ObjContainerRepository() = default; ObjContainerRepository() = default;
~ObjContainerRepository() = default; ~ObjContainerRepository() = default;
@ -120,4 +118,7 @@ public:
return entry.m_container.get(); return entry.m_container.get();
}); });
} }
private:
std::vector<ObjContainerEntry> m_containers;
}; };

View File

@ -22,7 +22,7 @@ const IObjLoader* const OBJ_LOADERS[]{
new T6::ObjLoader(), new T6::ObjLoader(),
}; };
void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) void ObjLoading::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone)
{ {
for (const auto* loader : OBJ_LOADERS) for (const auto* loader : OBJ_LOADERS)
{ {
@ -34,19 +34,7 @@ void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone*
} }
} }
void ObjLoading::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) void ObjLoading::UnloadContainersOfZone(Zone& zone)
{
for (const auto* loader : OBJ_LOADERS)
{
if (loader->SupportsZone(zone))
{
loader->LoadObjDataForZone(searchPath, zone);
return;
}
}
}
void ObjLoading::UnloadContainersOfZone(Zone* zone)
{ {
for (const auto* loader : OBJ_LOADERS) for (const auto* loader : OBJ_LOADERS)
{ {
@ -58,10 +46,10 @@ void ObjLoading::UnloadContainersOfZone(Zone* zone)
} }
} }
void ObjLoading::LoadIWDsInSearchPath(ISearchPath* searchPath) void ObjLoading::LoadIWDsInSearchPath(ISearchPath& searchPath)
{ {
searchPath->Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"), searchPath.Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"),
[searchPath](const std::string& path) [&searchPath](const std::string& path)
{ {
auto file = std::make_unique<std::ifstream>(path, std::fstream::in | std::fstream::binary); auto file = std::make_unique<std::ifstream>(path, std::fstream::in | std::fstream::binary);
@ -71,15 +59,15 @@ void ObjLoading::LoadIWDsInSearchPath(ISearchPath* searchPath)
if (iwd->Initialize()) if (iwd->Initialize())
{ {
IWD::Repository.AddContainer(std::move(iwd), searchPath); 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() SearchPaths ObjLoading::GetIWDSearchPaths()
@ -94,11 +82,11 @@ SearchPaths ObjLoading::GetIWDSearchPaths()
return iwdPaths; 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) for (const auto* loader : OBJ_LOADERS)
{ {
if (loader->SupportsZone(context->m_zone)) if (loader->SupportsZone(context.m_zone))
{ {
return loader->LoadAssetForZone(context, assetType, assetName); return loader->LoadAssetForZone(context, assetType, assetName);
} }
@ -107,11 +95,11 @@ bool ObjLoading::LoadAssetForZone(AssetLoadingContext* context, const asset_type
return false; return false;
} }
void ObjLoading::FinalizeAssetsForZone(AssetLoadingContext* context) void ObjLoading::FinalizeAssetsForZone(AssetLoadingContext& context)
{ {
for (const auto* loader : OBJ_LOADERS) for (const auto* loader : OBJ_LOADERS)
{ {
if (loader->SupportsZone(context->m_zone)) if (loader->SupportsZone(context.m_zone))
{ {
loader->FinalizeAssetsForZone(context); loader->FinalizeAssetsForZone(context);
return; return;

View File

@ -21,25 +21,25 @@ public:
* \param searchPath The search path to use to find the referenced containers. * \param searchPath The search path to use to find the referenced containers.
* \param zone The zone to load all referenced containers of. * \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 * \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. * 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. * \brief Loads all IWDs that can be found in a specified search path.
* \param searchPath The search path that contains IWDs to be loaded. * \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. * \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. * \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. * \brief Creates a \c SearchPaths object containing all IWDs that are currently loaded.
@ -47,13 +47,6 @@ public:
*/ */
static SearchPaths GetIWDSearchPaths(); static SearchPaths GetIWDSearchPaths();
/** static bool LoadAssetForZone(AssetLoadingContext& context, asset_type_t assetType, const std::string& assetName);
* \brief Loads the obj data for all assets of a zone. static void FinalizeAssetsForZone(AssetLoadingContext& context);
* \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);
}; };

View File

@ -1,5 +1,6 @@
#include "SearchPaths.h" #include "SearchPaths.h"
#include <cassert>
#include <filesystem> #include <filesystem>
SearchPathOpenFile SearchPaths::Open(const std::string& fileName) SearchPathOpenFile SearchPaths::Open(const std::string& fileName)
@ -38,11 +39,13 @@ void SearchPaths::CommitSearchPath(std::unique_ptr<ISearchPath> searchPath)
void SearchPaths::IncludeSearchPath(ISearchPath* searchPath) void SearchPaths::IncludeSearchPath(ISearchPath* searchPath)
{ {
assert(searchPath);
m_search_paths.push_back(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) for (auto i = m_search_paths.begin(); i != m_search_paths.end(); ++i)
{ {
if (*i == searchPath) if (*i == searchPath)

View File

@ -40,7 +40,7 @@ public:
* \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 * \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. * SearchPaths object. \param searchPath The search path to remove.
*/ */
void RemoveSearchPath(ISearchPath* searchPath); void RemoveSearchPath(const ISearchPath* searchPath);
iterator begin(); iterator begin();
iterator end(); iterator end();

View File

@ -8,9 +8,9 @@ namespace sound_curve
{ {
std::unique_ptr<GenericGraph2D> LoadSoundCurve(const IAssetLoadingManager* manager, const std::string& soundCurveName) std::unique_ptr<GenericGraph2D> 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 fileName = std::format("soundaliases/{}.vfcurve", soundCurveName);
const auto file = searchPath->Open(fileName); const auto file = searchPath.Open(fileName);
if (!file.IsOpen()) if (!file.IsOpen())
{ {
return nullptr; return nullptr;

View File

@ -9,9 +9,9 @@ namespace
{ {
std::unique_ptr<GenericGraph2D> LoadAccuracyGraph(const IAssetLoadingManager* manager, const std::string& graphName, const std::string& subFolder) std::unique_ptr<GenericGraph2D> 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 fileName = std::format("accuracy/{}/{}", subFolder, graphName);
const auto file = searchPath->Open(fileName); const auto file = searchPath.Open(fileName);
if (!file.IsOpen()) if (!file.IsOpen())
{ {
std::cerr << std::format("Failed to open file for accuracy graph: {}/{}\n", subFolder, graphName); std::cerr << std::format("Failed to open file for accuracy graph: {}/{}\n", subFolder, graphName);

View File

@ -20,7 +20,7 @@ bool PartClassificationState::Load(const char** hitLocNames, const size_t hitLoc
if (ObjLoading::Configuration.Verbose) if (ObjLoading::Configuration.Verbose)
std::cout << "Loading part classification...\n"; 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()) if (!file.IsOpen())
{ {
std::cerr << std::format("Could not load part classification: Failed to open {}\n", PART_CLASSIFICATION_FILE); std::cerr << std::format("Could not load part classification: Failed to open {}\n", PART_CLASSIFICATION_FILE);

Some files were not shown because too many files have changed in this diff Show More