2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-01-09 02:01:50 +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,110 +2,114 @@
#include <cstdint>
constexpr uint32_t MakeFourCc(const char ch0, const char ch1, const char ch2, const char ch3)
namespace image
{
return static_cast<uint32_t>(ch0) | static_cast<uint32_t>(ch1) << 8 | static_cast<uint32_t>(ch2) << 16 | static_cast<uint32_t>(ch3) << 24;
}
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;
}
enum DDP_FLAGS
{
DDPF_ALPHAPIXELS = 0x1,
DDPF_ALPHA = 0x2,
DDPF_FOURCC = 0x4,
DDPF_RGB = 0x40,
DDPF_YUV = 0x200,
DDPF_LUMINANCE = 0x20000
};
enum DDP_FLAGS
{
DDPF_ALPHAPIXELS = 0x1,
DDPF_ALPHA = 0x2,
DDPF_FOURCC = 0x4,
DDPF_RGB = 0x40,
DDPF_YUV = 0x200,
DDPF_LUMINANCE = 0x20000
};
enum DDS_HEADER_FLAGS
{
DDSD_CAPS = 0x1,
DDSD_HEIGHT = 0x2,
DDSD_WIDTH = 0x4,
DDSD_PITCH = 0x8,
DDSD_PIXELFORMAT = 0x1000,
DDSD_MIPMAPCOUNT = 0x20000,
DDSD_LINEARSIZE = 0x80000,
DDSD_DEPTH = 0x800000,
};
enum DDS_HEADER_FLAGS
{
DDSD_CAPS = 0x1,
DDSD_HEIGHT = 0x2,
DDSD_WIDTH = 0x4,
DDSD_PITCH = 0x8,
DDSD_PIXELFORMAT = 0x1000,
DDSD_MIPMAPCOUNT = 0x20000,
DDSD_LINEARSIZE = 0x80000,
DDSD_DEPTH = 0x800000,
};
enum DDS_HEADER_CAPS
{
DDSCAPS_COMPLEX = 0x8,
DDSCAPS_TEXTURE = 0x1000,
DDSCAPS_MIPMAP = 0x400000,
};
enum DDS_HEADER_CAPS
{
DDSCAPS_COMPLEX = 0x8,
DDSCAPS_TEXTURE = 0x1000,
DDSCAPS_MIPMAP = 0x400000,
};
enum DDS_HEADER_CAPS2
{
DDSCAPS2_CUBEMAP = 0x200,
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
DDSCAPS2_VOLUME = 0x200000,
};
enum DDS_HEADER_CAPS2
{
DDSCAPS2_CUBEMAP = 0x200,
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
DDSCAPS2_VOLUME = 0x200000,
};
struct DDS_PIXELFORMAT
{
uint32_t dwSize;
uint32_t dwFlags;
uint32_t dwFourCC;
uint32_t dwRGBBitCount;
uint32_t dwRBitMask;
uint32_t dwGBitMask;
uint32_t dwBBitMask;
uint32_t dwABitMask;
};
struct DDS_PIXELFORMAT
{
uint32_t dwSize;
uint32_t dwFlags;
uint32_t dwFourCC;
uint32_t dwRGBBitCount;
uint32_t dwRBitMask;
uint32_t dwGBitMask;
uint32_t dwBBitMask;
uint32_t dwABitMask;
};
struct DDS_HEADER
{
uint32_t dwSize;
uint32_t dwFlags;
uint32_t dwHeight;
uint32_t dwWidth;
uint32_t dwPitchOrLinearSize;
uint32_t dwDepth;
uint32_t dwMipMapCount;
uint32_t dwReserved1[11];
DDS_PIXELFORMAT ddspf;
uint32_t dwCaps;
uint32_t dwCaps2;
uint32_t dwCaps3;
uint32_t dwCaps4;
uint32_t dwReserved2;
};
struct DDS_HEADER
{
uint32_t dwSize;
uint32_t dwFlags;
uint32_t dwHeight;
uint32_t dwWidth;
uint32_t dwPitchOrLinearSize;
uint32_t dwDepth;
uint32_t dwMipMapCount;
uint32_t dwReserved1[11];
DDS_PIXELFORMAT ddspf;
uint32_t dwCaps;
uint32_t dwCaps2;
uint32_t dwCaps3;
uint32_t dwCaps4;
uint32_t dwReserved2;
};
enum D3D10_RESOURCE_DIMENSION
{
D3D10_RESOURCE_DIMENSION_UNKNOWN,
D3D10_RESOURCE_DIMENSION_BUFFER,
D3D10_RESOURCE_DIMENSION_TEXTURE1D,
D3D10_RESOURCE_DIMENSION_TEXTURE2D,
D3D10_RESOURCE_DIMENSION_TEXTURE3D
};
enum D3D10_RESOURCE_DIMENSION
{
D3D10_RESOURCE_DIMENSION_UNKNOWN,
D3D10_RESOURCE_DIMENSION_BUFFER,
D3D10_RESOURCE_DIMENSION_TEXTURE1D,
D3D10_RESOURCE_DIMENSION_TEXTURE2D,
D3D10_RESOURCE_DIMENSION_TEXTURE3D
};
enum DDS_HEADER_DXT10_MISC
{
DDS_RESOURCE_MISC_TEXTURECUBE = 0x4
};
enum DDS_HEADER_DXT10_MISC
{
DDS_RESOURCE_MISC_TEXTURECUBE = 0x4
};
enum DDS_HEADER_DXT10_MISC2
{
DDS_ALPHA_MODE_UNKNOWN = 0x0,
DDS_ALPHA_MODE_STRAIGHT = 0x1,
DDS_ALPHA_MODE_PREMULTIPLIED = 0x2,
DDS_ALPHA_MODE_OPAQUE = 0x3,
DDS_ALPHA_MODE_CUSTOM = 0x4,
};
enum DDS_HEADER_DXT10_MISC2
{
DDS_ALPHA_MODE_UNKNOWN = 0x0,
DDS_ALPHA_MODE_STRAIGHT = 0x1,
DDS_ALPHA_MODE_PREMULTIPLIED = 0x2,
DDS_ALPHA_MODE_OPAQUE = 0x3,
DDS_ALPHA_MODE_CUSTOM = 0x4,
};
struct DDS_HEADER_DXT10
{
oat::DXGI_FORMAT dxgiFormat;
D3D10_RESOURCE_DIMENSION resourceDimension;
uint32_t miscFlag;
uint32_t arraySize;
uint32_t miscFlags2;
};
struct DDS_HEADER_DXT10
{
oat::DXGI_FORMAT dxgiFormat;
D3D10_RESOURCE_DIMENSION resourceDimension;
uint32_t miscFlag;
uint32_t arraySize;
uint32_t miscFlags2;
};
} // namespace image

View File

