2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-01-09 18:21:49 +00:00

Merge pull request #641 from Laupetin/feature/feature-parity-image

feat: Feature parity for games
This commit is contained in:
Jan
2026-01-05 11:21:48 +01:00
committed by GitHub
88 changed files with 3044 additions and 2094 deletions

View File

@@ -1515,7 +1515,8 @@ namespace IW3
MAPTYPE_2D = 0x3,
MAPTYPE_3D = 0x4,
MAPTYPE_CUBE = 0x5,
MAPTYPE_COUNT = 0x6,
MAPTYPE_COUNT
};
enum TextureSemantic

View File

@@ -1181,6 +1181,18 @@ namespace IW4
int platform[2];
};
enum MapType
{
MAPTYPE_NONE = 0x0,
MAPTYPE_INVALID1 = 0x1,
MAPTYPE_1D = 0x2,
MAPTYPE_2D = 0x3,
MAPTYPE_3D = 0x4,
MAPTYPE_CUBE = 0x5,
MAPTYPE_COUNT
};
enum TextureSemantic
{
TS_2D = 0x0,
@@ -1197,6 +1209,19 @@ namespace IW4
TS_WATER_MAP = 0xB,
};
enum ImageCategory
{
IMG_CATEGORY_UNKNOWN = 0x0,
IMG_CATEGORY_AUTO_GENERATED = 0x1,
IMG_CATEGORY_LIGHTMAP = 0x2,
IMG_CATEGORY_LOAD_FROM_FILE = 0x3,
IMG_CATEGORY_RAW = 0x4,
IMG_CATEGORY_FIRST_UNMANAGED = 0x5,
IMG_CATEGORY_WATER = 0x5,
IMG_CATEGORY_RENDERTARGET = 0x6,
IMG_CATEGORY_TEMP = 0x7,
};
struct GfxImage
{
GfxTexture texture;

View File

@@ -732,23 +732,6 @@ namespace IW5
GfxImage* image;
};
enum TextureSemantic
{
TS_2D = 0x0,
TS_FUNCTION = 0x1,
TS_COLOR_MAP = 0x2,
TS_DETAIL_MAP = 0x3,
TS_UNUSED_2 = 0x4,
TS_NORMAL_MAP = 0x5,
TS_UNUSED_3 = 0x6,
TS_UNUSED_4 = 0x7,
TS_SPECULAR_MAP = 0x8,
TS_UNUSED_5 = 0x9,
TS_UNUSED_6 = 0xA,
TS_WATER_MAP = 0xB,
TS_DISPLACEMENT_MAP = 0xC
};
union MaterialTextureDefInfo
{
GfxImage* image;
@@ -1157,6 +1140,48 @@ namespace IW5
int platform[2];
};
enum MapType
{
MAPTYPE_NONE = 0x0,
MAPTYPE_INVALID1 = 0x1,
MAPTYPE_1D = 0x2,
MAPTYPE_2D = 0x3,
MAPTYPE_3D = 0x4,
MAPTYPE_CUBE = 0x5,
MAPTYPE_COUNT
};
enum TextureSemantic
{
TS_2D = 0x0,
TS_FUNCTION = 0x1,
TS_COLOR_MAP = 0x2,
TS_DETAIL_MAP = 0x3,
TS_UNUSED_2 = 0x4,
TS_NORMAL_MAP = 0x5,
TS_UNUSED_3 = 0x6,
TS_UNUSED_4 = 0x7,
TS_SPECULAR_MAP = 0x8,
TS_UNUSED_5 = 0x9,
TS_UNUSED_6 = 0xA,
TS_WATER_MAP = 0xB,
TS_DISPLACEMENT_MAP = 0xC
};
enum ImageCategory
{
IMG_CATEGORY_UNKNOWN = 0x0,
IMG_CATEGORY_AUTO_GENERATED = 0x1,
IMG_CATEGORY_LIGHTMAP = 0x2,
IMG_CATEGORY_LOAD_FROM_FILE = 0x3,
IMG_CATEGORY_RAW = 0x4,
IMG_CATEGORY_FIRST_UNMANAGED = 0x5,
IMG_CATEGORY_WATER = 0x5,
IMG_CATEGORY_RENDERTARGET = 0x6,
IMG_CATEGORY_TEMP = 0x7,
};
struct GfxImage
{
GfxTexture texture;

View File

@@ -1242,6 +1242,18 @@ namespace T5
int platform[2];
};
enum MapType
{
MAPTYPE_NONE = 0x0,
MAPTYPE_INVALID1 = 0x1,
MAPTYPE_INVALID2 = 0x2,
MAPTYPE_2D = 0x3,
MAPTYPE_3D = 0x4,
MAPTYPE_CUBE = 0x5,
MAPTYPE_COUNT
};
enum TextureSemantic
{
TS_2D = 0x0,

View File

@@ -879,6 +879,18 @@ namespace T6
uint32_t valid : 1;
};
enum MapType
{
MAPTYPE_NONE = 0x0,
MAPTYPE_INVALID1 = 0x1,
MAPTYPE_INVALID2 = 0x2,
MAPTYPE_2D = 0x3,
MAPTYPE_3D = 0x4,
MAPTYPE_CUBE = 0x5,
MAPTYPE_COUNT
};
enum TextureSemantic
{
TS_2D = 0x0,

View File

@@ -38,11 +38,13 @@ function ImageConverter:project()
self:include(includes)
Utils:include(includes)
Common:include(includes)
ObjImage:include(includes)
Raw:use()
links:linkto(Utils)
links:linkto(Common)
links:linkto(ObjImage)
links:linkall()
end

View File

@@ -1,5 +1,6 @@
#include "ImageConverter.h"
#include "Game/IGame.h"
#include "Image/DdsLoader.h"
#include "Image/DdsWriter.h"
#include "Image/IwiLoader.h"
@@ -17,10 +18,12 @@
#include <format>
#include <fstream>
#include <iostream>
#include <optional>
namespace fs = std::filesystem;
using namespace image;
namespace image_converter
namespace
{
constexpr auto EXTENSION_IWI = ".iwi";
constexpr auto EXTENSION_DDS = ".dds";
@@ -29,7 +32,7 @@ namespace image_converter
{
public:
ImageConverterImpl()
: m_game_to_convert_to(image_converter::Game::UNKNOWN)
: m_game_to_convert_to(std::nullopt)
{
}
@@ -76,8 +79,8 @@ namespace image_converter
return false;
}
const auto texture = iwi::LoadIwi(file);
if (!texture)
const auto loadResult = image::LoadIwi(file);
if (!loadResult)
return false;
auto outPath = iwiPath;
@@ -90,7 +93,7 @@ namespace image_converter
return false;
}
m_dds_writer.DumpImage(outFile, texture.get());
m_dds_writer.DumpImage(outFile, loadResult->m_texture.get());
return true;
}
@@ -103,7 +106,7 @@ namespace image_converter
return false;
}
const auto texture = dds::LoadDds(file);
const auto texture = image::LoadDds(file);
if (!texture)
return false;
@@ -129,23 +132,23 @@ namespace image_converter
if (m_iwi_writer)
return true;
if (m_game_to_convert_to == Game::UNKNOWN && !ShowGameTui())
if (!m_game_to_convert_to && !ShowGameTui())
return false;
switch (m_game_to_convert_to)
switch (*m_game_to_convert_to)
{
case Game::IW3:
m_iwi_writer = std::make_unique<iwi6::IwiWriter>();
case GameId::IW3:
m_iwi_writer = std::make_unique<image::iwi6::IwiWriter>();
break;
case Game::IW4:
case Game::IW5:
m_iwi_writer = std::make_unique<iwi8::IwiWriter>();
case GameId::IW4:
case GameId::IW5:
m_iwi_writer = std::make_unique<image::iwi8::IwiWriter>();
break;
case Game::T5:
m_iwi_writer = std::make_unique<iwi13::IwiWriter>();
case GameId::T5:
m_iwi_writer = std::make_unique<image::iwi13::IwiWriter>();
break;
case Game::T6:
m_iwi_writer = std::make_unique<iwi27::IwiWriter>();
case GameId::T6:
m_iwi_writer = std::make_unique<image::iwi27::IwiWriter>();
break;
default:
assert(false);
@@ -170,19 +173,19 @@ namespace image_converter
switch (num)
{
case 1:
m_game_to_convert_to = Game::IW3;
m_game_to_convert_to = GameId::IW3;
break;
case 2:
m_game_to_convert_to = Game::IW4;
m_game_to_convert_to = GameId::IW4;
break;
case 3:
m_game_to_convert_to = Game::IW5;
m_game_to_convert_to = GameId::IW5;
break;
case 4:
m_game_to_convert_to = Game::T5;
m_game_to_convert_to = GameId::T5;
break;
case 5:
m_game_to_convert_to = Game::T6;
m_game_to_convert_to = GameId::T6;
break;
default:
con::error("Invalid input");
@@ -193,13 +196,13 @@ namespace image_converter
}
ImageConverterArgs m_args;
image_converter::Game m_game_to_convert_to;
std::optional<GameId> m_game_to_convert_to;
DdsWriter m_dds_writer;
std::unique_ptr<IImageWriter> m_iwi_writer;
std::unique_ptr<ImageWriter> m_iwi_writer;
};
} // namespace image_converter
} // namespace
std::unique_ptr<ImageConverter> ImageConverter::Create()
{
return std::make_unique<image_converter::ImageConverterImpl>();
return std::make_unique<ImageConverterImpl>();
}

