2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-01-12 03:31:49 +00:00

feat: add external image loader for every supported game

This commit is contained in:
Jan Laupetin
2026-01-02 19:51:44 +01:00
parent da2a76f6da
commit 33584f6f7b
22 changed files with 369 additions and 228 deletions

View File

@@ -49,17 +49,20 @@ namespace
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];
@@ -88,18 +91,30 @@ namespace
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
con::error("Iwi has invalid file size for picmip {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
stream.read(reinterpret_cast<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)
@@ -147,17 +162,20 @@ namespace
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];
@@ -180,12 +198,12 @@ namespace
else if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_1D)
{
con::error("Iwi has unsupported map type 1D");
return nullptr;
return std::nullopt;
}
else
{
con::error("Iwi has unsupported map type");
return nullptr;
return std::nullopt;
}
texture->Allocate();
@@ -202,18 +220,30 @@ namespace
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
con::error("Iwi has invalid file size for picmip {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
stream.read(reinterpret_cast<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)
@@ -258,17 +288,20 @@ namespace
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];
@@ -297,18 +330,31 @@ namespace
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
con::error("Iwi has invalid file size for picmip {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
stream.read(reinterpret_cast<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)
@@ -355,17 +401,20 @@ namespace
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];
@@ -394,35 +443,51 @@ namespace
&& currentFileSize != header.fileSizeForPicmip[currentMipLevel])
{
con::error("Iwi has invalid file size for picmip {}", currentMipLevel);
return nullptr;
return std::nullopt;
}
stream.read(reinterpret_cast<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,
};
return IwiLoaderResult{
.m_version = IwiVersion::IWI_27,
.m_meta = meta,
.m_texture = std::move(texture),
};
}
} // namespace
namespace image
{
std::unique_ptr<Texture> LoadIwi(std::istream& stream)
std::optional<IwiLoaderResult> LoadIwi(std::istream& stream)
{
IwiVersionHeader iwiVersionHeader{};
stream.read(reinterpret_cast<char*>(&iwiVersionHeader), sizeof(iwiVersionHeader));
if (stream.gcount() != sizeof(iwiVersionHeader))
return nullptr;
{
con::error("IWI version header corrupted");
return std::nullopt;
}
if (iwiVersionHeader.tag[0] != 'I' || iwiVersionHeader.tag[1] != 'W' || iwiVersionHeader.tag[2] != 'i')
{
con::error("Invalid IWI magic");
return nullptr;
return std::nullopt;
}
switch (iwiVersionHeader.version)
@@ -444,6 +509,6 @@ namespace image
}
con::error("Unknown IWI version {}", iwiVersionHeader.version);
return nullptr;
return std::nullopt;
}
} // namespace image

View File

@@ -1,11 +1,20 @@
#pragma once
#include "Image/IwiTypes.h"
#include "Image/Texture.h"
#include <istream>
#include <memory>
#include <optional>
namespace image
{
std::unique_ptr<Texture> LoadIwi(std::istream& stream);
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

@@ -16,6 +16,18 @@ namespace image
IWI_27 = 27
};
struct CommonIwiMetaData
{
// Always high resolution
bool m_no_picmip;
bool m_streaming;
bool m_clamp_u;
bool m_clamp_v;
bool m_dynamic;
float m_gamma;
};
struct IwiVersionHeader
{
char tag[3];