@@ -7,234 +7,242 @@
#include <map>
#include <memory>
const std::map<ImageFormatId, ImageFormatId> DDS_CONVERSION_TABLE{
{ImageFormatId::R8_G8_B8, ImageFormatId::B8_G8_R8_X8},
};
using namespace image;
class DdsWriterInternal
namespace
{
public:
static bool SupportsImageFormat(const ImageFormat* imageFormat)
const std::map<ImageFormatId, ImageFormatId> DDS_CONVERSION_TABLE{
{ImageFormatId::R8_G8_B8, ImageFormatId::B8_G8_R8_X8},
};
class DdsWriterInternal
{
return true;
}
static std::string GetFileExtension()
{
return ".dds";
}
DdsWriterInternal(std::ostream& stream, const Texture* texture)
: m_stream(stream),
m_texture(texture),
m_use_dx10_extension(false)
{
}
void DumpImage()
{
ConvertTextureIfNecessary();
DDS_HEADER header{};
PopulateDdsHeader(header);
constexpr auto magic = MakeFourCc('D', 'D', 'S', ' ');
m_stream.write(reinterpret_cast<const char*>(&magic), sizeof(magic));
m_stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
if (m_use_dx10_extension)
public:
static bool SupportsImageFormat(const ImageFormat* imageFormat)
{
DDS_HEADER_DXT10 dxt10{};
PopulateDxt10Header(dxt10);
m_stream.write(reinterpret_cast<const char*>(&dxt10), sizeof(dxt10));
return true;
}
const auto mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
static std::string GetFileExtension()
{
const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel);
const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount();
m_stream.write(reinterpret_cast<const char*>(buffer), static_cast<std::streamsize>(mipLevelSize));
}
}
static constexpr unsigned Mask1(const unsigned length)
{
if (length >= sizeof(unsigned) * 8)
return UINT32_MAX;
return UINT32_MAX >> (sizeof(unsigned) * 8 - length);
}
void PopulatePixelFormatBlockCompressed(DDS_PIXELFORMAT& pf, const ImageFormatBlockCompressed* format)
{
pf.dwSize = sizeof(DDS_PIXELFORMAT);
pf.dwFlags = DDPF_FOURCC;
pf.dwRGBBitCount = 0;
pf.dwRBitMask = 0;
pf.dwGBitMask = 0;
pf.dwBBitMask = 0;
pf.dwABitMask = 0;
// Use standard pixel format for DXT1-5 for maximum compatibility and only otherwise use DX10 extension
switch (format->GetDxgiFormat())
{
case oat::DXGI_FORMAT_BC1_UNORM:
pf.dwFourCC = MakeFourCc('D', 'X', 'T', '1');
break;
case oat::DXGI_FORMAT_BC2_UNORM:
pf.dwFourCC = MakeFourCc('D', 'X', 'T', '3');
break;
case oat::DXGI_FORMAT_BC3_UNORM:
pf.dwFourCC = MakeFourCc('D', 'X', 'T', '5');
break;
default:
m_use_dx10_extension = true;
pf.dwFourCC = MakeFourCc('D', 'X', '1', '0');
break;
}
}
static void PopulatePixelFormatUnsigned(DDS_PIXELFORMAT& pf, const ImageFormatUnsigned* format)
{
pf.dwSize = sizeof(DDS_PIXELFORMAT);
pf.dwFourCC = 0;
pf.dwRGBBitCount = format->m_bits_per_pixel;
pf.dwRBitMask = format->HasR() ? Mask1(format->m_r_size) << format->m_r_offset : 0;
pf.dwGBitMask = format->HasG() ? Mask1(format->m_g_size) << format->m_g_offset : 0;
pf.dwBBitMask = format->HasB() ? Mask1(format->m_b_size) << format->m_b_offset : 0;
pf.dwABitMask = format->HasA() ? Mask1(format->m_a_size) << format->m_a_offset : 0;
pf.dwFlags = 0;
if (format->HasA())
pf.dwFlags |= DDPF_ALPHAPIXELS;
if (format->HasR() && !format->HasG() && !format->HasB())
pf.dwFlags |= DDPF_LUMINANCE;
else
pf.dwFlags |= DDPF_RGB;
}
void PopulatePixelFormat(DDS_PIXELFORMAT& pf)
{
const auto* format = m_texture->GetFormat();
switch (format->GetType())
{
case ImageFormatType::BLOCK_COMPRESSED:
PopulatePixelFormatBlockCompressed(pf, dynamic_cast<const ImageFormatBlockCompressed*>(format));
break;
case ImageFormatType::UNSIGNED:
PopulatePixelFormatUnsigned(pf, dynamic_cast<const ImageFormatUnsigned*>(format));
break;
default:
assert(false);
break;
}
}
void PopulateDdsHeader(DDS_HEADER& header)
{
header.dwSize = sizeof(header);
header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
if (m_texture->HasMipMaps())
header.dwFlags |= DDSD_MIPMAPCOUNT;
if (m_texture->GetFormat()->GetType() == ImageFormatType::BLOCK_COMPRESSED)
header.dwFlags |= DDSD_LINEARSIZE;
else
header.dwFlags |= DDSD_PITCH;
if (m_texture->GetDepth() > 1)
header.dwFlags |= DDSD_DEPTH;
header.dwHeight = m_texture->GetHeight();
header.dwWidth = m_texture->GetWidth();
header.dwDepth = m_texture->GetDepth();
header.dwPitchOrLinearSize = static_cast<uint32_t>(m_texture->GetFormat()->GetPitch(0, m_texture->GetWidth()));
header.dwMipMapCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
PopulatePixelFormat(header.ddspf);
header.dwCaps = DDSCAPS_TEXTURE;
if (m_texture->HasMipMaps())
header.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
if (m_texture->GetTextureType() == TextureType::T_CUBE)
header.dwCaps |= DDSCAPS_COMPLEX;
header.dwCaps2 = 0;
if (m_texture->GetTextureType() == TextureType::T_CUBE)
{
header.dwCaps2 |= DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX | DDSCAPS2_CUBEMAP_POSITIVEY
| DDSCAPS2_CUBEMAP_NEGATIVEY | DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ;
return ".dds";
}
header.dwCaps3 = 0;
header.dwCaps4 = 0;
header.dwReserved2 = 0;
}
void PopulateDxt10Header(DDS_HEADER_DXT10& header) const
{
header.dxgiFormat = m_texture->GetFormat()->GetDxgiFormat();
header.miscFlag = 0;
header.miscFlags2 = 0;
switch (m_texture->GetTextureType())
DdsWriterInternal(std::ostream& stream, const Texture* texture)
: m_stream(stream),
m_texture(texture),
m_use_dx10_extension(false)
{
case TextureType::T_2D:
header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
header.arraySize = 1;
break;
case TextureType::T_CUBE:
header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
header.arraySize = 6;
header.miscFlag |= DDS_RESOURCE_MISC_TEXTURECUBE;
break;
case TextureType::T_3D:
header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D;
header.arraySize = 1;
break;
}
}
void ConvertTextureIfNecessary()
{
const auto entry = DDS_CONVERSION_TABLE.find(m_texture->GetFormat()->GetId());
if (entry != DDS_CONVERSION_TABLE.end())
void DumpImage()
{
TextureConverter converter(m_texture, ImageFormat::ALL_FORMATS[static_cast<unsigned>(entry->second)]);
m_converted_texture = converter.Convert();
m_texture = m_converted_texture.get();
ConvertTextureIfNecessary();
DDS_HEADER header{};
PopulateDdsHeader(header);
constexpr auto magic = MakeFourCc('D', 'D', 'S', ' ');
m_stream.write(reinterpret_cast<const char*>(&magic), sizeof(magic));
m_stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
if (m_use_dx10_extension)
{
DDS_HEADER_DXT10 dxt10{};
PopulateDxt10Header(dxt10);
m_stream.write(reinterpret_cast<const char*>(&dxt10), sizeof(dxt10));
}
const auto mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
{
const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel);
const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount();
m_stream.write(reinterpret_cast<const char*>(buffer), static_cast<std::streamsize>(mipLevelSize));
}
}
}
std::ostream& m_stream;
const Texture* m_texture;
std::unique_ptr<Texture> m_converted_texture;
bool m_use_dx10_extension;
};
static constexpr unsigned Mask1(const unsigned length)
{
if (length >= sizeof(unsigned) * 8)
return UINT32_MAX;
DdsWriter::~DdsWriter() = default;
return UINT32_MAX >> (sizeof(unsigned) * 8 - length);
}
bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat)
void PopulatePixelFormatBlockCompressed(DDS_PIXELFORMAT& pf, const ImageFormatBlockCompressed* format)
{
pf.dwSize = sizeof(DDS_PIXELFORMAT);
pf.dwFlags = DDPF_FOURCC;
pf.dwRGBBitCount = 0;
pf.dwRBitMask = 0;
pf.dwGBitMask = 0;
pf.dwBBitMask = 0;
pf.dwABitMask = 0;
// Use standard pixel format for DXT1-5 for maximum compatibility and only otherwise use DX10 extension
switch (format->GetDxgiFormat())
{
case oat::DXGI_FORMAT_BC1_UNORM:
pf.dwFourCC = MakeFourCc('D', 'X', 'T', '1');
break;
case oat::DXGI_FORMAT_BC2_UNORM:
pf.dwFourCC = MakeFourCc('D', 'X', 'T', '3');
break;
case oat::DXGI_FORMAT_BC3_UNORM:
pf.dwFourCC = MakeFourCc('D', 'X', 'T', '5');
break;
default:
m_use_dx10_extension = true;
pf.dwFourCC = MakeFourCc('D', 'X', '1', '0');
break;
}
}
static void PopulatePixelFormatUnsigned(DDS_PIXELFORMAT& pf, const ImageFormatUnsigned* format)
{
pf.dwSize = sizeof(DDS_PIXELFORMAT);
pf.dwFourCC = 0;
pf.dwRGBBitCount = format->m_bits_per_pixel;
pf.dwRBitMask = format->HasR() ? Mask1(format->m_r_size) << format->m_r_offset : 0;
pf.dwGBitMask = format->HasG() ? Mask1(format->m_g_size) << format->m_g_offset : 0;
pf.dwBBitMask = format->HasB() ? Mask1(format->m_b_size) << format->m_b_offset : 0;
pf.dwABitMask = format->HasA() ? Mask1(format->m_a_size) << format->m_a_offset : 0;
pf.dwFlags = 0;
if (format->HasA())
pf.dwFlags |= DDPF_ALPHAPIXELS;
if (format->HasR() && !format->HasG() && !format->HasB())
pf.dwFlags |= DDPF_LUMINANCE;
else
pf.dwFlags |= DDPF_RGB;
}
void PopulatePixelFormat(DDS_PIXELFORMAT& pf)
{
const auto* format = m_texture->GetFormat();
switch (format->GetType())
{
case ImageFormatType::BLOCK_COMPRESSED:
PopulatePixelFormatBlockCompressed(pf, dynamic_cast<const ImageFormatBlockCompressed*>(format));
break;
case ImageFormatType::UNSIGNED:
PopulatePixelFormatUnsigned(pf, dynamic_cast<const ImageFormatUnsigned*>(format));
break;
default:
assert(false);
break;
}
}
void PopulateDdsHeader(DDS_HEADER& header)
{
header.dwSize = sizeof(header);
header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
if (m_texture->HasMipMaps())
header.dwFlags |= DDSD_MIPMAPCOUNT;
if (m_texture->GetFormat()->GetType() == ImageFormatType::BLOCK_COMPRESSED)
header.dwFlags |= DDSD_LINEARSIZE;
else
header.dwFlags |= DDSD_PITCH;
if (m_texture->GetDepth() > 1)
header.dwFlags |= DDSD_DEPTH;
header.dwHeight = m_texture->GetHeight();
header.dwWidth = m_texture->GetWidth();
header.dwDepth = m_texture->GetDepth();
header.dwPitchOrLinearSize = static_cast<uint32_t>(m_texture->GetFormat()->GetPitch(0, m_texture->GetWidth()));
header.dwMipMapCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
PopulatePixelFormat(header.ddspf);
header.dwCaps = DDSCAPS_TEXTURE;
if (m_texture->HasMipMaps())
header.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
if (m_texture->GetTextureType() == TextureType::T_CUBE)
header.dwCaps |= DDSCAPS_COMPLEX;
header.dwCaps2 = 0;
if (m_texture->GetTextureType() == TextureType::T_CUBE)
{
header.dwCaps2 |= DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX | DDSCAPS2_CUBEMAP_POSITIVEY
| DDSCAPS2_CUBEMAP_NEGATIVEY | DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ;
}
header.dwCaps3 = 0;
header.dwCaps4 = 0;
header.dwReserved2 = 0;
}
void PopulateDxt10Header(DDS_HEADER_DXT10& header) const
{
header.dxgiFormat = m_texture->GetFormat()->GetDxgiFormat();
header.miscFlag = 0;
header.miscFlags2 = 0;
switch (m_texture->GetTextureType())
{
case TextureType::T_2D:
header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
header.arraySize = 1;
break;
case TextureType::T_CUBE:
header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D;
header.arraySize = 6;
header.miscFlag |= DDS_RESOURCE_MISC_TEXTURECUBE;
break;
case TextureType::T_3D:
header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D;
header.arraySize = 1;
break;
}
}
void ConvertTextureIfNecessary()
{
const auto entry = DDS_CONVERSION_TABLE.find(m_texture->GetFormat()->GetId());
if (entry != DDS_CONVERSION_TABLE.end())
{
TextureConverter converter(m_texture, ImageFormat::ALL_FORMATS[static_cast<unsigned>(entry->second)]);
m_converted_texture = converter.Convert();
m_texture = m_converted_texture.get();
}
}
std::ostream& m_stream;
const Texture* m_texture;
std::unique_ptr<Texture> m_converted_texture;
bool m_use_dx10_extension;
};
} // namespace
namespace image
{
return DdsWriterInternal::SupportsImageFormat(imageFormat);
}
DdsWriter::~DdsWriter() = default;
std::string DdsWriter::GetFileExtension()
{
return DdsWriterInternal::GetFileExtension();
}
bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat)
{
return DdsWriterInternal::SupportsImageFormat(imageFormat);
}
void DdsWriter::DumpImage(std::ostream& stream, const Texture* texture)
{
DdsWriterInternal internal(stream, texture);
internal.DumpImage();
}
std::string DdsWriter::GetFileExtension()
{
return DdsWriterInternal::GetFileExtension();
}
void DdsWriter::DumpImage(std::ostream& stream, const Texture* texture)
{
DdsWriterInternal internal(stream, texture);
internal.DumpImage();
}
} // namespace image

View File

@@ -1,12 +1,16 @@
#pragma once
#include "IImageWriter.h"
class DdsWriter final : public IImageWriter
#include "ImageWriter.h"
namespace image
{
public:
~DdsWriter() override;
class DdsWriter final : public ImageWriter
{
public:
~DdsWriter() override;
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override;
void DumpImage(std::ostream& stream, const Texture* texture) override;
};
} // namespace image

View File

@@ -2,103 +2,106 @@
#include <cstring>
Dx12TextureLoader::Dx12TextureLoader()
: m_format(oat::DXGI_FORMAT_UNKNOWN),
m_type(TextureType::T_2D),
m_has_mip_maps(false),
m_width(1u),
m_height(1u),
m_depth(1u)
namespace image
{
}
const ImageFormat* Dx12TextureLoader::GetFormatForDx12Format() const
{
for (const auto* i : ImageFormat::ALL_FORMATS)
Dx12TextureLoader::Dx12TextureLoader()
: m_format(oat::DXGI_FORMAT_UNKNOWN),
m_type(TextureType::T_2D),
m_has_mip_maps(false),
m_width(1u),
m_height(1u),
m_depth(1u)
{
if (i->GetDxgiFormat() == m_format)
return i;
}
return nullptr;
}
Dx12TextureLoader& Dx12TextureLoader::Format(const oat::DXGI_FORMAT format)
{
m_format = format;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::Type(const TextureType textureType)
{
m_type = textureType;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::HasMipMaps(const bool hasMipMaps)
{
m_has_mip_maps = hasMipMaps;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::Width(const unsigned width)
{
m_width = width;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::Height(const unsigned height)
{
m_height = height;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::Depth(const unsigned depth)
{
m_depth = depth;
return *this;
}
std::unique_ptr<Texture> Dx12TextureLoader::LoadTexture(const void* data)
{
const auto* format = GetFormatForDx12Format();
if (format == nullptr)
return nullptr;
std::unique_ptr<Texture> texture;
switch (m_type)
const ImageFormat* Dx12TextureLoader::GetFormatForDx12Format() const
{
case TextureType::T_2D:
texture = std::make_unique<Texture2D>(format, m_width, m_height, m_has_mip_maps);
break;
case TextureType::T_3D:
texture = std::make_unique<Texture3D>(format, m_width, m_height, m_depth, m_has_mip_maps);
break;
case TextureType::T_CUBE:
texture = std::make_unique<TextureCube>(format, m_width, m_width, m_has_mip_maps);
break;
default:
return nullptr;
}
texture->Allocate();
const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1;
const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1;
const void* currentDataOffset = data;
for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++)
{
for (auto currentFace = 0; currentFace < faceCount; currentFace++)
for (const auto* i : ImageFormat::ALL_FORMATS)
{
const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel);
memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize);
currentDataOffset = reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(currentDataOffset) + mipSize);
if (i->GetDxgiFormat() == m_format)
return i;
}
return nullptr;
}
return texture;
}
Dx12TextureLoader& Dx12TextureLoader::Format(const oat::DXGI_FORMAT format)
{
m_format = format;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::Type(const TextureType textureType)
{
m_type = textureType;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::HasMipMaps(const bool hasMipMaps)
{
m_has_mip_maps = hasMipMaps;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::Width(const unsigned width)
{
m_width = width;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::Height(const unsigned height)
{
m_height = height;
return *this;
}
Dx12TextureLoader& Dx12TextureLoader::Depth(const unsigned depth)
{
m_depth = depth;
return *this;
}
std::unique_ptr<Texture> Dx12TextureLoader::LoadTexture(const void* data)
{
const auto* format = GetFormatForDx12Format();
if (format == nullptr)
return nullptr;
std::unique_ptr<Texture> texture;
switch (m_type)
{
case TextureType::T_2D:
texture = std::make_unique<Texture2D>(format, m_width, m_height, m_has_mip_maps);
break;
case TextureType::T_3D:
texture = std::make_unique<Texture3D>(format, m_width, m_height, m_depth, m_has_mip_maps);
break;
case TextureType::T_CUBE:
texture = std::make_unique<TextureCube>(format, m_width, m_width, m_has_mip_maps);
break;
default:
return nullptr;
}
texture->Allocate();
const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1;
const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1;
const void* currentDataOffset = data;
for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++)
{
for (auto currentFace = 0; currentFace < faceCount; currentFace++)
{
const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel);
memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize);
currentDataOffset = reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(currentDataOffset) + mipSize);
}
}
return texture;
}
} // namespace image