View File

@@ -86,7 +86,7 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
};
ImageConverterArgs::ImageConverterArgs()
: m_game_to_convert_to(image_converter::Game::UNKNOWN),
: m_game_to_convert_to(std::nullopt),
m_argument_parser(COMMAND_LINE_OPTIONS, std::extent_v<decltype(COMMAND_LINE_OPTIONS)>)
{
}

View File

@@ -1,24 +1,13 @@
#pragma once
#include "Game/IGame.h"
#include "Utils/Arguments/ArgumentParser.h"
#include <cstdint>
#include <optional>
#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:
@@ -26,7 +15,7 @@ public:
bool ParseArgs(int argc, const char** argv, bool& shouldContinue);
std::vector<std::string> m_files_to_convert;
image_converter::Game m_game_to_convert_to;
std::optional<GameId> m_game_to_convert_to;
private:
/**

View File

@@ -9,7 +9,9 @@
#include <iostream>
#include <memory>
namespace dds
using namespace image;
namespace
{
class DdsLoaderInternal
{
@@ -193,7 +195,7 @@ namespace dds
return ReadPixelFormatUnsigned(pf);
}
_NODISCARD bool ReadHeader()
[[nodiscard]] bool ReadHeader()
{
DDS_HEADER header{};
m_stream.read(reinterpret_cast<char*>(&header), sizeof(header));
@@ -277,10 +279,13 @@ namespace dds
unsigned m_depth;
const ImageFormat* m_format;
};
} // namespace
namespace image
{
std::unique_ptr<Texture> LoadDds(std::istream& stream)
{
DdsLoaderInternal internal(stream);
return internal.LoadDds();
}
} // namespace dds
} // namespace image

View File

@@ -5,7 +5,7 @@
#include <istream>
#include <memory>
namespace dds
namespace image
{
std::unique_ptr<Texture> LoadDds(std::istream& stream);
}

View File

@@ -2,6 +2,8 @@
#include <cstdint>
namespace image
{
constexpr uint32_t MakeFourCc(const char ch0, const char ch1, const char ch2, const char ch3)
{
return static_cast<uint32_t>(ch0) | static_cast<uint32_t>(ch1) << 8 | static_cast<uint32_t>(ch2) << 16 | static_cast<uint32_t>(ch3) << 24;
@@ -109,3 +111,5 @@ struct DDS_HEADER_DXT10
uint32_t arraySize;
uint32_t miscFlags2;
};
} // namespace image

View File

@@ -7,6 +7,10 @@
#include <map>
#include <memory>
using namespace image;
namespace
{
const std::map<ImageFormatId, ImageFormatId> DDS_CONVERSION_TABLE{
{ImageFormatId::R8_G8_B8, ImageFormatId::B8_G8_R8_X8},
};
@@ -220,7 +224,10 @@ public:
std::unique_ptr<Texture> m_converted_texture;
bool m_use_dx10_extension;
};
} // namespace
namespace image
{
DdsWriter::~DdsWriter() = default;
bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat)
@@ -238,3 +245,4 @@ void DdsWriter::DumpImage(std::ostream& stream, const Texture* texture)
DdsWriterInternal internal(stream, texture);
internal.DumpImage();
}
} // namespace image

View File

@@ -1,7 +1,10 @@
#pragma once
#include "IImageWriter.h"
class DdsWriter final : public IImageWriter
#include "ImageWriter.h"
namespace image
{
class DdsWriter final : public ImageWriter
{
public:
~DdsWriter() override;
@@ -10,3 +13,4 @@ public:
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace image

View File

@@ -2,6 +2,8 @@
#include <cstring>
namespace image
{
Dx12TextureLoader::Dx12TextureLoader()
: m_format(oat::DXGI_FORMAT_UNKNOWN),
m_type(TextureType::T_2D),
@@ -102,3 +104,4 @@ std::unique_ptr<Texture> Dx12TextureLoader::LoadTexture(const void* data)
return texture;
}
} // namespace image

View File

@@ -6,6 +6,8 @@
#include <memory>
#include <unordered_map>
namespace image
{
class Dx12TextureLoader
{
public:
@@ -32,3 +34,4 @@ private:
unsigned m_height;
unsigned m_depth;
};
} // namespace image

View File

@@ -2,6 +2,8 @@
#include <cstring>
namespace image
{
Dx9TextureLoader::Dx9TextureLoader()
: m_format(oat::D3DFMT_UNKNOWN),
m_type(TextureType::T_2D),
@@ -102,3 +104,4 @@ std::unique_ptr<Texture> Dx9TextureLoader::LoadTexture(const void* data)
return texture;
}
} // namespace image

View File

@@ -5,6 +5,8 @@
#include <memory>
namespace image
{
class Dx9TextureLoader
{
public:
@@ -29,3 +31,4 @@ private:
unsigned m_height;
unsigned m_depth;
};
} // namespace image

View File

@@ -1,21 +0,0 @@
#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

@@ -1,5 +1,7 @@
#include "ImageFormat.h"
namespace image
{
ImageFormat::ImageFormat(const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat)
: m_id(id),
m_d3d_format(d3dFormat),
@@ -173,3 +175,4 @@ const ImageFormat* const ImageFormat::ALL_FORMATS[static_cast<unsigned>(ImageFor
&FORMAT_BC4,
&FORMAT_BC5,
};
} // namespace image

View File

@@ -6,6 +6,8 @@
#include <cstddef>
#include <cstdint>
namespace image
{
enum class ImageFormatId
{
UNKNOWN = -1,
@@ -120,3 +122,4 @@ public:
[[nodiscard]] size_t GetPitch(unsigned mipLevel, unsigned width) const override;
[[nodiscard]] size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
};
} // namespace image

View File

@@ -0,0 +1,24 @@
#pragma once
#include "Image/Texture.h"
#include <ostream>
#include <string>
namespace image
{
class ImageWriter
{
public:
ImageWriter() = default;
virtual ~ImageWriter() = default;
ImageWriter(const ImageWriter& other) = default;
ImageWriter(ImageWriter&& other) noexcept = default;
ImageWriter& operator=(const ImageWriter& other) = default;
ImageWriter& operator=(ImageWriter&& other) noexcept = default;
virtual bool SupportsImageFormat(const ImageFormat* imageFormat) = 0;
virtual std::string GetFileExtension() = 0;
virtual void DumpImage(std::ostream& stream, const Texture* texture) = 0;
};
} // namespace image

View File

@@ -8,7 +8,9 @@
#include <iostream>
#include <type_traits>
namespace iwi
using namespace image;
namespace
{
const ImageFormat* GetFormat6(int8_t format)
{
@@ -47,17 +49,20 @@ namespace iwi
return nullptr;
}
std::unique_ptr<Texture> LoadIwi6(std::istream& stream)
std::optional<IwiLoaderResult> LoadIwi6(std::istream& stream)
{
iwi6::IwiHeader header{};
stream.read(reinterpret_cast<char*>(&header), sizeof(header));
if (stream.gcount() != sizeof(header))
return nullptr;
{
con::error("IWI header corrupted");
return std::nullopt;
}
const auto* format = GetFormat6(header.format);
if (format == nullptr)
return nullptr;
return std::nullopt;
auto width = header.dimensions[0];
auto height = header.dimensions[1];
@@ -74,7 +79,7 @@ namespace iwi
texture->Allocate();
auto currentFileSize = sizeof(iwi6::IwiHeader) + sizeof(IwiVersion);
auto currentFileSize = sizeof(iwi6::IwiHeader) + sizeof(IwiVersionHeader);
const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1;
for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--)
@@ -86,18 +91,30 @@ namespace iwi
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
con::error("Iwi has invalid file size for picmip {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
stream.read(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel);
if (stream.gcount() != sizeOfMipLevel)
{
con::error("Unexpected eof of iwi in mip level {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
}
return texture;
CommonIwiMetaData meta{
.m_no_picmip = (header.flags & iwi6::IwiFlags::IMG_FLAG_NOPICMIP) != 0,
.m_streaming = (header.flags & iwi6::IwiFlags::IMG_FLAG_STREAMING) != 0,
.m_clamp_u = (header.flags & iwi6::IwiFlags::IMG_FLAG_CLAMP_U) != 0,
.m_clamp_v = (header.flags & iwi6::IwiFlags::IMG_FLAG_CLAMP_V) != 0,
.m_dynamic = (header.flags & iwi6::IwiFlags::IMG_FLAG_DYNAMIC) != 0,
};
return IwiLoaderResult{
.m_version = IwiVersion::IWI_6,
.m_meta = meta,
.m_texture = std::move(texture),
};
}
const ImageFormat* GetFormat8(int8_t format)
@@ -145,17 +162,20 @@ namespace iwi
return nullptr;
}
std::unique_ptr<Texture> LoadIwi8(std::istream& stream)
std::optional<IwiLoaderResult> LoadIwi8(std::istream& stream)
{
iwi8::IwiHeader header{};
stream.read(reinterpret_cast<char*>(&header), sizeof(header));
if (stream.gcount() != sizeof(header))
return nullptr;
{
con::error("IWI header corrupted");
return std::nullopt;
}
const auto* format = GetFormat8(header.format);
if (format == nullptr)
return nullptr;
return std::nullopt;
auto width = header.dimensions[0];
auto height = header.dimensions[1];
@@ -178,17 +198,17 @@ namespace iwi
else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_1D)
{
con::error("Iwi has unsupported map type 1D");
return nullptr;
return std::nullopt;
}
else
{
con::error("Iwi has unsupported map type");
return nullptr;
return std::nullopt;
}
texture->Allocate();
auto currentFileSize = sizeof(iwi8::IwiHeader) + sizeof(IwiVersion);
auto currentFileSize = sizeof(iwi8::IwiHeader) + sizeof(IwiVersionHeader);
const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1;
for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--)
@@ -200,18 +220,30 @@ namespace iwi
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
con::error("Iwi has invalid file size for picmip {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
stream.read(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel);
if (stream.gcount() != sizeOfMipLevel)
{
con::error("Unexpected eof of iwi in mip level {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
}
return texture;
CommonIwiMetaData meta{
.m_no_picmip = (header.flags & iwi8::IwiFlags::IMG_FLAG_NOPICMIP) != 0,
.m_streaming = (header.flags & iwi8::IwiFlags::IMG_FLAG_STREAMING) != 0,
.m_clamp_u = (header.flags & iwi8::IwiFlags::IMG_FLAG_CLAMP_U) != 0,
.m_clamp_v = (header.flags & iwi8::IwiFlags::IMG_FLAG_CLAMP_V) != 0,
.m_dynamic = (header.flags & iwi8::IwiFlags::IMG_FLAG_DYNAMIC) != 0,
};
return IwiLoaderResult{
.m_version = IwiVersion::IWI_8,
.m_meta = meta,
.m_texture = std::move(texture),
};
}
const ImageFormat* GetFormat13(int8_t format)
@@ -256,17 +288,20 @@ namespace iwi
return nullptr;
}
std::unique_ptr<Texture> LoadIwi13(std::istream& stream)
std::optional<IwiLoaderResult> LoadIwi13(std::istream& stream)
{
iwi13::IwiHeader header{};
stream.read(reinterpret_cast<char*>(&header), sizeof(header));
if (stream.gcount() != sizeof(header))
return nullptr;
{
con::error("IWI header corrupted");
return std::nullopt;
}
const auto* format = GetFormat6(header.format);
if (format == nullptr)
return nullptr;
return std::nullopt;
auto width = header.dimensions[0];
auto height = header.dimensions[1];
@@ -283,7 +318,7 @@ namespace iwi
texture->Allocate();
auto currentFileSize = sizeof(iwi13::IwiHeader) + sizeof(IwiVersion);
auto currentFileSize = sizeof(iwi13::IwiHeader) + sizeof(IwiVersionHeader);
const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1;
for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--)
@@ -295,18 +330,31 @@ namespace iwi
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
con::error("Iwi has invalid file size for picmip {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
stream.read(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel);
if (stream.gcount() != sizeOfMipLevel)
{
con::error("Unexpected eof of iwi in mip level {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
}
return texture;
CommonIwiMetaData meta{
.m_no_picmip = (header.flags & iwi13::IwiFlags::IMG_FLAG_NOPICMIP) != 0,
.m_streaming = (header.flags & iwi13::IwiFlags::IMG_FLAG_STREAMING) != 0,
.m_clamp_u = (header.flags & iwi13::IwiFlags::IMG_FLAG_CLAMP_U) != 0,
.m_clamp_v = (header.flags & iwi13::IwiFlags::IMG_FLAG_CLAMP_V) != 0,
.m_dynamic = (header.flags & iwi13::IwiFlags::IMG_FLAG_DYNAMIC) != 0,
.m_gamma = header.gamma,
};
return IwiLoaderResult{
.m_version = IwiVersion::IWI_13,
.m_meta = meta,
.m_texture = std::move(texture),
};
}
const ImageFormat* GetFormat27(int8_t format)
@@ -353,17 +401,20 @@ namespace iwi
return nullptr;
}
std::unique_ptr<Texture> LoadIwi27(std::istream& stream)
std::optional<IwiLoaderResult> LoadIwi27(std::istream& stream)
{
iwi27::IwiHeader header{};
stream.read(reinterpret_cast<char*>(&header), sizeof(header));
if (stream.gcount() != sizeof(header))
return nullptr;
{
con::error("IWI header corrupted");
return std::nullopt;
}
const auto* format = GetFormat27(header.format);
if (format == nullptr)
return nullptr;
return std::nullopt;
auto width = header.dimensions[0];
auto height = header.dimensions[1];
@@ -380,7 +431,7 @@ namespace iwi
texture->Allocate();
auto currentFileSize = sizeof(iwi27::IwiHeader) + sizeof(IwiVersion);
auto currentFileSize = sizeof(iwi27::IwiHeader) + sizeof(IwiVersionHeader);
const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1;
for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--)
@@ -392,35 +443,54 @@ namespace iwi
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
con::error("Iwi has invalid file size for picmip {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
stream.read(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel);
if (stream.gcount() != sizeOfMipLevel)
{
con::error("Unexpected eof of iwi in mip level {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
}
return texture;
}
CommonIwiMetaData meta{
.m_no_picmip = (header.flags & iwi27::IwiFlags::IMG_FLAG_NOPICMIP) != 0,
.m_streaming = (header.flags & iwi27::IwiFlags::IMG_FLAG_STREAMING) != 0,
.m_clamp_u = (header.flags & iwi27::IwiFlags::IMG_FLAG_CLAMP_U) != 0,
.m_clamp_v = (header.flags & iwi27::IwiFlags::IMG_FLAG_CLAMP_V) != 0,
.m_dynamic = (header.flags & iwi27::IwiFlags::IMG_FLAG_DYNAMIC) != 0,
.m_gamma = header.gamma,
};
std::unique_ptr<Texture> LoadIwi(std::istream& stream)
return IwiLoaderResult{
.m_version = IwiVersion::IWI_27,
.m_meta = meta,
.m_texture = std::move(texture),
};
}
} // namespace
namespace image
{
IwiVersion iwiVersion{};
std::optional<IwiLoaderResult> LoadIwi(std::istream& stream)
{
IwiVersionHeader iwiVersionHeader{};
stream.read(reinterpret_cast<char*>(&iwiVersion), sizeof(iwiVersion));
if (stream.gcount() != sizeof(iwiVersion))
return nullptr;
stream.read(reinterpret_cast<char*>(&iwiVersionHeader), sizeof(iwiVersionHeader));
if (stream.gcount() != sizeof(iwiVersionHeader))
{
con::error("IWI version header corrupted");
return std::nullopt;
}
if (iwiVersion.tag[0] != 'I' || iwiVersion.tag[1] != 'W' || iwiVersion.tag[2] != 'i')
if (iwiVersionHeader.tag[0] != 'I' || iwiVersionHeader.tag[1] != 'W' || iwiVersionHeader.tag[2] != 'i')
{
con::error("Invalid IWI magic");
return nullptr;
return std::nullopt;
}
switch (iwiVersion.version)
switch (iwiVersionHeader.version)
{
case 6:
return LoadIwi6(stream);
@@ -438,7 +508,7 @@ namespace iwi
break;
}
con::error("Unknown IWI version {}", iwiVersion.version);
return nullptr;
con::error("Unknown IWI version {}", iwiVersionHeader.version);
return std::nullopt;
}
} // namespace iwi
} // namespace image

View File

@@ -1,11 +1,20 @@
#pragma once
#include "Image/IwiTypes.h"
#include "Image/Texture.h"
#include <istream>
#include <memory>
#include <optional>
namespace iwi
namespace image
{
std::unique_ptr<Texture> LoadIwi(std::istream& stream);
}; // namespace iwi
struct IwiLoaderResult
{
IwiVersion m_version;
CommonIwiMetaData m_meta;
std::unique_ptr<Texture> m_texture;
};
std::optional<IwiLoaderResult> LoadIwi(std::istream& stream);
}; // namespace image

View File

@@ -2,13 +2,38 @@
#include <cstdint>
struct IwiVersion
namespace image
{
enum class IwiVersion : std::uint8_t
{
// IW3
IWI_6 = 6,
// IW4, IW5
IWI_8 = 8,
// T5
IWI_13 = 13,
// T6
IWI_27 = 27
};
struct CommonIwiMetaData
{
// Always high resolution
bool m_no_picmip;
bool m_streaming;
bool m_clamp_u;
bool m_clamp_v;
bool m_dynamic;
float m_gamma;
};
struct IwiVersionHeader
{
char tag[3];
char version;
};
// IW3
namespace iwi6
{
struct IwiHeader
@@ -56,7 +81,6 @@ namespace iwi6
};
} // namespace iwi6
// IW4
namespace iwi8
{
struct IwiHeader
@@ -124,7 +148,6 @@ namespace iwi8
};
} // namespace iwi8
// T5
namespace iwi13
{
struct IwiHeader
@@ -179,7 +202,6 @@ namespace iwi13
} // namespace iwi13
// T6
namespace iwi27
{
struct IwiHeader
@@ -233,3 +255,4 @@ namespace iwi27
};
} // namespace iwi27
} // namespace image

View File

@@ -3,7 +3,7 @@
#include <cassert>
#include <ostream>
using namespace iwi13;
using namespace image::iwi13;
IwiWriter::IwiWriter() = default;
@@ -54,13 +54,13 @@ std::string IwiWriter::GetFileExtension()
void IwiWriter::WriteVersion(std::ostream& stream)
{
IwiVersion version{};
IwiVersionHeader version{};
version.tag[0] = 'I';
version.tag[1] = 'W';
version.tag[2] = 'i';
version.version = 13;
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersionHeader));
}
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
@@ -101,7 +101,7 @@ void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
if (!texture->HasMipMaps())
header.flags |= IMG_FLAG_NOMIPMAPS;
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
auto currentFileSize = sizeof(IwiVersionHeader) + sizeof(IwiHeader);
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)

View File

@@ -1,11 +1,11 @@
#pragma once
#include "IImageWriter.h"
#include "Image/IwiTypes.h"
#include "ImageWriter.h"
namespace iwi13
namespace image::iwi13
{
class IwiWriter final : public IImageWriter
class IwiWriter final : public ImageWriter
{
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
@@ -27,4 +27,4 @@ namespace iwi13
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace iwi13
} // namespace image::iwi13

View File

@@ -3,7 +3,7 @@
#include <cassert>
#include <ostream>
using namespace iwi27;
using namespace image::iwi27;
IwiWriter::IwiWriter() = default;
@@ -54,13 +54,13 @@ std::string IwiWriter::GetFileExtension()
void IwiWriter::WriteVersion(std::ostream& stream)
{
IwiVersion version{};
IwiVersionHeader version{};
version.tag[0] = 'I';
version.tag[1] = 'W';
version.tag[2] = 'i';
version.version = 27;
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersionHeader));
}
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
@@ -104,7 +104,7 @@ void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
for (auto& i : header.maxGlossForMip)
i = 0;
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
auto currentFileSize = sizeof(IwiVersionHeader) + sizeof(IwiHeader);
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)

View File

@@ -1,11 +1,11 @@
#pragma once
#include "IImageWriter.h"
#include "Image/IwiTypes.h"
#include "ImageWriter.h"
namespace iwi27
namespace image::iwi27
{
class IwiWriter final : public IImageWriter
class IwiWriter final : public ImageWriter
{
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
@@ -27,4 +27,4 @@ namespace iwi27
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace iwi27
} // namespace image::iwi27

View File

@@ -2,7 +2,7 @@
#include <cassert>
using namespace iwi6;
using namespace image::iwi6;
IwiWriter::IwiWriter() = default;
@@ -40,13 +40,13 @@ IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat)
void IwiWriter::WriteVersion(std::ostream& stream)
{
IwiVersion version{};
IwiVersionHeader version{};
version.tag[0] = 'I';
version.tag[1] = 'W';
version.tag[2] = 'i';
version.version = 6;
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersionHeader));
}
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
@@ -96,7 +96,7 @@ void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
if (!texture->HasMipMaps())
header.flags |= IMG_FLAG_NOMIPMAPS;
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
auto currentFileSize = sizeof(IwiVersionHeader) + sizeof(IwiHeader);
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)

View File

@@ -1,11 +1,11 @@
#pragma once
#include "IImageWriter.h"
#include "Image/IwiTypes.h"
#include "ImageWriter.h"
namespace iwi6
namespace image::iwi6
{
class IwiWriter final : public IImageWriter
class IwiWriter final : public ImageWriter
{
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
@@ -27,4 +27,4 @@ namespace iwi6
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace iwi6
} // namespace image::iwi6

View File

@@ -2,7 +2,7 @@
#include <cassert>
using namespace iwi8;
using namespace image::iwi8;
IwiWriter::IwiWriter() = default;
@@ -40,13 +40,13 @@ IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat)
void IwiWriter::WriteVersion(std::ostream& stream)
{
IwiVersion version{};
IwiVersionHeader version{};
version.tag[0] = 'I';
version.tag[1] = 'W';
version.tag[2] = 'i';
version.version = 8;
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersionHeader));
}
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
@@ -96,7 +96,7 @@ void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
if (!texture->HasMipMaps())
header.flags |= IMG_FLAG_NOMIPMAPS;
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
auto currentFileSize = sizeof(IwiVersionHeader) + sizeof(IwiHeader);
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)

View File

@@ -1,11 +1,11 @@
#pragma once
#include "IImageWriter.h"
#include "Image/IwiTypes.h"
#include "ImageWriter.h"
namespace iwi8
namespace image::iwi8
{
class IwiWriter final : public IImageWriter
class IwiWriter final : public ImageWriter
{
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
@@ -27,4 +27,4 @@ namespace iwi8
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace iwi8
} // namespace image::iwi8

View File

@@ -4,6 +4,8 @@
#include <cassert>
#include <cstring>
namespace image
{
// ==============================================
// ================= Texture ====================
// ==============================================
@@ -441,3 +443,4 @@ const uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int fac
return &m_data[bufferOffset];
}
} // namespace image

View File

@@ -3,6 +3,8 @@
#include <cstdint>
namespace image
{
enum class TextureType : std::uint8_t
{
T_2D,
@@ -130,3 +132,4 @@ public:
[[nodiscard]] int GetMipMapCount() const override;
};
} // namespace image

View File

@@ -2,6 +2,8 @@
#include <cassert>
namespace image
{
constexpr uint64_t TextureConverter::Mask1(const unsigned length)
{
if (length >= sizeof(uint64_t) * 8)
@@ -192,8 +194,8 @@ void TextureConverter::ConvertUnsignedToUnsigned()
SetPixelFunctions(inputFormat->m_bits_per_pixel, outputFormat->m_bits_per_pixel);
if (inputFormat->m_r_size == outputFormat->m_r_size && inputFormat->m_g_size == outputFormat->m_g_size && inputFormat->m_b_size == outputFormat->m_b_size
&& inputFormat->m_a_size == outputFormat->m_a_size)
if (inputFormat->m_r_size == outputFormat->m_r_size && inputFormat->m_g_size == outputFormat->m_g_size
&& inputFormat->m_b_size == outputFormat->m_b_size && inputFormat->m_a_size == outputFormat->m_a_size)
{
ReorderUnsignedToUnsigned();
}
@@ -220,3 +222,4 @@ std::unique_ptr<Texture> TextureConverter::Convert()
return std::move(m_output_texture);
}
} // namespace image

View File

@@ -5,6 +5,8 @@
#include <functional>
#include <memory>
namespace image
{
class TextureConverter
{
public:
@@ -29,3 +31,4 @@ private:
const ImageFormat* m_input_format;
const ImageFormat* m_output_format;
};
} // namespace image

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/IW3/IW3.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace image
{
std::unique_ptr<AssetCreator<IW3::AssetImage>> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath);
} // namespace image

View File

@@ -4,8 +4,9 @@
#include "Game/IW3/AssetMarkerIW3.h"
#include "Game/IW3/GameIW3.h"
#include "Game/IW3/IW3.h"
#include "Game/IW3/Image/ImageLoaderEmbeddedIW3.h"
#include "Game/IW3/Image/ImageLoaderExternalIW3.h"
#include "Game/IW3/XModel/LoaderXModelIW3.h"
#include "Image/AssetLoaderImageIW3.h"
#include "Localize/AssetLoaderLocalizeIW3.h"
#include "Material/LoaderMaterialIW3.h"
#include "ObjLoading.h"
@@ -95,7 +96,8 @@ namespace
collection.AddAssetCreator(xmodel::CreateLoaderIW3(memory, searchPath, zone));
collection.AddAssetCreator(material::CreateLoaderIW3(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechniqueSet>(memory));
collection.AddAssetCreator(image::CreateLoaderIW3(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderEmbeddedIW3(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderExternalIW3(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSound>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSoundCurve>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderLoadedSound>(memory));

View File

@@ -4,6 +4,8 @@
#include "Game/IW4/AssetMarkerIW4.h"
#include "Game/IW4/GameIW4.h"
#include "Game/IW4/IW4.h"
#include "Game/IW4/Image/ImageLoaderEmbeddedIW4.h"
#include "Game/IW4/Image/ImageLoaderExternalIW4.h"
#include "Game/IW4/XModel/LoaderXModelIW4.h"
#include "Leaderboard/LoaderLeaderboardIW4.h"
#include "LightDef/LightDefLoaderIW4.h"
@@ -130,7 +132,8 @@ namespace
collection.AddAssetCreator(shader::CreatePixelShaderLoaderIW4(memory, searchPath));
collection.AddAssetCreator(shader::CreateVertexShaderLoaderIW4(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechset>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderImage>(memory));
collection.AddAssetCreator(image::CreateLoaderEmbeddedIW4(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderExternalIW4(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSound>(memory));
collection.AddAssetCreator(sound_curve::CreateLoaderIW4(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderLoadedSound>(memory));

View File

@@ -1,71 +0,0 @@
#include "LoaderImageIW5.h"
#include "Game/IW5/IW5.h"
#include "Image/ImageCommon.h"
#include "Image/IwiLoader.h"
#include "Utils/Logging/Log.h"
#include <cstring>
#include <format>
#include <iostream>
#include <sstream>
using namespace IW5;
namespace
{
constexpr auto MAX_IMAGE_NAME_SIZE = 0x800;
class ImageLoader final : public AssetCreator<AssetImage>
{
public:
ImageLoader(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{
const auto fileName = image::GetFileNameForAsset(assetName, ".iwi");
const auto file = m_search_path.Open(fileName);
if (!file.IsOpen())
return AssetCreationResult::NoAction();
const auto fileSize = static_cast<size_t>(file.m_length);
const auto fileData = std::make_unique<char[]>(fileSize);
file.m_stream->read(fileData.get(), fileSize);
std::istringstream ss(std::string(fileData.get(), fileSize));
const auto texture = iwi::LoadIwi(ss);
if (!texture)
{
con::error("Failed to load texture from: {}", fileName);
return AssetCreationResult::Failure();
}
auto* image = m_memory.Alloc<GfxImage>();
image->name = m_memory.Dup(assetName.c_str());
image->noPicmip = !texture->HasMipMaps();
image->width = static_cast<uint16_t>(texture->GetWidth());
image->height = static_cast<uint16_t>(texture->GetHeight());
image->depth = static_cast<uint16_t>(texture->GetDepth());
image->texture.loadDef = m_memory.Alloc<GfxImageLoadDef>();
return AssetCreationResult::Success(context.AddAsset<AssetImage>(assetName, image));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace image
{
std::unique_ptr<AssetCreator<AssetImage>> CreateLoaderIW5(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<ImageLoader>(memory, searchPath);
}
} // namespace image

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/IW5/IW5.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace image
{
std::unique_ptr<AssetCreator<IW5::AssetImage>> CreateLoaderIW5(MemoryManager& memory, ISearchPath& searchPath);
} // namespace image

View File

@@ -4,8 +4,9 @@
#include "Game/IW5/AssetMarkerIW5.h"
#include "Game/IW5/GameIW5.h"
#include "Game/IW5/IW5.h"
#include "Game/IW5/Image/ImageLoaderEmbeddedIW5.h"
#include "Game/IW5/Image/ImageLoaderExternalIW5.h"
#include "Game/IW5/XModel/LoaderXModelIW5.h"
#include "Image/LoaderImageIW5.h"
#include "Leaderboard/LoaderLeaderboardIW5.h"
#include "Localize/LoaderLocalizeIW5.h"
#include "Material/LoaderMaterialIW5.h"
@@ -132,7 +133,8 @@ namespace
// collection.AddAssetCreator(std::make_unique<AssetLoaderVertexShader>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderVertexDecl>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechniqueSet>(memory));
collection.AddAssetCreator(image::CreateLoaderIW5(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderEmbeddedIW5(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderExternalIW5(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSound>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSoundCurve>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderLoadedSound>(memory));

View File

@@ -3,6 +3,8 @@
#include "Asset/GlobalAssetPoolsLoader.h"
#include "Game/T5/AssetMarkerT5.h"
#include "Game/T5/GameT5.h"
#include "Game/T5/Image/ImageLoaderEmbeddedT5.h"
#include "Game/T5/Image/ImageLoaderExternalT5.h"
#include "Game/T5/T5.h"
#include "Game/T5/XModel/LoaderXModelT5.h"
#include "Localize/LoaderLocalizeT5.h"
@@ -108,7 +110,8 @@ namespace
collection.AddAssetCreator(xmodel::CreateLoaderT5(memory, searchPath, zone));
collection.AddAssetCreator(material::CreateLoaderT5(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechniqueSet>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderImage>(memory));
collection.AddAssetCreator(image::CreateLoaderEmbeddedT5(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderExternalT5(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSoundBank>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSoundPatch>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderClipMapPvs>(memory));

View File

@@ -1,79 +0,0 @@
#include "LoaderImageT6.h"
#include "Game/T6/CommonT6.h"
#include "Game/T6/T6.h"
#include "Image/ImageCommon.h"
#include "Image/IwiLoader.h"
#include "Utils/Logging/Log.h"
#include <cstring>
#include <format>
#include <iostream>
#include <sstream>
#include <zlib.h>
using namespace T6;
namespace
{
class ImageLoader final : public AssetCreator<AssetImage>
{
public:
ImageLoader(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{
const auto fileName = image::GetFileNameForAsset(assetName, ".iwi");
const auto file = m_search_path.Open(fileName);
if (!file.IsOpen())
return AssetCreationResult::NoAction();
const auto fileSize = static_cast<size_t>(file.m_length);
const auto fileData = std::make_unique<char[]>(fileSize);
file.m_stream->read(fileData.get(), static_cast<std::streamsize>(fileSize));
const auto dataHash = static_cast<unsigned>(crc32(0u, reinterpret_cast<const Bytef*>(fileData.get()), static_cast<unsigned>(fileSize)));
std::istringstream ss(std::string(fileData.get(), fileSize));
const auto texture = iwi::LoadIwi(ss);
if (!texture)
{
con::error("Failed to load texture from: {}", fileName);
return AssetCreationResult::Failure();
}
auto* image = m_memory.Alloc<GfxImage>();
image->name = m_memory.Dup(assetName.c_str());
image->hash = Common::R_HashString(image->name, 0);
image->delayLoadPixels = true;
image->noPicmip = !texture->HasMipMaps();
image->width = static_cast<uint16_t>(texture->GetWidth());
image->height = static_cast<uint16_t>(texture->GetHeight());
image->depth = static_cast<uint16_t>(texture->GetDepth());
image->streaming = 1;
image->streamedParts[0].levelCount = 1;
image->streamedParts[0].levelSize = static_cast<uint32_t>(fileSize);
image->streamedParts[0].hash = dataHash & 0x1FFFFFFF;
image->streamedPartCount = 1;
return AssetCreationResult::Success(context.AddAsset<AssetImage>(assetName, image));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace image
{
std::unique_ptr<AssetCreator<AssetImage>> CreateLoaderT6(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<ImageLoader>(memory, searchPath);
}
} // namespace image

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/T6/T6.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace image
{
std::unique_ptr<AssetCreator<T6::AssetImage>> CreateLoaderT6(MemoryManager& memory, ISearchPath& searchPath);
} // namespace image

View File

@@ -7,12 +7,13 @@
#include "Game/T6/CommonT6.h"
#include "Game/T6/GameAssetPoolT6.h"
#include "Game/T6/GameT6.h"
#include "Game/T6/Image/ImageLoaderEmbeddedT6.h"
#include "Game/T6/Image/ImageLoaderExternalT6.h"
#include "Game/T6/T6.h"
#include "Game/T6/XModel/LoaderXModelT6.h"
#include "Image/Dx12TextureLoader.h"
#include "Image/IwiLoader.h"
#include "Image/IwiTypes.h"
#include "Image/LoaderImageT6.h"
#include "Image/Texture.h"
#include "Leaderboard/JsonLoaderLeaderboardT6.h"
#include "Localize/LocalizeLoaderT6.h"
@@ -394,7 +395,8 @@ namespace T6
collection.AddAssetCreator(xmodel::CreateLoaderT6(memory, searchPath, zone));
collection.AddAssetCreator(material::CreateLoaderT6(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechniqueSet>(memory));
collection.AddAssetCreator(image::CreateLoaderT6(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderEmbeddedT6(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderExternalT6(memory, searchPath));
collection.AddAssetCreator(sound::CreateSoundBankLoaderT6(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSoundPatch>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderClipMapPvs>(memory));

View File

@@ -0,0 +1,89 @@
#include "ImageLoaderCommon.h"
#include "Image/ImageCommon.h"
#include "Image/IwiLoader.h"
#include "Image/Texture.h"
#include "Utils/Logging/Log.h"
#include <sstream>
#include <zlib.h>
using namespace image;
namespace
{
CommonImageLoaderResult Success(size_t iwiSize, CommonIwiMetaData meta, std::unique_ptr<Texture> texture, CommonImageLoaderHash hash)
{
return CommonImageLoaderResult{
.m_failure = false,
.m_iwi_size = iwiSize,
.m_meta = meta,
.m_texture = std::move(texture),
.m_hash = hash,
};
}
CommonImageLoaderResult NoAction()
{
return CommonImageLoaderResult{
.m_failure = false,
};
}
CommonImageLoaderResult Failure()
{
return CommonImageLoaderResult{
.m_failure = true,
};
}
} // namespace
namespace image
{
std::optional<AssetCreationResult> CommonImageLoaderResult::GetResultIfCancelled() const
{
if (m_failure)
return AssetCreationResult::Failure();
if (!m_texture)
return AssetCreationResult::NoAction();
return std::nullopt;
}
CommonImageLoaderResult
LoadImageCommon(const std::string& imageName, ISearchPath& searchPath, IwiVersion expectedIwiVersion, CommonImageLoaderHashType hashType)
{
const auto fileName = image::GetFileNameForAsset(imageName, ".iwi");
const auto file = searchPath.Open(fileName);
if (!file.IsOpen())
return NoAction();
const auto fileSize = static_cast<size_t>(file.m_length);
std::optional<IwiLoaderResult> loaderResult;
CommonImageLoaderHash hash{};
if (hashType == CommonImageLoaderHashType::NONE)
{
loaderResult = image::LoadIwi(*file.m_stream);
}
else
{
const auto fileData = std::make_unique<char[]>(fileSize);
file.m_stream->read(fileData.get(), static_cast<std::streamsize>(fileSize));
hash.crc32 = static_cast<unsigned>(crc32(0u, reinterpret_cast<const Bytef*>(fileData.get()), static_cast<unsigned>(fileSize)));
std::istringstream inMemory(std::string(fileData.get(), fileSize));
loaderResult = image::LoadIwi(inMemory);
}
if (!loaderResult)
{
con::error("Failed to load texture from: {}", fileName);
return Failure();
}
return Success(fileSize, loaderResult->m_meta, std::move(loaderResult->m_texture), hash);
}
} // namespace image

View File

@@ -0,0 +1,39 @@
#pragma once
#include "Asset/AssetCreationResult.h"
#include "Image/IwiTypes.h"
#include "Image/Texture.h"
#include "SearchPath/ISearchPath.h"
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
namespace image
{
enum class CommonImageLoaderHashType
{
NONE,
CRC32
};
union CommonImageLoaderHash
{
uint32_t crc32;
};
struct CommonImageLoaderResult
{
std::optional<AssetCreationResult> GetResultIfCancelled() const;
bool m_failure;
size_t m_iwi_size;
CommonIwiMetaData m_meta;
std::unique_ptr<Texture> m_texture;
CommonImageLoaderHash m_hash;
};
CommonImageLoaderResult
LoadImageCommon(const std::string& imageName, ISearchPath& searchPath, IwiVersion expectedIwiVersion, CommonImageLoaderHashType hashType);
} // namespace image

View File

@@ -1,24 +1,64 @@
#include "AssetLoaderImageIW3.h"
#options GAME (IW3, IW4, IW5, T5, T6)
#include "Game/IW3/IW3.h"
#filename "Game/" + GAME + "/Image/ImageLoaderEmbedded" + GAME + ".cpp"
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#endif
#if defined(FEATURE_IW3)
#define IWI_NS iwi6
#define FLAG_CUBE IMG_FLAG_CUBEMAP
#define FLAG_3D IMG_FLAG_VOLMAP
#elif defined(FEATURE_IW4) || defined(FEATURE_IW5)
#define IWI_NS iwi8
#define FLAG_CUBE IMG_FLAG_MAPTYPE_CUBE
#define FLAG_3D IMG_FLAG_MAPTYPE_3D
#elif defined(FEATURE_T5)
#define IWI_NS iwi13
#define FLAG_CUBE IMG_FLAG_CUBEMAP
#define FLAG_3D IMG_FLAG_VOLMAP
#elif defined(FEATURE_T6)
#define IWI_NS iwi27
#define FLAG_CUBE IMG_FLAG_CUBEMAP
#define FLAG_3D IMG_FLAG_VOLMAP
#endif
// This file was templated.
// See ImageLoaderEmbedded.cpp.template.
// Do not modify, changes will be lost.
#set LOADER_HEADER "\"ImageLoaderEmbedded" + GAME + ".h\""
#include LOADER_HEADER
#set COMMON_HEADER "\"Game/" + GAME + "/Common" + GAME + ".h\""
#include COMMON_HEADER
#include "Image/DdsLoader.h"
#include "Image/ImageCommon.h"
#include "Image/IwiTypes.h"
#include "Pool/GlobalAssetPool.h"
#include "Utils/Logging/Log.h"
#include <algorithm>
#include <cstring>
#include <format>
#include <iostream>
using namespace IW3;
using namespace GAME;
using namespace image;
namespace
{
class ImageLoader final : public AssetCreator<AssetImage>
#set LOADER_CLASS "ImageLoader" + GAME
class LOADER_CLASS final : public AssetCreator<AssetImage>
{
public:
ImageLoader(MemoryManager& memory, ISearchPath& searchPath)
LOADER_CLASS(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
@@ -31,14 +71,11 @@ namespace
if (assetName.empty() || assetName[0] != '*')
return AssetCreationResult::NoAction();
std::string safeAssetName = assetName;
std::ranges::replace(safeAssetName, '*', '_');
const auto file = m_search_path.Open(std::format("images/{}.dds", safeAssetName));
const auto file = m_search_path.Open(image::GetFileNameForAsset(assetName, ".dds"));
if (!file.IsOpen())
return AssetCreationResult::NoAction();
const auto texture = dds::LoadDds(*file.m_stream);
const auto texture = image::LoadDds(*file.m_stream);
if (!texture)
{
con::error("Failed to load dds file for image asset \"{}\"", assetName);
@@ -58,7 +95,9 @@ namespace
image->height = static_cast<uint16_t>(texture->GetHeight());
image->depth = static_cast<uint16_t>(texture->GetDepth());
image->category = IMG_CATEGORY_AUTO_GENERATED;
#ifndef FEATURE_IW5
image->delayLoadPixels = false;
#endif
switch (texture->GetTextureType())
{
@@ -91,15 +130,23 @@ namespace
loadDef->levelCount = static_cast<char>(mipCount);
loadDef->flags = 0;
if (!texture->HasMipMaps())
loadDef->flags |= iwi6::IMG_FLAG_NOMIPMAPS;
loadDef->flags |= IWI_NS::IMG_FLAG_NOMIPMAPS;
if (texture->GetTextureType() == TextureType::T_CUBE)
loadDef->flags |= iwi6::IMG_FLAG_CUBEMAP;
loadDef->flags |= IWI_NS::FLAG_CUBE;
if (texture->GetTextureType() == TextureType::T_3D)
loadDef->flags |= iwi6::IMG_FLAG_VOLMAP;
loadDef->flags |= IWI_NS::FLAG_3D;
#if defined(FEATURE_IW3)
loadDef->dimensions[0] = image->width;
loadDef->dimensions[1] = image->height;
loadDef->dimensions[2] = image->depth;
#endif
#if defined(FEATURE_T6)
loadDef->format = static_cast<int>(texture->GetFormat()->GetDxgiFormat());
#else
loadDef->format = static_cast<int>(texture->GetFormat()->GetD3DFormat());
#endif
loadDef->resourceSize = static_cast<unsigned>(dataSize);
char* currentDataBuffer = loadDef->data;
@@ -117,7 +164,6 @@ namespace
return AssetCreationResult::Success(context.AddAsset<AssetImage>(assetName, image));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
@@ -125,8 +171,9 @@ namespace
namespace image
{
std::unique_ptr<AssetCreator<AssetImage>> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath)
#set LOADER_METHOD "CreateLoaderEmbedded" + GAME
std::unique_ptr<AssetCreator<AssetImage>> LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<ImageLoader>(memory, searchPath);
return std::make_unique<LOADER_CLASS>(memory, searchPath);
}
} // namespace image

View File

@@ -0,0 +1,23 @@
#options GAME (IW3, IW4, IW5, T5, T6)
#filename "Game/" + GAME + "/Image/ImageLoaderEmbedded" + GAME + ".h"
// This file was templated.
// See ImageLoaderEmbedded.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Asset/IAssetCreator.h"
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
#include GAME_HEADER
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace image
{
#set LOADER_METHOD "CreateLoaderEmbedded" + GAME
std::unique_ptr<AssetCreator<GAME::AssetImage>> LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath);
} // namespace image

View File

@@ -0,0 +1,111 @@
#options GAME (IW3, IW4, IW5, T5, T6)
#filename "Game/" + GAME + "/Image/ImageLoaderExternal" + GAME + ".cpp"
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#endif
#if defined(FEATURE_IW3)
#define IWI_VERSION IWI_6
#elif defined(FEATURE_IW4) || defined(FEATURE_IW5)
#define IWI_VERSION IWI_8
#elif defined(FEATURE_T5)
#define IWI_VERSION IWI_13
#elif defined(FEATURE_T6)
#define IWI_VERSION IWI_27
#endif
#if defined(FEATURE_T6)
#define HASH_TYPE CRC32
#else
#define HASH_TYPE NONE
#endif
// This file was templated.
// See ImageLoaderExternal.cpp.template.
// Do not modify, changes will be lost.
#set LOADER_HEADER "\"ImageLoaderExternal" + GAME + ".h\""
#include LOADER_HEADER
#set COMMON_HEADER "\"Game/" + GAME + "/Common" + GAME + ".h\""
#include COMMON_HEADER
#include "Image/ImageLoaderCommon.h"
#include "Utils/Logging/Log.h"
#include <cstring>
using namespace GAME;
using namespace image;
namespace
{
#set LOADER_CLASS "ImageLoader" + GAME
class LOADER_CLASS final : public AssetCreator<AssetImage>
{
public:
LOADER_CLASS(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{
const auto loadingResult = LoadImageCommon(assetName, m_search_path, IwiVersion::IWI_VERSION, CommonImageLoaderHashType::HASH_TYPE);
const auto earlyReturn = loadingResult.GetResultIfCancelled();
if (earlyReturn)
return *earlyReturn;
const auto* texture = loadingResult.m_texture.get();
auto* image = m_memory.Alloc<GfxImage>();
image->name = m_memory.Dup(assetName.c_str());
#ifdef FEATURE_t6
image->hash = Common::R_HashString(image->name, 0);
#endif
#ifndef FEATURE_IW5
image->delayLoadPixels = true;
#endif
image->noPicmip = loadingResult.m_meta.m_no_picmip;
image->width = static_cast<uint16_t>(texture->GetWidth());
image->height = static_cast<uint16_t>(texture->GetHeight());
image->depth = static_cast<uint16_t>(texture->GetDepth());
#ifdef FEATURE_T6
image->streaming = 1;
image->streamedParts[0].levelCount = 1;
image->streamedParts[0].levelSize = static_cast<uint32_t>(loadingResult.m_iwi_size);
image->streamedParts[0].hash = loadingResult.m_hash.crc32 & 0x1FFFFFFF;
image->streamedPartCount = 1;
#endif
image->texture.loadDef = m_memory.Alloc<GfxImageLoadDef>();
return AssetCreationResult::Success(context.AddAsset<AssetImage>(assetName, image));
}
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace image
{
#set LOADER_METHOD "CreateLoaderExternal" + GAME
std::unique_ptr<AssetCreator<AssetImage>> LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<LOADER_CLASS>(memory, searchPath);
}
} // namespace image

View File

@@ -0,0 +1,23 @@
#options GAME (IW3, IW4, IW5, T5, T6)
#filename "Game/" + GAME + "/Image/ImageLoaderExternal" + GAME + ".h"
// This file was templated.
// See ImageLoaderExternal.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Asset/IAssetCreator.h"
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
#include GAME_HEADER
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace image
{
#set LOADER_METHOD "CreateLoaderExternal" + GAME
std::unique_ptr<AssetCreator<GAME::AssetImage>> LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath);
} // namespace image

View File

@@ -16,6 +16,7 @@
#include <format>
using namespace IW3;
using namespace image;
namespace
{
@@ -26,15 +27,15 @@ namespace
const auto& loadDef = *image.texture.loadDef;
textureLoader.Width(loadDef.dimensions[0]).Height(loadDef.dimensions[1]).Depth(loadDef.dimensions[2]);
if (loadDef.flags & iwi6::IMG_FLAG_VOLMAP)
if (loadDef.flags & image::iwi6::IMG_FLAG_VOLMAP)
textureLoader.Type(TextureType::T_3D);
else if (loadDef.flags & iwi6::IMG_FLAG_CUBEMAP)
else if (loadDef.flags & image::iwi6::IMG_FLAG_CUBEMAP)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::D3DFORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi6::IMG_FLAG_NOMIPMAPS));
textureLoader.HasMipMaps(!(loadDef.flags & image::iwi6::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
@@ -48,7 +49,8 @@ namespace
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
auto loadResult = image::LoadIwi(*filePathImage.m_stream);
return loadResult ? std::move(loadResult->m_texture) : nullptr;
}
std::unique_ptr<Texture> LoadImageData(ISearchPath& searchPath, const GfxImage& image)

View File

@@ -2,7 +2,7 @@
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW3/IW3.h"
#include "Image/IImageWriter.h"
#include "Image/ImageWriter.h"
#include <memory>
@@ -17,6 +17,6 @@ namespace image
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW3::AssetImage::Type>& asset) override;
private:
std::unique_ptr<IImageWriter> m_writer;
std::unique_ptr<ImageWriter> m_writer;
};
} // namespace image

View File

@@ -13,6 +13,7 @@
#include <format>
using namespace IW4;
using namespace image;
namespace
{
@@ -23,15 +24,15 @@ namespace
const auto& loadDef = *image.texture.loadDef;
textureLoader.Width(image.width).Height(image.height).Depth(image.depth);
if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_3D)
if ((loadDef.flags & image::iwi8::IMG_FLAG_MAPTYPE_MASK) == image::iwi8::IMG_FLAG_MAPTYPE_3D)
textureLoader.Type(TextureType::T_3D);
else if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_CUBE)
else if ((loadDef.flags & image::iwi8::IMG_FLAG_MAPTYPE_MASK) == image::iwi8::IMG_FLAG_MAPTYPE_CUBE)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::D3DFORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi8::IMG_FLAG_NOMIPMAPS));
textureLoader.HasMipMaps(!(loadDef.flags & image::iwi8::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
@@ -45,7 +46,8 @@ namespace
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
auto loadResult = image::LoadIwi(*filePathImage.m_stream);
return loadResult ? std::move(loadResult->m_texture) : nullptr;
}
std::unique_ptr<Texture> LoadImageData(ISearchPath& searchPath, const GfxImage& image)

View File

@@ -2,7 +2,7 @@
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW4/IW4.h"
#include "Image/IImageWriter.h"
#include "Image/ImageWriter.h"
#include <memory>
@@ -17,6 +17,6 @@ namespace image
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW4::AssetImage::Type>& asset) override;
private:
std::unique_ptr<IImageWriter> m_writer;
std::unique_ptr<ImageWriter> m_writer;
};
} // namespace image

View File

@@ -13,6 +13,7 @@
#include <format>
using namespace IW5;
using namespace image;
namespace
{
@@ -24,15 +25,15 @@ namespace
textureLoader.Width(image.width).Height(image.height).Depth(image.depth);
if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_3D)
if ((loadDef.flags & image::iwi8::IMG_FLAG_MAPTYPE_MASK) == image::iwi8::IMG_FLAG_MAPTYPE_3D)
textureLoader.Type(TextureType::T_3D);
else if ((loadDef.flags & iwi8::IMG_FLAG_MAPTYPE_MASK) == iwi8::IMG_FLAG_MAPTYPE_CUBE)
else if ((loadDef.flags & image::iwi8::IMG_FLAG_MAPTYPE_MASK) == image::iwi8::IMG_FLAG_MAPTYPE_CUBE)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::D3DFORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi8::IMG_FLAG_NOMIPMAPS));
textureLoader.HasMipMaps(!(loadDef.flags & image::iwi8::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
@@ -46,7 +47,8 @@ namespace
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
auto loadResult = image::LoadIwi(*filePathImage.m_stream);
return loadResult ? std::move(loadResult->m_texture) : nullptr;
}
std::unique_ptr<Texture> LoadImageData(ISearchPath& searchPath, const GfxImage& image)

View File

@@ -2,7 +2,7 @@
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW5/IW5.h"
#include "Image/IImageWriter.h"
#include "Image/ImageWriter.h"
#include <memory>
@@ -17,6 +17,6 @@ namespace image
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW5::AssetImage::Type>& asset) override;
private:
std::unique_ptr<IImageWriter> m_writer;
std::unique_ptr<ImageWriter> m_writer;
};
} // namespace image

View File

@@ -13,6 +13,7 @@
#include <format>
using namespace T5;
using namespace image;
namespace
{
@@ -23,15 +24,15 @@ namespace
const auto& loadDef = *image.texture.loadDef;
textureLoader.Width(image.width).Height(image.height).Depth(image.depth);
if (loadDef.flags & iwi13::IMG_FLAG_VOLMAP)
if (loadDef.flags & image::iwi13::IMG_FLAG_VOLMAP)
textureLoader.Type(TextureType::T_3D);
else if (loadDef.flags & iwi13::IMG_FLAG_CUBEMAP)
else if (loadDef.flags & image::iwi13::IMG_FLAG_CUBEMAP)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::D3DFORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi13::IMG_FLAG_NOMIPMAPS));
textureLoader.HasMipMaps(!(loadDef.flags & image::iwi13::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
@@ -45,7 +46,8 @@ namespace
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
auto loadResult = image::LoadIwi(*filePathImage.m_stream);
return loadResult ? std::move(loadResult->m_texture) : nullptr;
}
std::unique_ptr<Texture> LoadImageData(ISearchPath& searchPath, const GfxImage& image)

View File

@@ -2,7 +2,7 @@
#include "Dumping/AbstractAssetDumper.h"
#include "Game/T5/T5.h"
#include "Image/IImageWriter.h"
#include "Image/ImageWriter.h"
#include <memory>
@@ -17,6 +17,6 @@ namespace image
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<T5::AssetImage::Type>& asset) override;
private:
std::unique_ptr<IImageWriter> m_writer;
std::unique_ptr<ImageWriter> m_writer;
};
} // namespace image

View File

@@ -14,6 +14,7 @@
#include <format>
using namespace T6;
using namespace image;
namespace
{
@@ -24,15 +25,15 @@ namespace
const auto& loadDef = *image.texture.loadDef;
textureLoader.Width(image.width).Height(image.height).Depth(image.depth);
if (loadDef.flags & iwi27::IMG_FLAG_VOLMAP)
if (loadDef.flags & image::iwi27::IMG_FLAG_VOLMAP)
textureLoader.Type(TextureType::T_3D);
else if (loadDef.flags & iwi27::IMG_FLAG_CUBEMAP)
else if (loadDef.flags & image::iwi27::IMG_FLAG_CUBEMAP)
textureLoader.Type(TextureType::T_CUBE);
else
textureLoader.Type(TextureType::T_2D);
textureLoader.Format(static_cast<oat::DXGI_FORMAT>(loadDef.format));
textureLoader.HasMipMaps(!(loadDef.flags & iwi27::IMG_FLAG_NOMIPMAPS));
textureLoader.HasMipMaps(!(loadDef.flags & image::iwi27::IMG_FLAG_NOMIPMAPS));
return textureLoader.LoadTexture(loadDef.data);
}
@@ -46,11 +47,11 @@ namespace
if (ipakStream)
{
auto loadedTexture = iwi::LoadIwi(*ipakStream);
auto loadResult = image::LoadIwi(*ipakStream);
ipakStream->close();
if (loadedTexture != nullptr)
return loadedTexture;
if (loadResult)
return std::move(loadResult->m_texture);
}
}
}
@@ -63,7 +64,8 @@ namespace
return nullptr;
}
return iwi::LoadIwi(*filePathImage.m_stream);
auto loadResult = image::LoadIwi(*filePathImage.m_stream);
return loadResult ? std::move(loadResult->m_texture) : nullptr;
}
std::unique_ptr<Texture> LoadImageData(ISearchPath& searchPath, const GfxImage& image)

View File

@@ -2,7 +2,7 @@
#include "Dumping/AbstractAssetDumper.h"
#include "Game/T6/T6.h"
#include "Image/IImageWriter.h"
#include "Image/ImageWriter.h"
#include <memory>
@@ -17,6 +17,6 @@ namespace image
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<T6::AssetImage::Type>& asset) override;
private:
std::unique_ptr<IImageWriter> m_writer;
std::unique_ptr<ImageWriter> m_writer;
};
} // namespace image

View File

@@ -3,6 +3,7 @@ ObjLoadingTests = {}
function ObjLoadingTests:include(includes)
if includes:handle(self:name()) then
includedirs {
"%{wks.location}/src/ObjLoading",
path.join(TestFolder(), "ObjLoadingTests")
}
end

View File

@@ -0,0 +1,57 @@
#include "Game/IW3/Image/ImageLoaderEmbeddedIW3.h"
#include "Game/IW3/GameIW3.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace IW3;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderEmbeddedIW3: Can parse dds", "[iw3][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW3/Image/TestImage.dds";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderEmbeddedIW3(memory, searchPath);
auto result = loader->CreateAsset("*testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "*testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
REQUIRE(image->texture.loadDef);
REQUIRE(image->texture.loadDef->resourceSize > 0);
}
} // namespace

View File

@@ -0,0 +1,54 @@
#include "Game/IW3/Image/ImageLoaderExternalIW3.h"
#include "Game/IW3/GameIW3.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace IW3;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderExternalIW3: Can parse iwi", "[iw3][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW3/Image/TestImage.iwi";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::IW3, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderExternalIW3(memory, searchPath);
auto result = loader->CreateAsset("testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
}
} // namespace

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,57 @@
#include "Game/IW4/Image/ImageLoaderEmbeddedIW4.h"
#include "Game/IW4/GameIW4.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace IW4;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderEmbeddedIW4: Can parse dds", "[iw4][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW4/Image/TestImage.dds";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderEmbeddedIW4(memory, searchPath);
auto result = loader->CreateAsset("*testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "*testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
REQUIRE(image->texture.loadDef);
REQUIRE(image->texture.loadDef->resourceSize > 0);
}
} // namespace

View File

@@ -0,0 +1,54 @@
#include "Game/IW4/Image/ImageLoaderExternalIW4.h"
#include "Game/IW4/GameIW4.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace IW4;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderExternalIW4: Can parse iwi", "[iw4][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW4/Image/TestImage.iwi";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderExternalIW4(memory, searchPath);
auto result = loader->CreateAsset("testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
}
} // namespace

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,57 @@
#include "Game/IW5/Image/ImageLoaderEmbeddedIW5.h"
#include "Game/IW5/GameIW5.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace IW5;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderEmbeddedIW5: Can parse dds", "[iw5][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW5/Image/TestImage.dds";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderEmbeddedIW5(memory, searchPath);
auto result = loader->CreateAsset("*testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "*testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
REQUIRE(image->texture.loadDef);
REQUIRE(image->texture.loadDef->resourceSize > 0);
}
} // namespace

View File

@@ -0,0 +1,54 @@
#include "Game/IW5/Image/ImageLoaderExternalIW5.h"
#include "Game/IW5/GameIW5.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace IW5;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderExternalIW5: Can parse iwi", "[iw5][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/IW5/Image/TestImage.iwi";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::IW5, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderExternalIW5(memory, searchPath);
auto result = loader->CreateAsset("testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
}
} // namespace

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,57 @@
#include "Game/T5/Image/ImageLoaderEmbeddedT5.h"
#include "Game/T5/GameT5.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace T5;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderEmbeddedT5: Can parse dds", "[t5][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/T5/Image/TestImage.dds";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::T5, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderEmbeddedT5(memory, searchPath);
auto result = loader->CreateAsset("*testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "*testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
REQUIRE(image->texture.loadDef);
REQUIRE(image->texture.loadDef->resourceSize > 0);
}
} // namespace

View File

@@ -0,0 +1,54 @@
#include "Game/T5/Image/ImageLoaderExternalT5.h"
#include "Game/T5/GameT5.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace T5;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderExternalT5: Can parse iwi", "[t5][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/T5/Image/TestImage.iwi";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::T5, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderExternalT5(memory, searchPath);
auto result = loader->CreateAsset("testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
}
} // namespace

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,58 @@
#include "Game/T6/Image/ImageLoaderEmbeddedT6.h"
#include "Game/T6/GameT6.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace T6;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderEmbeddedT6: Can parse dds", "[t6][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/T6/Image/TestImage.dds";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/_testimage.dds", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderEmbeddedT6(memory, searchPath);
auto result = loader->CreateAsset("*testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "*testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
REQUIRE(image->streamedPartCount == 0);
REQUIRE(image->texture.loadDef);
REQUIRE(image->texture.loadDef->resourceSize > 0);
}
} // namespace

View File

@@ -0,0 +1,57 @@
#include "Game/T6/Image/ImageLoaderExternalT6.h"
#include "Game/T6/GameT6.h"
#include "OatTestPaths.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/MemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
namespace fs = std::filesystem;
using namespace T6;
using namespace std::literals;
namespace
{
TEST_CASE("ImageLoaderExternalT6: Can parse iwi", "[t6][image]")
{
MockSearchPath searchPath;
const auto filePath = oat::paths::GetTestDirectory() / "ObjLoadingTests/Game/T6/Image/TestImage.iwi";
const auto fileSize = static_cast<size_t>(fs::file_size(filePath));
std::ifstream file(filePath, std::ios::binary);
REQUIRE(file.is_open());
const auto data = std::make_unique<char[]>(fileSize);
file.read(data.get(), fileSize);
searchPath.AddFileData("images/testimage.iwi", std::string(data.get(), fileSize));
Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC);
MemoryManager memory;
AssetCreatorCollection creatorCollection(zone);
IgnoredAssetLookup ignoredAssetLookup;
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
auto loader = image::CreateLoaderExternalT6(memory, searchPath);
auto result = loader->CreateAsset("testimage", context);
REQUIRE(result.HasBeenSuccessful());
const auto* assetInfo = reinterpret_cast<XAssetInfo<GfxImage>*>(result.GetAssetInfo());
const auto* image = assetInfo->Asset();
REQUIRE(image->name == "testimage"s);
REQUIRE(image->width == 64);
REQUIRE(image->height == 64);
REQUIRE(image->depth == 1);
REQUIRE(image->streamedPartCount == 1);
REQUIRE(image->streamedParts[0].levelSize == 2112);
REQUIRE(image->streamedParts[0].hash == (0x386422F2 & 0x1FFFFFFF));
}
} // namespace

Binary file not shown.

Binary file not shown.