fix: t6 modman textures (#849)

* feat: dynamically decompress bc5 textures for modman

* chore: restructure image format class

* chore: keep dds file conversions

* chore: convert all kinds of webgl unsupported formats

* chore: add decompressors for remaining formats

* chore: always set full alpha if available on bc4 and bc5 decompression
This commit is contained in:
Jan
2026-06-22 07:02:35 +02:00
committed by GitHub
parent 087ce0c208
commit 255c424aac
28 changed files with 2373 additions and 237 deletions
+75 -43
View File
@@ -5,12 +5,14 @@
#include <cstddef>
#include <cstdint>
#include <utility>
namespace image
{
enum class ImageFormatId : std::uint8_t
{
R8_G8_B8,
B8_G8_R8,
B8_G8_R8_X8,
R8_G8_B8_A8,
B8_G8_R8_A8,
@@ -24,12 +26,9 @@ namespace image
BC4,
BC5,
MAX,
UNKNOWN
MAX
};
const char* GetImageFormatName(ImageFormatId id);
enum class ImageFormatType : std::uint8_t
{
UNKNOWN,
@@ -42,17 +41,12 @@ namespace image
class ImageFormat
{
ImageFormatId m_id;
oat::D3DFORMAT m_d3d_format;
oat::DXGI_FORMAT m_dxgi_format;
protected:
ImageFormat(ImageFormatId id, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat);
public:
static const ImageFormat* GetImageFormatById(ImageFormatId id);
virtual ~ImageFormat() = default;
[[nodiscard]] ImageFormatId GetId() const;
[[nodiscard]] const std::string& GetName() const;
[[nodiscard]] oat::D3DFORMAT GetD3DFormat() const;
[[nodiscard]] oat::DXGI_FORMAT GetDxgiFormat() const;
@@ -60,36 +54,26 @@ namespace image
[[nodiscard]] virtual size_t GetPitch(unsigned mipLevel, unsigned width) const = 0;
[[nodiscard]] virtual size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const = 0;
static const ImageFormatUnsigned FORMAT_R8_G8_B8;
static const ImageFormatUnsigned FORMAT_B8_G8_R8_X8;
static const ImageFormatUnsigned FORMAT_R8_G8_B8_A8;
static const ImageFormatUnsigned FORMAT_B8_G8_R8_A8;
static const ImageFormatUnsigned FORMAT_A8;
static const ImageFormatUnsigned FORMAT_R16_G16_B16_A16_FLOAT; // TODO: Float not unsigned
static const ImageFormatUnsigned FORMAT_R8;
static const ImageFormatUnsigned FORMAT_R8_A8;
static const ImageFormatBlockCompressed FORMAT_BC1;
static const ImageFormatBlockCompressed FORMAT_BC2;
static const ImageFormatBlockCompressed FORMAT_BC3;
static const ImageFormatBlockCompressed FORMAT_BC4;
static const ImageFormatBlockCompressed FORMAT_BC5;
static const ImageFormat* const ALL_FORMATS[static_cast<unsigned>(ImageFormatId::MAX)];
[[nodiscard]] virtual bool HasR() const = 0;
[[nodiscard]] virtual bool HasG() const = 0;
[[nodiscard]] virtual bool HasB() const = 0;
[[nodiscard]] virtual bool HasA() const = 0;
protected:
ImageFormat(ImageFormatId id, std::string name, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat);
private:
ImageFormatId m_id;
std::string m_name;
oat::D3DFORMAT m_d3d_format;
oat::DXGI_FORMAT m_dxgi_format;
};
class ImageFormatUnsigned final : public ImageFormat
{
public:
unsigned m_bits_per_pixel;
unsigned m_r_offset;
unsigned m_r_size;
unsigned m_g_offset;
unsigned m_g_size;
unsigned m_b_offset;
unsigned m_b_size;
unsigned m_a_offset;
unsigned m_a_size;
ImageFormatUnsigned(ImageFormatId id,
std::string name,
oat::D3DFORMAT d3dFormat,
oat::DXGI_FORMAT dxgiFormat,
unsigned bitsPerPixel,
@@ -106,22 +90,70 @@ namespace image
[[nodiscard]] size_t GetPitch(unsigned mipLevel, unsigned width) const override;
[[nodiscard]] size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
[[nodiscard]] bool HasR() const;
[[nodiscard]] bool HasG() const;
[[nodiscard]] bool HasB() const;
[[nodiscard]] bool HasA() const;
[[nodiscard]] bool HasR() const override;
[[nodiscard]] bool HasG() const override;
[[nodiscard]] bool HasB() const override;
[[nodiscard]] bool HasA() const override;
unsigned m_bits_per_pixel;
unsigned m_r_offset;
unsigned m_r_size;
unsigned m_g_offset;
unsigned m_g_size;
unsigned m_b_offset;
unsigned m_b_size;
unsigned m_a_offset;
unsigned m_a_size;
};
class ImageFormatBlockCompressed final : public ImageFormat
{
public:
unsigned m_block_size;
unsigned m_bits_per_block;
ImageFormatBlockCompressed(ImageFormatId id, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat, unsigned blockSize, unsigned bitsPerBlock);
ImageFormatBlockCompressed(ImageFormatId id,
std::string name,
oat::D3DFORMAT d3dFormat,
oat::DXGI_FORMAT dxgiFormat,
unsigned blockSize,
unsigned bitsPerBlock,
bool hasR,
bool hasG,
bool hasB,
bool hasA);
[[nodiscard]] ImageFormatType GetType() const override;
[[nodiscard]] size_t GetPitch(unsigned mipLevel, unsigned width) const override;
[[nodiscard]] size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
[[nodiscard]] bool HasR() const override;
[[nodiscard]] bool HasG() const override;
[[nodiscard]] bool HasB() const override;
[[nodiscard]] bool HasA() const override;
unsigned m_block_size;
unsigned m_bits_per_block;
bool m_has_r;
bool m_has_g;
bool m_has_b;
bool m_has_a;
};
namespace format
{
extern const ImageFormatUnsigned R8_G8_B8;
extern const ImageFormatUnsigned B8_G8_R8;
extern const ImageFormatUnsigned B8_G8_R8_X8;
extern const ImageFormatUnsigned R8_G8_B8_A8;
extern const ImageFormatUnsigned B8_G8_R8_A8;
extern const ImageFormatUnsigned A8;
extern const ImageFormatUnsigned R16_G16_B16_A16_FLOAT; // TODO: Float not unsigned
extern const ImageFormatUnsigned R8;
extern const ImageFormatUnsigned R8_A8;
extern const ImageFormatBlockCompressed BC1;
extern const ImageFormatBlockCompressed BC2;
extern const ImageFormatBlockCompressed BC3;
extern const ImageFormatBlockCompressed BC4;
extern const ImageFormatBlockCompressed BC5;
extern const ImageFormat* const ALL[std::to_underlying(ImageFormatId::MAX)];
} // namespace format
} // namespace image