View File

@@ -6,29 +6,32 @@
#include <memory>
#include <unordered_map>
class Dx12TextureLoader
namespace image
{
public:
Dx12TextureLoader();
class Dx12TextureLoader
{
public:
Dx12TextureLoader();
Dx12TextureLoader& Format(oat::DXGI_FORMAT format);
Dx12TextureLoader& Type(TextureType textureType);
Dx12TextureLoader& HasMipMaps(bool hasMipMaps);
Dx12TextureLoader& Width(unsigned width);
Dx12TextureLoader& Height(unsigned height);
Dx12TextureLoader& Depth(unsigned depth);
Dx12TextureLoader& Format(oat::DXGI_FORMAT format);
Dx12TextureLoader& Type(TextureType textureType);
Dx12TextureLoader& HasMipMaps(bool hasMipMaps);
Dx12TextureLoader& Width(unsigned width);
Dx12TextureLoader& Height(unsigned height);
Dx12TextureLoader& Depth(unsigned depth);
std::unique_ptr<Texture> LoadTexture(const void* data);
std::unique_ptr<Texture> LoadTexture(const void* data);
private:
[[nodiscard]] const ImageFormat* GetFormatForDx12Format() const;
private:
[[nodiscard]] const ImageFormat* GetFormatForDx12Format() const;
static std::unordered_map<ImageFormatId, ImageFormatId> m_conversion_table;
static std::unordered_map<ImageFormatId, ImageFormatId> m_conversion_table;
oat::DXGI_FORMAT m_format;
TextureType m_type;
bool m_has_mip_maps;
unsigned m_width;
unsigned m_height;
unsigned m_depth;
};
oat::DXGI_FORMAT m_format;
TextureType m_type;
bool m_has_mip_maps;
unsigned m_width;
unsigned m_height;
unsigned m_depth;
};
} // namespace image

View File

@@ -2,103 +2,106 @@
#include <cstring>
Dx9TextureLoader::Dx9TextureLoader()
: m_format(oat::D3DFMT_UNKNOWN),
m_type(TextureType::T_2D),
m_has_mip_maps(false),
m_width(1u),
m_height(1u),
m_depth(1u)
namespace image
{
}
const ImageFormat* Dx9TextureLoader::GetFormatForDx9Format() const
{
for (const auto* i : ImageFormat::ALL_FORMATS)
Dx9TextureLoader::Dx9TextureLoader()
: m_format(oat::D3DFMT_UNKNOWN),
m_type(TextureType::T_2D),
m_has_mip_maps(false),
m_width(1u),
m_height(1u),
m_depth(1u)
{
if (i->GetD3DFormat() == m_format)
return i;
}
return nullptr;
}
Dx9TextureLoader& Dx9TextureLoader::Format(const oat::D3DFORMAT format)
{
m_format = format;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::Type(const TextureType textureType)
{
m_type = textureType;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::HasMipMaps(const bool hasMipMaps)
{
m_has_mip_maps = hasMipMaps;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::Width(const unsigned width)
{
m_width = width;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::Height(const unsigned height)
{
m_height = height;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::Depth(const unsigned depth)
{
m_depth = depth;
return *this;
}
std::unique_ptr<Texture> Dx9TextureLoader::LoadTexture(const void* data)
{
const auto* format = GetFormatForDx9Format();
if (format == nullptr)
return nullptr;
std::unique_ptr<Texture> texture;
switch (m_type)
const ImageFormat* Dx9TextureLoader::GetFormatForDx9Format() const
{
case TextureType::T_2D:
texture = std::make_unique<Texture2D>(format, m_width, m_height, m_has_mip_maps);
break;
case TextureType::T_3D:
texture = std::make_unique<Texture3D>(format, m_width, m_height, m_depth, m_has_mip_maps);
break;
case TextureType::T_CUBE:
texture = std::make_unique<TextureCube>(format, m_width, m_width, m_has_mip_maps);
break;
default:
return nullptr;
}
texture->Allocate();
const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1;
const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1;
const void* currentDataOffset = data;
for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++)
{
for (auto currentFace = 0; currentFace < faceCount; currentFace++)
for (const auto* i : ImageFormat::ALL_FORMATS)
{
const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel);
memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize);
currentDataOffset = reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(currentDataOffset) + mipSize);
if (i->GetD3DFormat() == m_format)
return i;
}
return nullptr;
}
return texture;
}
Dx9TextureLoader& Dx9TextureLoader::Format(const oat::D3DFORMAT format)
{
m_format = format;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::Type(const TextureType textureType)
{
m_type = textureType;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::HasMipMaps(const bool hasMipMaps)
{
m_has_mip_maps = hasMipMaps;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::Width(const unsigned width)
{
m_width = width;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::Height(const unsigned height)
{
m_height = height;
return *this;
}
Dx9TextureLoader& Dx9TextureLoader::Depth(const unsigned depth)
{
m_depth = depth;
return *this;
}
std::unique_ptr<Texture> Dx9TextureLoader::LoadTexture(const void* data)
{
const auto* format = GetFormatForDx9Format();
if (format == nullptr)
return nullptr;
std::unique_ptr<Texture> texture;
switch (m_type)
{
case TextureType::T_2D:
texture = std::make_unique<Texture2D>(format, m_width, m_height, m_has_mip_maps);
break;
case TextureType::T_3D:
texture = std::make_unique<Texture3D>(format, m_width, m_height, m_depth, m_has_mip_maps);
break;
case TextureType::T_CUBE:
texture = std::make_unique<TextureCube>(format, m_width, m_width, m_has_mip_maps);
break;
default:
return nullptr;
}
texture->Allocate();
const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1;
const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1;
const void* currentDataOffset = data;
for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++)
{
for (auto currentFace = 0; currentFace < faceCount; currentFace++)
{
const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel);
memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize);
currentDataOffset = reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(currentDataOffset) + mipSize);
}
}
return texture;
}
} // namespace image

View File

@@ -5,27 +5,30 @@
#include <memory>
class Dx9TextureLoader
namespace image
{
public:
Dx9TextureLoader();
class Dx9TextureLoader
{
public:
Dx9TextureLoader();
Dx9TextureLoader& Format(oat::D3DFORMAT format);
Dx9TextureLoader& Type(TextureType textureType);
Dx9TextureLoader& HasMipMaps(bool hasMipMaps);
Dx9TextureLoader& Width(unsigned width);
Dx9TextureLoader& Height(unsigned height);
Dx9TextureLoader& Depth(unsigned depth);
Dx9TextureLoader& Format(oat::D3DFORMAT format);
Dx9TextureLoader& Type(TextureType textureType);
Dx9TextureLoader& HasMipMaps(bool hasMipMaps);
Dx9TextureLoader& Width(unsigned width);
Dx9TextureLoader& Height(unsigned height);
Dx9TextureLoader& Depth(unsigned depth);
std::unique_ptr<Texture> LoadTexture(const void* data);
std::unique_ptr<Texture> LoadTexture(const void* data);
private:
[[nodiscard]] const ImageFormat* GetFormatForDx9Format() const;
private:
[[nodiscard]] const ImageFormat* GetFormatForDx9Format() const;
oat::D3DFORMAT m_format;
TextureType m_type;
bool m_has_mip_maps;
unsigned m_width;
unsigned m_height;
unsigned m_depth;
};
oat::D3DFORMAT m_format;
TextureType m_type;
bool m_has_mip_maps;
unsigned m_width;
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,175 +1,178 @@
#include "ImageFormat.h"
ImageFormat::ImageFormat(const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat)
: m_id(id),
m_d3d_format(d3dFormat),
m_dxgi_format(dxgiFormat)
namespace image
{
}
ImageFormat::ImageFormat(const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat)
: m_id(id),
m_d3d_format(d3dFormat),
m_dxgi_format(dxgiFormat)
{
}
ImageFormatId ImageFormat::GetId() const
{
return m_id;
}
ImageFormatId ImageFormat::GetId() const
{
return m_id;
}
oat::D3DFORMAT ImageFormat::GetD3DFormat() const
{
return m_d3d_format;
}
oat::D3DFORMAT ImageFormat::GetD3DFormat() const
{
return m_d3d_format;
}
oat::DXGI_FORMAT ImageFormat::GetDxgiFormat() const
{
return m_dxgi_format;
}
oat::DXGI_FORMAT ImageFormat::GetDxgiFormat() const
{
return m_dxgi_format;
}
ImageFormatUnsigned::ImageFormatUnsigned(const ImageFormatId id,
const oat::D3DFORMAT d3dFormat,
const oat::DXGI_FORMAT dxgiFormat,
const unsigned bitsPerPixel,
const unsigned rOffset,
const unsigned rSize,
const unsigned gOffset,
const unsigned gSize,
const unsigned bOffset,
const unsigned bSize,
const unsigned aOffset,
const unsigned aSize)
: ImageFormat(id, d3dFormat, dxgiFormat),
m_bits_per_pixel(bitsPerPixel),
m_r_offset(rOffset),
m_r_size(rSize),
m_g_offset(gOffset),
m_g_size(gSize),
m_b_offset(bOffset),
m_b_size(bSize),
m_a_offset(aOffset),
m_a_size(aSize)
{
}
ImageFormatUnsigned::ImageFormatUnsigned(const ImageFormatId id,
const oat::D3DFORMAT d3dFormat,
const oat::DXGI_FORMAT dxgiFormat,
const unsigned bitsPerPixel,
const unsigned rOffset,
const unsigned rSize,
const unsigned gOffset,
const unsigned gSize,
const unsigned bOffset,
const unsigned bSize,
const unsigned aOffset,
const unsigned aSize)
: ImageFormat(id, d3dFormat, dxgiFormat),
m_bits_per_pixel(bitsPerPixel),
m_r_offset(rOffset),
m_r_size(rSize),
m_g_offset(gOffset),
m_g_size(gSize),
m_b_offset(bOffset),
m_b_size(bSize),
m_a_offset(aOffset),
m_a_size(aSize)
{
}
ImageFormatType ImageFormatUnsigned::GetType() const
{
return ImageFormatType::UNSIGNED;
}
ImageFormatType ImageFormatUnsigned::GetType() const
{
return ImageFormatType::UNSIGNED;
}
size_t ImageFormatUnsigned::GetPitch(const unsigned mipLevel, const unsigned width) const
{
unsigned mipWidth = width >> mipLevel;
if (mipWidth == 0)
mipWidth = 1;
size_t ImageFormatUnsigned::GetPitch(const unsigned mipLevel, const unsigned width) const
{
unsigned mipWidth = width >> mipLevel;
if (mipWidth == 0)
mipWidth = 1;
return mipWidth * m_bits_per_pixel / 8;
}
return mipWidth * m_bits_per_pixel / 8;
}
size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, const unsigned depth) const
{
unsigned mipWidth = width >> mipLevel;
unsigned mipHeight = height >> mipLevel;
unsigned mipDepth = depth >> mipLevel;
size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, const unsigned depth) const
{
unsigned mipWidth = width >> mipLevel;
unsigned mipHeight = height >> mipLevel;
unsigned mipDepth = depth >> mipLevel;
if (mipWidth == 0)
mipWidth = 1;
if (mipHeight == 0)
mipHeight = 1;
if (mipDepth == 0)
mipDepth = 1;
if (mipWidth == 0)
mipWidth = 1;
if (mipHeight == 0)
mipHeight = 1;
if (mipDepth == 0)
mipDepth = 1;
return mipWidth * mipHeight * mipDepth * m_bits_per_pixel / 8;
}
return mipWidth * mipHeight * mipDepth * m_bits_per_pixel / 8;
}
ImageFormatBlockCompressed::ImageFormatBlockCompressed(
const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat, const unsigned blockSize, const unsigned bitsPerBlock)
: ImageFormat(id, d3dFormat, dxgiFormat),
m_block_size(blockSize),
m_bits_per_block(bitsPerBlock)
{
}
ImageFormatBlockCompressed::ImageFormatBlockCompressed(
const ImageFormatId id, const oat::D3DFORMAT d3dFormat, const oat::DXGI_FORMAT dxgiFormat, const unsigned blockSize, const unsigned bitsPerBlock)
: ImageFormat(id, d3dFormat, dxgiFormat),
m_block_size(blockSize),
m_bits_per_block(bitsPerBlock)
{
}
ImageFormatType ImageFormatBlockCompressed::GetType() const
{
return ImageFormatType::BLOCK_COMPRESSED;
}
ImageFormatType ImageFormatBlockCompressed::GetType() const
{
return ImageFormatType::BLOCK_COMPRESSED;
}
size_t ImageFormatBlockCompressed::GetPitch(const unsigned mipLevel, const unsigned width) const
{
unsigned mipWidth = width >> mipLevel;
size_t ImageFormatBlockCompressed::GetPitch(const unsigned mipLevel, const unsigned width) const
{
unsigned mipWidth = width >> mipLevel;
if (mipWidth == 0)
mipWidth = 1;
if (mipWidth == 0)
mipWidth = 1;
const unsigned blockCount = (mipWidth + m_block_size - 1) / m_block_size;
const unsigned blockCount = (mipWidth + m_block_size - 1) / m_block_size;
return blockCount * m_bits_per_block / 8;
}
return blockCount * m_bits_per_block / 8;
}
size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, const unsigned depth) const
{
unsigned mipWidth = width >> mipLevel;
unsigned mipHeight = height >> mipLevel;
unsigned mipDepth = depth >> mipLevel;
size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, const unsigned depth) const
{
unsigned mipWidth = width >> mipLevel;
unsigned mipHeight = height >> mipLevel;
unsigned mipDepth = depth >> mipLevel;
if (mipWidth == 0)
mipWidth = 1;
if (mipHeight == 0)
mipHeight = 1;
if (mipDepth == 0)
mipDepth = 1;
if (mipWidth == 0)
mipWidth = 1;
if (mipHeight == 0)
mipHeight = 1;
if (mipDepth == 0)
mipDepth = 1;
const unsigned blockCount = ((mipWidth + m_block_size - 1) / m_block_size) * ((mipHeight + m_block_size - 1) / m_block_size) * mipDepth;
const unsigned blockCount = ((mipWidth + m_block_size - 1) / m_block_size) * ((mipHeight + m_block_size - 1) / m_block_size) * mipDepth;
return blockCount * m_bits_per_block / 8;
}
return blockCount * m_bits_per_block / 8;
}
bool ImageFormatUnsigned::HasR() const
{
return m_r_size > 0;
}
bool ImageFormatUnsigned::HasR() const
{
return m_r_size > 0;
}
bool ImageFormatUnsigned::HasG() const
{
return m_g_size > 0;
}
bool ImageFormatUnsigned::HasG() const
{
return m_g_size > 0;
}
bool ImageFormatUnsigned::HasB() const
{
return m_b_size > 0;
}
bool ImageFormatUnsigned::HasB() const
{
return m_b_size > 0;
}
bool ImageFormatUnsigned::HasA() const
{
return m_a_size > 0;
}
bool ImageFormatUnsigned::HasA() const
{
return m_a_size > 0;
}
const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8(ImageFormatId::R8_G8_B8, oat::D3DFMT_R8G8B8, oat::DXGI_FORMAT_UNKNOWN, 24, 0, 8, 8, 8, 16, 8, 0, 0);
const ImageFormatUnsigned
ImageFormat::FORMAT_B8_G8_R8_X8(ImageFormatId::B8_G8_R8_X8, oat::D3DFMT_X8R8G8B8, oat::DXGI_FORMAT_B8G8R8X8_UNORM, 32, 16, 8, 8, 8, 0, 8, 0, 0);
const ImageFormatUnsigned
ImageFormat::FORMAT_R8_G8_B8_A8(ImageFormatId::R8_G8_B8_A8, oat::D3DFMT_A8B8G8R8, oat::DXGI_FORMAT_R8G8B8A8_UNORM, 32, 0, 8, 8, 8, 16, 8, 24, 8);
const ImageFormatUnsigned
ImageFormat::FORMAT_B8_G8_R8_A8(ImageFormatId::B8_G8_R8_A8, oat::D3DFMT_A8R8G8B8, oat::DXGI_FORMAT_B8G8R8A8_UNORM, 32, 16, 8, 8, 8, 0, 8, 24, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_A8(ImageFormatId::A8, oat::D3DFMT_A8, oat::DXGI_FORMAT_A8_UNORM, 8, 0, 0, 0, 0, 0, 0, 0, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_R16_G16_B16_A16_FLOAT(
ImageFormatId::R16_G16_B16_A16_FLOAT, oat::D3DFMT_A16B16G16R16F, oat::DXGI_FORMAT_R16G16B16A16_FLOAT, 128, 0, 0, 0, 0, 0, 0, 0, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_R8(ImageFormatId::R8, oat::D3DFMT_L8, oat::DXGI_FORMAT_R8_UNORM, 8, 0, 8, 0, 0, 0, 0, 0, 0);
const ImageFormatUnsigned ImageFormat::FORMAT_R8_A8(ImageFormatId::R8_A8, oat::D3DFMT_A8L8, oat::DXGI_FORMAT_UNKNOWN, 16, 0, 8, 0, 0, 0, 0, 8, 8);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC1(ImageFormatId::BC1, oat::D3DFMT_DXT1, oat::DXGI_FORMAT_BC1_UNORM, 4, 64);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC2(ImageFormatId::BC2, oat::D3DFMT_DXT3, oat::DXGI_FORMAT_BC2_UNORM, 4, 128);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(ImageFormatId::BC3, oat::D3DFMT_DXT5, oat::DXGI_FORMAT_BC3_UNORM, 4, 128);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC4(ImageFormatId::BC4, oat::D3DFMT_UNKNOWN, oat::DXGI_FORMAT_BC4_UNORM, 4, 64);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC5(ImageFormatId::BC5, oat::D3DFMT_UNKNOWN, oat::DXGI_FORMAT_BC5_UNORM, 4, 128);
const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8(ImageFormatId::R8_G8_B8, oat::D3DFMT_R8G8B8, oat::DXGI_FORMAT_UNKNOWN, 24, 0, 8, 8, 8, 16, 8, 0, 0);
const ImageFormatUnsigned
ImageFormat::FORMAT_B8_G8_R8_X8(ImageFormatId::B8_G8_R8_X8, oat::D3DFMT_X8R8G8B8, oat::DXGI_FORMAT_B8G8R8X8_UNORM, 32, 16, 8, 8, 8, 0, 8, 0, 0);
const ImageFormatUnsigned
ImageFormat::FORMAT_R8_G8_B8_A8(ImageFormatId::R8_G8_B8_A8, oat::D3DFMT_A8B8G8R8, oat::DXGI_FORMAT_R8G8B8A8_UNORM, 32, 0, 8, 8, 8, 16, 8, 24, 8);
const ImageFormatUnsigned
ImageFormat::FORMAT_B8_G8_R8_A8(ImageFormatId::B8_G8_R8_A8, oat::D3DFMT_A8R8G8B8, oat::DXGI_FORMAT_B8G8R8A8_UNORM, 32, 16, 8, 8, 8, 0, 8, 24, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_A8(ImageFormatId::A8, oat::D3DFMT_A8, oat::DXGI_FORMAT_A8_UNORM, 8, 0, 0, 0, 0, 0, 0, 0, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_R16_G16_B16_A16_FLOAT(
ImageFormatId::R16_G16_B16_A16_FLOAT, oat::D3DFMT_A16B16G16R16F, oat::DXGI_FORMAT_R16G16B16A16_FLOAT, 128, 0, 0, 0, 0, 0, 0, 0, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_R8(ImageFormatId::R8, oat::D3DFMT_L8, oat::DXGI_FORMAT_R8_UNORM, 8, 0, 8, 0, 0, 0, 0, 0, 0);
const ImageFormatUnsigned ImageFormat::FORMAT_R8_A8(ImageFormatId::R8_A8, oat::D3DFMT_A8L8, oat::DXGI_FORMAT_UNKNOWN, 16, 0, 8, 0, 0, 0, 0, 8, 8);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC1(ImageFormatId::BC1, oat::D3DFMT_DXT1, oat::DXGI_FORMAT_BC1_UNORM, 4, 64);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC2(ImageFormatId::BC2, oat::D3DFMT_DXT3, oat::DXGI_FORMAT_BC2_UNORM, 4, 128);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(ImageFormatId::BC3, oat::D3DFMT_DXT5, oat::DXGI_FORMAT_BC3_UNORM, 4, 128);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC4(ImageFormatId::BC4, oat::D3DFMT_UNKNOWN, oat::DXGI_FORMAT_BC4_UNORM, 4, 64);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC5(ImageFormatId::BC5, oat::D3DFMT_UNKNOWN, oat::DXGI_FORMAT_BC5_UNORM, 4, 128);
const ImageFormat* const ImageFormat::ALL_FORMATS[static_cast<unsigned>(ImageFormatId::MAX)]{
&FORMAT_R8_G8_B8,
&FORMAT_B8_G8_R8_X8,
&FORMAT_R8_G8_B8_A8,
&FORMAT_B8_G8_R8_A8,
&FORMAT_A8,
&FORMAT_R16_G16_B16_A16_FLOAT,
&FORMAT_R8,
&FORMAT_R8_A8,
&FORMAT_BC1,
&FORMAT_BC2,
&FORMAT_BC3,
&FORMAT_BC4,
&FORMAT_BC5,
};
const ImageFormat* const ImageFormat::ALL_FORMATS[static_cast<unsigned>(ImageFormatId::MAX)]{
&FORMAT_R8_G8_B8,
&FORMAT_B8_G8_R8_X8,
&FORMAT_R8_G8_B8_A8,
&FORMAT_B8_G8_R8_A8,
&FORMAT_A8,
&FORMAT_R16_G16_B16_A16_FLOAT,
&FORMAT_R8,
&FORMAT_R8_A8,
&FORMAT_BC1,
&FORMAT_BC2,
&FORMAT_BC3,
&FORMAT_BC4,
&FORMAT_BC5,
};
} // namespace image

View File

@@ -6,117 +6,120 @@
#include <cstddef>
#include <cstdint>
enum class ImageFormatId
namespace image
{
UNKNOWN = -1,
R8_G8_B8,
B8_G8_R8_X8,
R8_G8_B8_A8,
B8_G8_R8_A8,
A8,
R16_G16_B16_A16_FLOAT,
R8,
R8_A8,
BC1,
BC2,
BC3,
BC4,
BC5,
enum class ImageFormatId
{
UNKNOWN = -1,
R8_G8_B8,
B8_G8_R8_X8,
R8_G8_B8_A8,
B8_G8_R8_A8,
A8,
R16_G16_B16_A16_FLOAT,
R8,
R8_A8,
BC1,
BC2,
BC3,
BC4,
BC5,
MAX
};
MAX
};
enum class ImageFormatType
{
UNKNOWN,
UNSIGNED,
BLOCK_COMPRESSED
};
enum class ImageFormatType
{
UNKNOWN,
UNSIGNED,
BLOCK_COMPRESSED
};
class ImageFormatUnsigned;
class ImageFormatBlockCompressed;
class ImageFormatUnsigned;
class ImageFormatBlockCompressed;
class ImageFormat
{
ImageFormatId m_id;
oat::D3DFORMAT m_d3d_format;
oat::DXGI_FORMAT m_dxgi_format;
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);
protected:
ImageFormat(ImageFormatId id, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat);
public:
virtual ~ImageFormat() = default;
public:
virtual ~ImageFormat() = default;
[[nodiscard]] ImageFormatId GetId() const;
[[nodiscard]] oat::D3DFORMAT GetD3DFormat() const;
[[nodiscard]] oat::DXGI_FORMAT GetDxgiFormat() const;
[[nodiscard]] ImageFormatId GetId() const;
[[nodiscard]] oat::D3DFORMAT GetD3DFormat() const;
[[nodiscard]] oat::DXGI_FORMAT GetDxgiFormat() const;
[[nodiscard]] virtual ImageFormatType GetType() const = 0;
[[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;
[[nodiscard]] virtual ImageFormatType GetType() const = 0;
[[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)];
};
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)];
};
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;
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,
oat::D3DFORMAT d3dFormat,
oat::DXGI_FORMAT dxgiFormat,
unsigned bitsPerPixel,
unsigned rOffset,
unsigned rSize,
unsigned gOffset,
unsigned gSize,
unsigned bOffset,
unsigned bSize,
unsigned aOffset,
unsigned aSize);
ImageFormatUnsigned(ImageFormatId id,
oat::D3DFORMAT d3dFormat,
oat::DXGI_FORMAT dxgiFormat,
unsigned bitsPerPixel,
unsigned rOffset,
unsigned rSize,
unsigned gOffset,
unsigned gSize,
unsigned bOffset,
unsigned bSize,
unsigned aOffset,
unsigned aSize);
[[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]] 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;
[[nodiscard]] bool HasG() const;
[[nodiscard]] bool HasB() const;
[[nodiscard]] bool HasA() const;
};
[[nodiscard]] bool HasR() const;
[[nodiscard]] bool HasG() const;
[[nodiscard]] bool HasB() const;
[[nodiscard]] bool HasA() const;
};
class ImageFormatBlockCompressed final : public ImageFormat
{
public:
unsigned m_block_size;
unsigned m_bits_per_block;
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, oat::D3DFORMAT d3dFormat, oat::DXGI_FORMAT dxgiFormat, unsigned blockSize, unsigned bitsPerBlock);
[[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]] 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;
};
} // 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,
};
return IwiLoaderResult{
.m_version = IwiVersion::IWI_27,
.m_meta = meta,
.m_texture = std::move(texture),
};
}
} // namespace
std::unique_ptr<Texture> LoadIwi(std::istream& stream)
namespace image
{
std::optional<IwiLoaderResult> LoadIwi(std::istream& stream)
{
IwiVersion iwiVersion{};
IwiVersionHeader iwiVersionHeader{};
stream.read(reinterpret_cast<char*>(&iwiVersion), sizeof(iwiVersion));
if (stream.gcount() != sizeof(iwiVersion))
return nullptr;
if (iwiVersion.tag[0] != 'I' || iwiVersion.tag[1] != 'W' || iwiVersion.tag[2] != 'i')
stream.read(reinterpret_cast<char*>(&iwiVersionHeader), sizeof(iwiVersionHeader));
if (stream.gcount() != sizeof(iwiVersionHeader))
{
con::error("Invalid IWI magic");
return nullptr;
con::error("IWI version header corrupted");
return std::nullopt;
}
switch (iwiVersion.version)
if (iwiVersionHeader.tag[0] != 'I' || iwiVersionHeader.tag[1] != 'W' || iwiVersionHeader.tag[2] != 'i')
{
con::error("Invalid IWI magic");
return std::nullopt;
}
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,234 +2,257 @@
#include <cstdint>
struct IwiVersion
namespace image
{
char tag[3];
char version;
};
// IW3
namespace iwi6
{
struct IwiHeader
enum class IwiVersion : std::uint8_t
{
int8_t format;
int8_t flags;
uint16_t dimensions[3];
uint32_t fileSizeForPicmip[4];
// IW3
IWI_6 = 6,
// IW4, IW5
IWI_8 = 8,
// T5
IWI_13 = 13,
// T6
IWI_27 = 27
};
enum class IwiFormat
struct CommonIwiMetaData
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
// Always high resolution
bool m_no_picmip;
bool m_streaming;
bool m_clamp_u;
bool m_clamp_v;
bool m_dynamic;
IMG_FORMAT_COUNT
float m_gamma;
};
enum IwiFlags
struct IwiVersionHeader
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_CUBEMAP = 1 << 2,
IMG_FLAG_VOLMAP = 1 << 3,
IMG_FLAG_STREAMING = 1 << 4,
IMG_FLAG_LEGACY_NORMALS = 1 << 5,
IMG_FLAG_CLAMP_U = 1 << 6,
IMG_FLAG_CLAMP_V = 1 << 7,
IMG_FLAG_DYNAMIC = 1 << 16,
IMG_FLAG_RENDER_TARGET = 1 << 17,
IMG_FLAG_SYSTEMMEM = 1 << 18
};
} // namespace iwi6
// IW4
namespace iwi8
{
struct IwiHeader
{
uint32_t flags;
int8_t format;
int8_t unused;
uint16_t dimensions[3];
uint32_t fileSizeForPicmip[4];
char tag[3];
char version;
};
enum class IwiFormat
namespace iwi6
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
IMG_FORMAT_DXT3A_AS_LUMINANCE = 0xF,
IMG_FORMAT_DXT5A_AS_LUMINANCE = 0x10,
IMG_FORMAT_DXT3A_AS_ALPHA = 0x11,
IMG_FORMAT_DXT5A_AS_ALPHA = 0x12,
IMG_FORMAT_DXT1_AS_LUMINANCE_ALPHA = 0x13,
IMG_FORMAT_DXN_AS_LUMINANCE_ALPHA = 0x14,
IMG_FORMAT_DXT1_AS_LUMINANCE = 0x15,
IMG_FORMAT_DXT1_AS_ALPHA = 0x16,
struct IwiHeader
{
int8_t format;
int8_t flags;
uint16_t dimensions[3];
uint32_t fileSizeForPicmip[4];
};
IMG_FORMAT_COUNT
};
enum class IwiFormat
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
enum IwiFlags
IMG_FORMAT_COUNT
};
enum IwiFlags
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_CUBEMAP = 1 << 2,
IMG_FLAG_VOLMAP = 1 << 3,
IMG_FLAG_STREAMING = 1 << 4,
IMG_FLAG_LEGACY_NORMALS = 1 << 5,
IMG_FLAG_CLAMP_U = 1 << 6,
IMG_FLAG_CLAMP_V = 1 << 7,
IMG_FLAG_DYNAMIC = 1 << 16,
IMG_FLAG_RENDER_TARGET = 1 << 17,
IMG_FLAG_SYSTEMMEM = 1 << 18
};
} // namespace iwi6
namespace iwi8
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_STREAMING = 1 << 2,
IMG_FLAG_LEGACY_NORMALS = 1 << 3,
IMG_FLAG_CLAMP_U = 1 << 4,
IMG_FLAG_CLAMP_V = 1 << 5,
IMG_FLAG_ALPHA_WEIGHTED_COLORS = 1 << 6,
IMG_FLAG_DXTC_APPROX_WEIGHTS = 1 << 7,
IMG_FLAG_GAMMA_NONE = 0,
IMG_FLAG_GAMMA_SRGB = 1 << 8,
IMG_FLAG_GAMMA_PWL = 1 << 9,
IMG_FLAG_GAMMA_2 = IMG_FLAG_GAMMA_SRGB | IMG_FLAG_GAMMA_PWL,
IMG_FLAG_MAPTYPE_2D = 0,
IMG_FLAG_MAPTYPE_CUBE = 1 << 16,
IMG_FLAG_MAPTYPE_3D = 1 << 17,
IMG_FLAG_MAPTYPE_1D = IMG_FLAG_MAPTYPE_CUBE | IMG_FLAG_MAPTYPE_3D,
IMG_FLAG_MAPTYPE_MASK = IMG_FLAG_MAPTYPE_2D | IMG_FLAG_MAPTYPE_CUBE | IMG_FLAG_MAPTYPE_3D | IMG_FLAG_MAPTYPE_1D,
IMG_FLAG_NORMALMAP = 1 << 18,
IMG_FLAG_INTENSITY_TO_ALPHA = 1 << 19,
IMG_FLAG_DYNAMIC = 1 << 24,
IMG_FLAG_RENDER_TARGET = 1 << 25,
IMG_FLAG_SYSTEMMEM = 1 << 26
};
} // namespace iwi8
struct IwiHeader
{
uint32_t flags;
int8_t format;
int8_t unused;
uint16_t dimensions[3];
uint32_t fileSizeForPicmip[4];
};
// T5
namespace iwi13
{
struct IwiHeader
enum class IwiFormat
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
IMG_FORMAT_DXT3A_AS_LUMINANCE = 0xF,
IMG_FORMAT_DXT5A_AS_LUMINANCE = 0x10,
IMG_FORMAT_DXT3A_AS_ALPHA = 0x11,
IMG_FORMAT_DXT5A_AS_ALPHA = 0x12,
IMG_FORMAT_DXT1_AS_LUMINANCE_ALPHA = 0x13,
IMG_FORMAT_DXN_AS_LUMINANCE_ALPHA = 0x14,
IMG_FORMAT_DXT1_AS_LUMINANCE = 0x15,
IMG_FORMAT_DXT1_AS_ALPHA = 0x16,
IMG_FORMAT_COUNT
};
enum IwiFlags
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_STREAMING = 1 << 2,
IMG_FLAG_LEGACY_NORMALS = 1 << 3,
IMG_FLAG_CLAMP_U = 1 << 4,
IMG_FLAG_CLAMP_V = 1 << 5,
IMG_FLAG_ALPHA_WEIGHTED_COLORS = 1 << 6,
IMG_FLAG_DXTC_APPROX_WEIGHTS = 1 << 7,
IMG_FLAG_GAMMA_NONE = 0,
IMG_FLAG_GAMMA_SRGB = 1 << 8,
IMG_FLAG_GAMMA_PWL = 1 << 9,
IMG_FLAG_GAMMA_2 = IMG_FLAG_GAMMA_SRGB | IMG_FLAG_GAMMA_PWL,
IMG_FLAG_MAPTYPE_2D = 0,
IMG_FLAG_MAPTYPE_CUBE = 1 << 16,
IMG_FLAG_MAPTYPE_3D = 1 << 17,
IMG_FLAG_MAPTYPE_1D = IMG_FLAG_MAPTYPE_CUBE | IMG_FLAG_MAPTYPE_3D,
IMG_FLAG_MAPTYPE_MASK = IMG_FLAG_MAPTYPE_2D | IMG_FLAG_MAPTYPE_CUBE | IMG_FLAG_MAPTYPE_3D | IMG_FLAG_MAPTYPE_1D,
IMG_FLAG_NORMALMAP = 1 << 18,
IMG_FLAG_INTENSITY_TO_ALPHA = 1 << 19,
IMG_FLAG_DYNAMIC = 1 << 24,
IMG_FLAG_RENDER_TARGET = 1 << 25,
IMG_FLAG_SYSTEMMEM = 1 << 26
};
} // namespace iwi8
namespace iwi13
{
int8_t format;
int8_t flags;
uint16_t dimensions[3];
float gamma;
uint32_t fileSizeForPicmip[8];
};
struct IwiHeader
{
int8_t format;
int8_t flags;
uint16_t dimensions[3];
float gamma;
uint32_t fileSizeForPicmip[8];
};
enum class IwiFormat
enum class IwiFormat
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
IMG_FORMAT_BITMAP_RGB565 = 0xF,
IMG_FORMAT_BITMAP_RGB5A3 = 0x10,
IMG_FORMAT_BITMAP_C8 = 0x11,
IMG_FORMAT_BITMAP_RGBA8 = 0x12,
IMG_FORMAT_A16B16G16R16F = 0x13,
IMG_FORMAT_COUNT = 0x14,
};
enum IwiFlags
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_CUBEMAP = 1 << 2,
IMG_FLAG_VOLMAP = 1 << 3,
IMG_FLAG_STREAMING = 1 << 4,
IMG_FLAG_LEGACY_NORMALS = 1 << 5,
IMG_FLAG_CLAMP_U = 1 << 6,
IMG_FLAG_CLAMP_V = 1 << 7,
IMG_FLAG_FORCE_SYSTEM = 1 << 8,
IMG_FLAG_DYNAMIC = 1 << 16,
IMG_FLAG_RENDER_TARGET = 1 << 17,
IMG_FLAG_SYSTEMMEM = 1 << 18,
};
} // namespace iwi13
namespace iwi27
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
IMG_FORMAT_BITMAP_RGB565 = 0xF,
IMG_FORMAT_BITMAP_RGB5A3 = 0x10,
IMG_FORMAT_BITMAP_C8 = 0x11,
IMG_FORMAT_BITMAP_RGBA8 = 0x12,
IMG_FORMAT_A16B16G16R16F = 0x13,
IMG_FORMAT_COUNT = 0x14,
};
struct IwiHeader
{
int8_t format;
int8_t flags;
uint16_t dimensions[3];
float gamma;
int8_t maxGlossForMip[16];
uint32_t fileSizeForPicmip[8];
};
enum IwiFlags
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_CUBEMAP = 1 << 2,
IMG_FLAG_VOLMAP = 1 << 3,
IMG_FLAG_STREAMING = 1 << 4,
IMG_FLAG_LEGACY_NORMALS = 1 << 5,
IMG_FLAG_CLAMP_U = 1 << 6,
IMG_FLAG_CLAMP_V = 1 << 7,
IMG_FLAG_FORCE_SYSTEM = 1 << 8,
IMG_FLAG_DYNAMIC = 1 << 16,
IMG_FLAG_RENDER_TARGET = 1 << 17,
IMG_FLAG_SYSTEMMEM = 1 << 18,
};
enum class IwiFormat
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
IMG_FORMAT_BITMAP_RGB565 = 0xF,
IMG_FORMAT_BITMAP_RGB5A3 = 0x10,
IMG_FORMAT_BITMAP_C8 = 0x11,
IMG_FORMAT_BITMAP_RGBA8 = 0x12,
IMG_FORMAT_A16B16G16R16F = 0x13,
IMG_FORMAT_COUNT,
};
} // namespace iwi13
enum IwiFlags
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_CUBEMAP = 1 << 2,
IMG_FLAG_VOLMAP = 1 << 3,
IMG_FLAG_STREAMING = 1 << 4,
IMG_FLAG_CLAMP_U = 1 << 6,
IMG_FLAG_CLAMP_V = 1 << 7,
IMG_FLAG_FORCE_SYSTEM = 1 << 8,
IMG_FLAG_DYNAMIC = 1 << 16,
IMG_FLAG_RENDER_TARGET = 1 << 17,
IMG_FLAG_MULTISAMPLE = 1 << 18,
};
// T6
namespace iwi27
{
struct IwiHeader
{
int8_t format;
int8_t flags;
uint16_t dimensions[3];
float gamma;
int8_t maxGlossForMip[16];
uint32_t fileSizeForPicmip[8];
};
enum class IwiFormat
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
IMG_FORMAT_BITMAP_RGB565 = 0xF,
IMG_FORMAT_BITMAP_RGB5A3 = 0x10,
IMG_FORMAT_BITMAP_C8 = 0x11,
IMG_FORMAT_BITMAP_RGBA8 = 0x12,
IMG_FORMAT_A16B16G16R16F = 0x13,
IMG_FORMAT_COUNT,
};
enum IwiFlags
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_CUBEMAP = 1 << 2,
IMG_FLAG_VOLMAP = 1 << 3,
IMG_FLAG_STREAMING = 1 << 4,
IMG_FLAG_CLAMP_U = 1 << 6,
IMG_FLAG_CLAMP_V = 1 << 7,
IMG_FLAG_FORCE_SYSTEM = 1 << 8,
IMG_FLAG_DYNAMIC = 1 << 16,
IMG_FLAG_RENDER_TARGET = 1 << 17,
IMG_FLAG_MULTISAMPLE = 1 << 18,
};
} // 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,440 +4,443 @@
#include <cassert>
#include <cstring>
// ==============================================
// ================= Texture ====================
// ==============================================
Texture::Texture(const ImageFormat* format, const bool mipMaps)
namespace image
{
m_format = format;
m_has_mip_maps = mipMaps;
m_data = nullptr;
}
Texture::Texture(Texture&& other) noexcept
{
m_format = other.m_format;
m_has_mip_maps = other.m_has_mip_maps;
m_data = other.m_data;
other.m_data = nullptr;
}
Texture& Texture::operator=(Texture&& other) noexcept
{
m_format = other.m_format;
m_has_mip_maps = other.m_has_mip_maps;
m_data = other.m_data;
other.m_data = nullptr;
return *this;
}
Texture::~Texture()
{
delete[] m_data;
m_data = nullptr;
}
const ImageFormat* Texture::GetFormat() const
{
return m_format;
}
void Texture::Allocate()
{
size_t storageRequirement = 0;
const int mipLevelCount = m_has_mip_maps ? GetMipMapCount() : 1;
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++)
// ==============================================
// ================= Texture ====================
// ==============================================
Texture::Texture(const ImageFormat* format, const bool mipMaps)
{
storageRequirement += GetSizeOfMipLevel(currentMipLevel) * GetFaceCount();
m_format = format;
m_has_mip_maps = mipMaps;
m_data = nullptr;
}
if (storageRequirement > 0)
Texture::Texture(Texture&& other) noexcept
{
m_data = new uint8_t[storageRequirement];
memset(m_data, 0, storageRequirement);
m_format = other.m_format;
m_has_mip_maps = other.m_has_mip_maps;
m_data = other.m_data;
other.m_data = nullptr;
}
}
bool Texture::Empty() const
{
return m_data == nullptr;
}
Texture& Texture::operator=(Texture&& other) noexcept
{
m_format = other.m_format;
m_has_mip_maps = other.m_has_mip_maps;
m_data = other.m_data;
bool Texture::HasMipMaps() const
{
return m_has_mip_maps;
}
other.m_data = nullptr;
uint8_t* Texture::GetBufferForMipLevel(const int mipLevel)
{
return GetBufferForMipLevel(mipLevel, 0);
}
const uint8_t* Texture::GetBufferForMipLevel(const int mipLevel) const
{
return GetBufferForMipLevel(mipLevel, 0);
}
// ==============================================
// ================ Texture2D ===================
// ==============================================
Texture2D::Texture2D(const ImageFormat* format, const unsigned width, const unsigned height)
: Texture2D(format, width, height, false)
{
}
Texture2D::Texture2D(const ImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps)
: Texture(format, mipMaps)
{
m_width = width;
m_height = height;
}
Texture2D::Texture2D(Texture2D&& other) noexcept
: Texture(std::move(other)),
m_width(other.m_width),
m_height(other.m_height)
{
}
Texture2D::~Texture2D() = default;
Texture2D& Texture2D::operator=(Texture2D&& other) noexcept
{
if (this == &other)
return *this;
Texture::operator=(std::move(other));
m_width = other.m_width;
m_height = other.m_height;
return *this;
}
TextureType Texture2D::GetTextureType() const
{
return TextureType::T_2D;
}
unsigned Texture2D::GetWidth() const
{
return m_width;
}
unsigned Texture2D::GetHeight() const
{
return m_height;
}
unsigned Texture2D::GetDepth() const
{
return 1;
}
int Texture2D::GetFaceCount() const
{
return 1;
}
size_t Texture2D::GetSizeOfMipLevel(const int mipLevel) const
{
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, 1);
}
int Texture2D::GetMipMapCount() const
{
unsigned maxDimension = std::max(m_width, m_height);
int mipMapCount = 0;
while (maxDimension != 0)
{
maxDimension >>= 1;
mipMapCount++;
}
return mipMapCount;
}
uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face)
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face == 0);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face != 0)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
Texture::~Texture()
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
delete[] m_data;
m_data = nullptr;
}
return &m_data[bufferOffset];
}
const uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face) const
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face == 0);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face != 0)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
const ImageFormat* Texture::GetFormat() const
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
return m_format;
}
return &m_data[bufferOffset];
}
void Texture::Allocate()
{
size_t storageRequirement = 0;
const int mipLevelCount = m_has_mip_maps ? GetMipMapCount() : 1;
// ==============================================
// =============== TextureCube ==================
// ==============================================
const int TextureCube::FACE_COUNT = 6;
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++)
{
storageRequirement += GetSizeOfMipLevel(currentMipLevel) * GetFaceCount();
}
TextureCube::TextureCube(const ImageFormat* format, const unsigned width, const unsigned height)
: Texture2D(format, width, height)
{
}
if (storageRequirement > 0)
{
m_data = new uint8_t[storageRequirement];
memset(m_data, 0, storageRequirement);
}
}
TextureCube::TextureCube(const ImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps)
: Texture2D(format, width, height, mipMaps)
{
}
bool Texture::Empty() const
{
return m_data == nullptr;
}
TextureCube::TextureCube(TextureCube&& other) noexcept
: Texture2D(std::move(other))
{
}
bool Texture::HasMipMaps() const
{
return m_has_mip_maps;
}
TextureCube::~TextureCube() = default;
uint8_t* Texture::GetBufferForMipLevel(const int mipLevel)
{
return GetBufferForMipLevel(mipLevel, 0);
}
const uint8_t* Texture::GetBufferForMipLevel(const int mipLevel) const
{
return GetBufferForMipLevel(mipLevel, 0);
}
// ==============================================
// ================ Texture2D ===================
// ==============================================
Texture2D::Texture2D(const ImageFormat* format, const unsigned width, const unsigned height)
: Texture2D(format, width, height, false)
{
}
Texture2D::Texture2D(const ImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps)
: Texture(format, mipMaps)
{
m_width = width;
m_height = height;
}
Texture2D::Texture2D(Texture2D&& other) noexcept
: Texture(std::move(other)),
m_width(other.m_width),
m_height(other.m_height)
{
}
Texture2D::~Texture2D() = default;
Texture2D& Texture2D::operator=(Texture2D&& other) noexcept
{
if (this == &other)
return *this;
Texture::operator=(std::move(other));
m_width = other.m_width;
m_height = other.m_height;
TextureCube& TextureCube::operator=(TextureCube&& other) noexcept
{
if (this == &other)
return *this;
Texture2D::operator=(std::move(other));
return *this;
}
TextureType TextureCube::GetTextureType() const
{
return TextureType::T_CUBE;
}
int TextureCube::GetFaceCount() const
{
return FACE_COUNT;
}
uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face)
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face >= 0);
assert(face < FACE_COUNT);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face < 0 || face >= FACE_COUNT)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT;
}
return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face];
}
const uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face) const
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face >= 0);
assert(face < FACE_COUNT);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face < 0 || face >= FACE_COUNT)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
TextureType Texture2D::GetTextureType() const
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT;
return TextureType::T_2D;
}
return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face];
}
unsigned Texture2D::GetWidth() const
{
return m_width;
}
// ==============================================
// ================ Texture3D ===================
// ==============================================
unsigned Texture2D::GetHeight() const
{
return m_height;
}
Texture3D::Texture3D(const ImageFormat* format, const unsigned width, const unsigned height, const unsigned depth)
: Texture3D(format, width, height, depth, false)
{
}
unsigned Texture2D::GetDepth() const
{
return 1;
}
Texture3D::Texture3D(const ImageFormat* format, const unsigned width, const unsigned height, const unsigned depth, const bool mipMaps)
: Texture(format, mipMaps)
{
m_width = width;
m_height = height;
m_depth = depth;
}
int Texture2D::GetFaceCount() const
{
return 1;
}
Texture3D::Texture3D(Texture3D&& other) noexcept
: Texture(std::move(other)),
m_width(other.m_width),
m_height(other.m_height),
m_depth(other.m_depth)
{
}
size_t Texture2D::GetSizeOfMipLevel(const int mipLevel) const
{
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, 1);
}
Texture3D::~Texture3D() = default;
int Texture2D::GetMipMapCount() const
{
unsigned maxDimension = std::max(m_width, m_height);
int mipMapCount = 0;
while (maxDimension != 0)
{
maxDimension >>= 1;
mipMapCount++;
}
return mipMapCount;
}
uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face)
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face == 0);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face != 0)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
}
return &m_data[bufferOffset];
}
const uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face) const
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face == 0);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face != 0)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
}
return &m_data[bufferOffset];
}
// ==============================================
// =============== TextureCube ==================
// ==============================================
const int TextureCube::FACE_COUNT = 6;
TextureCube::TextureCube(const ImageFormat* format, const unsigned width, const unsigned height)
: Texture2D(format, width, height)
{
}
TextureCube::TextureCube(const ImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps)
: Texture2D(format, width, height, mipMaps)
{
}
TextureCube::TextureCube(TextureCube&& other) noexcept
: Texture2D(std::move(other))
{
}
TextureCube::~TextureCube() = default;
TextureCube& TextureCube::operator=(TextureCube&& other) noexcept
{
if (this == &other)
return *this;
Texture2D::operator=(std::move(other));
Texture3D& Texture3D::operator=(Texture3D&& other) noexcept
{
if (this == &other)
return *this;
Texture::operator=(std::move(other));
m_width = other.m_width;
m_height = other.m_height;
m_depth = other.m_depth;
return *this;
}
TextureType Texture3D::GetTextureType() const
{
return TextureType::T_3D;
}
unsigned Texture3D::GetWidth() const
{
return m_width;
}
unsigned Texture3D::GetHeight() const
{
return m_height;
}
unsigned Texture3D::GetDepth() const
{
return m_depth;
}
int Texture3D::GetFaceCount() const
{
return 1;
}
size_t Texture3D::GetSizeOfMipLevel(const int mipLevel) const
{
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, m_depth);
}
int Texture3D::GetMipMapCount() const
{
unsigned maxDimension = std::max(std::max(m_width, m_height), m_depth);
int mipMapCount = 0;
while (maxDimension != 0)
{
maxDimension >>= 1;
mipMapCount++;
}
return mipMapCount;
}
uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face)
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face == 0);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face != 0)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
TextureType TextureCube::GetTextureType() const
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
return TextureType::T_CUBE;
}
return &m_data[bufferOffset];
}
const uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face) const
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face == 0);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face != 0)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
int TextureCube::GetFaceCount() const
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
return FACE_COUNT;
}
return &m_data[bufferOffset];
}
uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face)
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face >= 0);
assert(face < FACE_COUNT);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face < 0 || face >= FACE_COUNT)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT;
}
return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face];
}
const uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face) const
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face >= 0);
assert(face < FACE_COUNT);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face < 0 || face >= FACE_COUNT)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT;
}
return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face];
}
// ==============================================
// ================ Texture3D ===================
// ==============================================
Texture3D::Texture3D(const ImageFormat* format, const unsigned width, const unsigned height, const unsigned depth)
: Texture3D(format, width, height, depth, false)
{
}
Texture3D::Texture3D(const ImageFormat* format, const unsigned width, const unsigned height, const unsigned depth, const bool mipMaps)
: Texture(format, mipMaps)
{
m_width = width;
m_height = height;
m_depth = depth;
}
Texture3D::Texture3D(Texture3D&& other) noexcept
: Texture(std::move(other)),
m_width(other.m_width),
m_height(other.m_height),
m_depth(other.m_depth)
{
}
Texture3D::~Texture3D() = default;
Texture3D& Texture3D::operator=(Texture3D&& other) noexcept
{
if (this == &other)
return *this;
Texture::operator=(std::move(other));
m_width = other.m_width;
m_height = other.m_height;
m_depth = other.m_depth;
return *this;
}
TextureType Texture3D::GetTextureType() const
{
return TextureType::T_3D;
}
unsigned Texture3D::GetWidth() const
{
return m_width;
}
unsigned Texture3D::GetHeight() const
{
return m_height;
}
unsigned Texture3D::GetDepth() const
{
return m_depth;
}
int Texture3D::GetFaceCount() const
{
return 1;
}
size_t Texture3D::GetSizeOfMipLevel(const int mipLevel) const
{
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, m_depth);
}
int Texture3D::GetMipMapCount() const
{
unsigned maxDimension = std::max(std::max(m_width, m_height), m_depth);
int mipMapCount = 0;
while (maxDimension != 0)
{
maxDimension >>= 1;
mipMapCount++;
}
return mipMapCount;
}
uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face)
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face == 0);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face != 0)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
}
return &m_data[bufferOffset];
}
const uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face) const
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(face == 0);
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (face != 0)
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
}
return &m_data[bufferOffset];
}
} // namespace image

View File

@@ -3,130 +3,133 @@
#include <cstdint>
enum class TextureType : std::uint8_t
namespace image
{
T_2D,
T_CUBE,
T_3D
};
enum class TextureType : std::uint8_t
{
T_2D,
T_CUBE,
T_3D
};
class Texture
{
protected:
const ImageFormat* m_format;
bool m_has_mip_maps;
uint8_t* m_data;
class Texture
{
protected:
const ImageFormat* m_format;
bool m_has_mip_maps;
uint8_t* m_data;
Texture(const ImageFormat* format, bool mipMaps);
Texture(Texture&& other) noexcept;
Texture(const ImageFormat* format, bool mipMaps);
Texture(Texture&& other) noexcept;
Texture& operator=(Texture&& other) noexcept;
Texture& operator=(Texture&& other) noexcept;
public:
Texture(const Texture& other) = delete;
virtual ~Texture();
public:
Texture(const Texture& other) = delete;
virtual ~Texture();
Texture& operator=(const Texture& other) = delete;
Texture& operator=(const Texture& other) = delete;
[[nodiscard]] virtual TextureType GetTextureType() const = 0;
[[nodiscard]] const ImageFormat* GetFormat() const;
[[nodiscard]] virtual TextureType GetTextureType() const = 0;
[[nodiscard]] const ImageFormat* GetFormat() const;
[[nodiscard]] virtual unsigned GetWidth() const = 0;
[[nodiscard]] virtual unsigned GetHeight() const = 0;
[[nodiscard]] virtual unsigned GetDepth() const = 0;
[[nodiscard]] virtual int GetFaceCount() const = 0;
[[nodiscard]] virtual unsigned GetWidth() const = 0;
[[nodiscard]] virtual unsigned GetHeight() const = 0;
[[nodiscard]] virtual unsigned GetDepth() const = 0;
[[nodiscard]] virtual int GetFaceCount() const = 0;
void Allocate();
[[nodiscard]] bool Empty() const;
void Allocate();
[[nodiscard]] bool Empty() const;
[[nodiscard]] virtual size_t GetSizeOfMipLevel(int mipLevel) const = 0;
[[nodiscard]] virtual uint8_t* GetBufferForMipLevel(int mipLevel, int face) = 0;
[[nodiscard]] virtual const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const = 0;
[[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel);
[[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel) const;
[[nodiscard]] virtual size_t GetSizeOfMipLevel(int mipLevel) const = 0;
[[nodiscard]] virtual uint8_t* GetBufferForMipLevel(int mipLevel, int face) = 0;
[[nodiscard]] virtual const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const = 0;
[[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel);
[[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel) const;
[[nodiscard]] bool HasMipMaps() const;
[[nodiscard]] virtual int GetMipMapCount() const = 0;
};
[[nodiscard]] bool HasMipMaps() const;
[[nodiscard]] virtual int GetMipMapCount() const = 0;
};
class Texture2D : public Texture
{
protected:
unsigned m_width;
unsigned m_height;
class Texture2D : public Texture
{
protected:
unsigned m_width;
unsigned m_height;
public:
Texture2D(const ImageFormat* format, unsigned width, unsigned height);
Texture2D(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps);
Texture2D(const Texture2D& other) = delete;
Texture2D(Texture2D&& other) noexcept;
~Texture2D() override;
public:
Texture2D(const ImageFormat* format, unsigned width, unsigned height);
Texture2D(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps);
Texture2D(const Texture2D& other) = delete;
Texture2D(Texture2D&& other) noexcept;
~Texture2D() override;
Texture2D& operator=(const Texture2D& other) = delete;
Texture2D& operator=(Texture2D&& other) noexcept;
Texture2D& operator=(const Texture2D& other) = delete;
Texture2D& operator=(Texture2D&& other) noexcept;
[[nodiscard]] TextureType GetTextureType() const override;
[[nodiscard]] TextureType GetTextureType() const override;
[[nodiscard]] unsigned GetWidth() const override;
[[nodiscard]] unsigned GetHeight() const override;
[[nodiscard]] unsigned GetDepth() const override;
[[nodiscard]] int GetFaceCount() const override;
[[nodiscard]] unsigned GetWidth() const override;
[[nodiscard]] unsigned GetHeight() const override;
[[nodiscard]] unsigned GetDepth() const override;
[[nodiscard]] int GetFaceCount() const override;
[[nodiscard]] size_t GetSizeOfMipLevel(int mipLevel) const override;
[[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
[[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override;
[[nodiscard]] size_t GetSizeOfMipLevel(int mipLevel) const override;
[[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
[[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override;
[[nodiscard]] int GetMipMapCount() const override;
};
[[nodiscard]] int GetMipMapCount() const override;
};
class TextureCube final : public Texture2D
{
static const int FACE_COUNT;
class TextureCube final : public Texture2D
{
static const int FACE_COUNT;
public:
TextureCube(const ImageFormat* format, unsigned width, unsigned height);
TextureCube(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps);
TextureCube(const TextureCube& other) = delete;
TextureCube(TextureCube&& other) noexcept;
~TextureCube() override;
public:
TextureCube(const ImageFormat* format, unsigned width, unsigned height);
TextureCube(const ImageFormat* format, unsigned width, unsigned height, bool mipMaps);
TextureCube(const TextureCube& other) = delete;
TextureCube(TextureCube&& other) noexcept;
~TextureCube() override;
TextureCube& operator=(const TextureCube& other) = delete;
TextureCube& operator=(TextureCube&& other) noexcept;
TextureCube& operator=(const TextureCube& other) = delete;
TextureCube& operator=(TextureCube&& other) noexcept;
[[nodiscard]] TextureType GetTextureType() const override;
[[nodiscard]] TextureType GetTextureType() const override;
[[nodiscard]] int GetFaceCount() const override;
[[nodiscard]] int GetFaceCount() const override;
[[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
[[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override;
};
[[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
[[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override;
};
class Texture3D final : public Texture
{
unsigned m_width;
unsigned m_height;
unsigned m_depth;
class Texture3D final : public Texture
{
unsigned m_width;
unsigned m_height;
unsigned m_depth;
public:
Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth);
Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth, bool mipMaps);
Texture3D(const Texture3D& other) = delete;
Texture3D(Texture3D&& other) noexcept;
~Texture3D() override;
public:
Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth);
Texture3D(const ImageFormat* format, unsigned width, unsigned height, unsigned depth, bool mipMaps);
Texture3D(const Texture3D& other) = delete;
Texture3D(Texture3D&& other) noexcept;
~Texture3D() override;
Texture3D& operator=(const Texture3D& other) = delete;
Texture3D& operator=(Texture3D&& other) noexcept;
Texture3D& operator=(const Texture3D& other) = delete;
Texture3D& operator=(Texture3D&& other) noexcept;
[[nodiscard]] TextureType GetTextureType() const override;
[[nodiscard]] TextureType GetTextureType() const override;
[[nodiscard]] unsigned GetWidth() const override;
[[nodiscard]] unsigned GetHeight() const override;
[[nodiscard]] unsigned GetDepth() const override;
[[nodiscard]] int GetFaceCount() const override;
[[nodiscard]] unsigned GetWidth() const override;
[[nodiscard]] unsigned GetHeight() const override;
[[nodiscard]] unsigned GetDepth() const override;
[[nodiscard]] int GetFaceCount() const override;
[[nodiscard]] size_t GetSizeOfMipLevel(int mipLevel) const override;
[[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
[[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override;
[[nodiscard]] size_t GetSizeOfMipLevel(int mipLevel) const override;
[[nodiscard]] uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
[[nodiscard]] const uint8_t* GetBufferForMipLevel(int mipLevel, int face) const override;
[[nodiscard]] int GetMipMapCount() const override;
};
[[nodiscard]] int GetMipMapCount() const override;
};
} // namespace image

View File

@@ -2,221 +2,224 @@
#include <cassert>
constexpr uint64_t TextureConverter::Mask1(const unsigned length)
namespace image
{
if (length >= sizeof(uint64_t) * 8)
return UINT64_MAX;
return UINT64_MAX >> (sizeof(uint64_t) * 8 - length);
}
void TextureConverter::SetPixelFunctions(const unsigned inBitCount, const unsigned outBitCount)
{
switch (inBitCount)
constexpr uint64_t TextureConverter::Mask1(const unsigned length)
{
case 16:
m_read_pixel_func = [](const void* offset, unsigned bitCount)
{
return static_cast<uint64_t>(*static_cast<const uint16_t*>(offset));
};
break;
if (length >= sizeof(uint64_t) * 8)
return UINT64_MAX;
case 32:
m_read_pixel_func = [](const void* offset, unsigned bitCount)
{
return static_cast<uint64_t>(*static_cast<const uint32_t*>(offset));
};
break;
return UINT64_MAX >> (sizeof(uint64_t) * 8 - length);
}
case 64:
m_read_pixel_func = [](const void* offset, unsigned bitCount)
void TextureConverter::SetPixelFunctions(const unsigned inBitCount, const unsigned outBitCount)
{
switch (inBitCount)
{
return *static_cast<const uint64_t*>(offset);
};
break;
default:
if (inBitCount <= 64)
{
m_read_pixel_func = [](const void* offset, const unsigned bitCount)
{
uint64_t result = 0;
for (auto pixelOffset = 0u; pixelOffset < bitCount; pixelOffset += 8)
{
result |= (static_cast<uint64_t>(*(static_cast<const uint8_t*>(offset) + (pixelOffset / 8))) << pixelOffset);
}
return result;
};
}
else
{
assert(false);
case 16:
m_read_pixel_func = [](const void* offset, unsigned bitCount)
{
return 0ull;
return static_cast<uint64_t>(*static_cast<const uint16_t*>(offset));
};
break;
case 32:
m_read_pixel_func = [](const void* offset, unsigned bitCount)
{
return static_cast<uint64_t>(*static_cast<const uint32_t*>(offset));
};
break;
case 64:
m_read_pixel_func = [](const void* offset, unsigned bitCount)
{
return *static_cast<const uint64_t*>(offset);
};
break;
default:
if (inBitCount <= 64)
{
m_read_pixel_func = [](const void* offset, const unsigned bitCount)
{
uint64_t result = 0;
for (auto pixelOffset = 0u; pixelOffset < bitCount; pixelOffset += 8)
{
result |= (static_cast<uint64_t>(*(static_cast<const uint8_t*>(offset) + (pixelOffset / 8))) << pixelOffset);
}
return result;
};
}
else
{
assert(false);
m_read_pixel_func = [](const void* offset, unsigned bitCount)
{
return 0ull;
};
}
break;
}
switch (outBitCount)
{
case 16:
m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount)
{
*static_cast<uint16_t*>(offset) = static_cast<uint16_t>(pixel);
};
break;
case 32:
m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount)
{
*static_cast<uint32_t*>(offset) = static_cast<uint32_t>(pixel);
};
break;
case 64:
m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount)
{
*static_cast<uint64_t*>(offset) = pixel;
};
break;
default:
if (inBitCount <= 64)
{
m_write_pixel_func = [](void* offset, const uint64_t pixel, const unsigned bitCount)
{
for (auto pixelOffset = 0u; pixelOffset < bitCount; pixelOffset += 8)
{
*(static_cast<uint8_t*>(offset) + (pixelOffset / 8)) = static_cast<uint8_t>(pixel >> pixelOffset);
}
};
}
else
{
assert(false);
m_write_pixel_func = [](void* offset, uint64_t pixel, unsigned bitCount) {};
}
break;
}
break;
}
switch (outBitCount)
TextureConverter::TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat)
: m_input_texture(inputTexture),
m_output_texture(nullptr),
m_input_format(inputTexture->GetFormat()),
m_output_format(targetFormat)
{
case 16:
m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount)
{
*static_cast<uint16_t*>(offset) = static_cast<uint16_t>(pixel);
};
break;
}
case 32:
m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount)
void TextureConverter::CreateOutputTexture()
{
switch (m_input_texture->GetTextureType())
{
*static_cast<uint32_t*>(offset) = static_cast<uint32_t>(pixel);
};
break;
case TextureType::T_2D:
m_output_texture =
std::make_unique<Texture2D>(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps());
break;
case 64:
m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount)
{
*static_cast<uint64_t*>(offset) = pixel;
};
break;
case TextureType::T_CUBE:
m_output_texture =
std::make_unique<TextureCube>(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps());
break;
default:
if (inBitCount <= 64)
case TextureType::T_3D:
m_output_texture = std::make_unique<Texture3D>(
m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->GetDepth(), m_input_texture->HasMipMaps());
break;
default:
assert(false);
break;
}
m_output_texture->Allocate();
}
void TextureConverter::ReorderUnsignedToUnsigned() const
{
const auto* inputFormat = dynamic_cast<const ImageFormatUnsigned*>(m_input_format);
const auto* outputFormat = dynamic_cast<const ImageFormatUnsigned*>(m_output_format);
const auto mipCount = m_input_texture->HasMipMaps() ? m_input_texture->GetMipMapCount() : 1;
const auto rInputMask = inputFormat->HasR() ? Mask1(inputFormat->m_r_size) << inputFormat->m_r_offset : 0;
const auto gInputMask = inputFormat->HasG() ? Mask1(inputFormat->m_g_size) << inputFormat->m_g_offset : 0;
const auto bInputMask = inputFormat->HasB() ? Mask1(inputFormat->m_b_size) << inputFormat->m_b_offset : 0;
const auto aInputMask = inputFormat->HasA() ? Mask1(inputFormat->m_a_size) << inputFormat->m_a_offset : 0;
const bool rConvert = rInputMask != 0 && outputFormat->m_r_size > 0;
const bool gConvert = gInputMask != 0 && outputFormat->m_g_size > 0;
const bool bConvert = bInputMask != 0 && outputFormat->m_b_size > 0;
const bool aConvert = aInputMask != 0 && outputFormat->m_a_size > 0;
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
{
m_write_pixel_func = [](void* offset, const uint64_t pixel, const unsigned bitCount)
const auto mipLevelSize = m_input_texture->GetSizeOfMipLevel(mipLevel) * m_input_texture->GetFaceCount();
const auto* inputBuffer = m_input_texture->GetBufferForMipLevel(mipLevel);
auto* outputBuffer = m_output_texture->GetBufferForMipLevel(mipLevel);
const auto inputBytePerPixel = inputFormat->m_bits_per_pixel / 8;
const auto outputBytePerPixel = outputFormat->m_bits_per_pixel / 8;
auto outputOffset = 0u;
for (auto inputOffset = 0u; inputOffset < mipLevelSize; inputOffset += inputBytePerPixel, outputOffset += outputBytePerPixel)
{
for (auto pixelOffset = 0u; pixelOffset < bitCount; pixelOffset += 8)
{
*(static_cast<uint8_t*>(offset) + (pixelOffset / 8)) = static_cast<uint8_t>(pixel >> pixelOffset);
}
};
uint64_t outPixel = 0;
const auto inPixel = m_read_pixel_func(&inputBuffer[inputOffset], inputFormat->m_bits_per_pixel);
if (rConvert)
outPixel |= (inPixel & rInputMask) >> inputFormat->m_r_offset << outputFormat->m_r_offset;
if (gConvert)
outPixel |= (inPixel & gInputMask) >> inputFormat->m_g_offset << outputFormat->m_g_offset;
if (bConvert)
outPixel |= (inPixel & bInputMask) >> inputFormat->m_b_offset << outputFormat->m_b_offset;
if (aConvert)
outPixel |= (inPixel & aInputMask) >> inputFormat->m_a_offset << outputFormat->m_a_offset;
m_write_pixel_func(&outputBuffer[outputOffset], outPixel, outputFormat->m_bits_per_pixel);
}
}
}
void TextureConverter::ConvertUnsignedToUnsigned()
{
const auto* inputFormat = dynamic_cast<const ImageFormatUnsigned*>(m_input_format);
const auto* outputFormat = dynamic_cast<const ImageFormatUnsigned*>(m_output_format);
assert(inputFormat->m_bits_per_pixel <= 64);
assert(outputFormat->m_bits_per_pixel <= 64);
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)
{
ReorderUnsignedToUnsigned();
}
else
{
// Unsupported as of now
assert(false);
m_write_pixel_func = [](void* offset, uint64_t pixel, unsigned bitCount) {};
}
break;
}
}
TextureConverter::TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat)
: m_input_texture(inputTexture),
m_output_texture(nullptr),
m_input_format(inputTexture->GetFormat()),
m_output_format(targetFormat)
{
}
void TextureConverter::CreateOutputTexture()
{
switch (m_input_texture->GetTextureType())
{
case TextureType::T_2D:
m_output_texture =
std::make_unique<Texture2D>(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps());
break;
case TextureType::T_CUBE:
m_output_texture =
std::make_unique<TextureCube>(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->HasMipMaps());
break;
case TextureType::T_3D:
m_output_texture = std::make_unique<Texture3D>(
m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(), m_input_texture->GetDepth(), m_input_texture->HasMipMaps());
break;
default:
assert(false);
break;
}
m_output_texture->Allocate();
}
void TextureConverter::ReorderUnsignedToUnsigned() const
{
const auto* inputFormat = dynamic_cast<const ImageFormatUnsigned*>(m_input_format);
const auto* outputFormat = dynamic_cast<const ImageFormatUnsigned*>(m_output_format);
const auto mipCount = m_input_texture->HasMipMaps() ? m_input_texture->GetMipMapCount() : 1;
const auto rInputMask = inputFormat->HasR() ? Mask1(inputFormat->m_r_size) << inputFormat->m_r_offset : 0;
const auto gInputMask = inputFormat->HasG() ? Mask1(inputFormat->m_g_size) << inputFormat->m_g_offset : 0;
const auto bInputMask = inputFormat->HasB() ? Mask1(inputFormat->m_b_size) << inputFormat->m_b_offset : 0;
const auto aInputMask = inputFormat->HasA() ? Mask1(inputFormat->m_a_size) << inputFormat->m_a_offset : 0;
const bool rConvert = rInputMask != 0 && outputFormat->m_r_size > 0;
const bool gConvert = gInputMask != 0 && outputFormat->m_g_size > 0;
const bool bConvert = bInputMask != 0 && outputFormat->m_b_size > 0;
const bool aConvert = aInputMask != 0 && outputFormat->m_a_size > 0;
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
std::unique_ptr<Texture> TextureConverter::Convert()
{
const auto mipLevelSize = m_input_texture->GetSizeOfMipLevel(mipLevel) * m_input_texture->GetFaceCount();
const auto* inputBuffer = m_input_texture->GetBufferForMipLevel(mipLevel);
auto* outputBuffer = m_output_texture->GetBufferForMipLevel(mipLevel);
CreateOutputTexture();
const auto inputBytePerPixel = inputFormat->m_bits_per_pixel / 8;
const auto outputBytePerPixel = outputFormat->m_bits_per_pixel / 8;
auto outputOffset = 0u;
for (auto inputOffset = 0u; inputOffset < mipLevelSize; inputOffset += inputBytePerPixel, outputOffset += outputBytePerPixel)
if (m_input_format->GetType() == ImageFormatType::UNSIGNED && m_output_format->GetType() == ImageFormatType::UNSIGNED)
{
uint64_t outPixel = 0;
const auto inPixel = m_read_pixel_func(&inputBuffer[inputOffset], inputFormat->m_bits_per_pixel);
if (rConvert)
outPixel |= (inPixel & rInputMask) >> inputFormat->m_r_offset << outputFormat->m_r_offset;
if (gConvert)
outPixel |= (inPixel & gInputMask) >> inputFormat->m_g_offset << outputFormat->m_g_offset;
if (bConvert)
outPixel |= (inPixel & bInputMask) >> inputFormat->m_b_offset << outputFormat->m_b_offset;
if (aConvert)
outPixel |= (inPixel & aInputMask) >> inputFormat->m_a_offset << outputFormat->m_a_offset;
m_write_pixel_func(&outputBuffer[outputOffset], outPixel, outputFormat->m_bits_per_pixel);
ConvertUnsignedToUnsigned();
}
else
{
// Unsupported as of now
assert(false);
}
return std::move(m_output_texture);
}
}
void TextureConverter::ConvertUnsignedToUnsigned()
{
const auto* inputFormat = dynamic_cast<const ImageFormatUnsigned*>(m_input_format);
const auto* outputFormat = dynamic_cast<const ImageFormatUnsigned*>(m_output_format);
assert(inputFormat->m_bits_per_pixel <= 64);
assert(outputFormat->m_bits_per_pixel <= 64);
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)
{
ReorderUnsignedToUnsigned();
}
else
{
// Unsupported as of now
assert(false);
}
}
std::unique_ptr<Texture> TextureConverter::Convert()
{
CreateOutputTexture();
if (m_input_format->GetType() == ImageFormatType::UNSIGNED && m_output_format->GetType() == ImageFormatType::UNSIGNED)
{
ConvertUnsignedToUnsigned();
}
else
{
// Unsupported as of now
assert(false);
}
return std::move(m_output_texture);
}
} // namespace image

View File

@@ -5,27 +5,30 @@
#include <functional>
#include <memory>
class TextureConverter
namespace image
{
public:
TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat);
class TextureConverter
{
public:
TextureConverter(const Texture* inputTexture, const ImageFormat* targetFormat);
std::unique_ptr<Texture> Convert();
std::unique_ptr<Texture> Convert();
private:
static constexpr uint64_t Mask1(unsigned length);
void SetPixelFunctions(unsigned inBitCount, unsigned outBitCount);
private:
static constexpr uint64_t Mask1(unsigned length);
void SetPixelFunctions(unsigned inBitCount, unsigned outBitCount);
void CreateOutputTexture();
void CreateOutputTexture();
void ReorderUnsignedToUnsigned() const;
void ConvertUnsignedToUnsigned();
void ReorderUnsignedToUnsigned() const;
void ConvertUnsignedToUnsigned();
std::function<uint64_t(const void* offset, unsigned bitCount)> m_read_pixel_func;
std::function<void(void* offset, uint64_t pixel, unsigned bitCount)> m_write_pixel_func;
std::function<uint64_t(const void* offset, unsigned bitCount)> m_read_pixel_func;
std::function<void(void* offset, uint64_t pixel, unsigned bitCount)> m_write_pixel_func;
const Texture* m_input_texture;
std::unique_ptr<Texture> m_output_texture;
const ImageFormat* m_input_format;
const ImageFormat* m_output_format;
};
const Texture* m_input_texture;
std::unique_ptr<Texture> m_output_texture;
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.