mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-06-19 03:07:58 -05:00
refactor: extract image code into single component
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
|
@ -1,240 +0,0 @@
|
||||
#include "DdsWriter.h"
|
||||
|
||||
#include "Image/DdsTypes.h"
|
||||
#include "Image/TextureConverter.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
const std::map<ImageFormatId, ImageFormatId> DDS_CONVERSION_TABLE{
|
||||
{ImageFormatId::R8_G8_B8, ImageFormatId::B8_G8_R8_X8},
|
||||
};
|
||||
|
||||
class DdsWriterInternal
|
||||
{
|
||||
public:
|
||||
static bool SupportsImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string GetFileExtension()
|
||||
{
|
||||
return ".dds";
|
||||
}
|
||||
|
||||
DdsWriterInternal(std::ostream& stream, const Texture* texture)
|
||||
: m_stream(stream),
|
||||
m_texture(texture),
|
||||
m_use_dx10_extension(false)
|
||||
{
|
||||
}
|
||||
|
||||
void DumpImage()
|
||||
{
|
||||
ConvertTextureIfNecessary();
|
||||
|
||||
DDS_HEADER header{};
|
||||
PopulateDdsHeader(header);
|
||||
|
||||
constexpr auto magic = MakeFourCc('D', 'D', 'S', ' ');
|
||||
|
||||
m_stream.write(reinterpret_cast<const char*>(&magic), sizeof(magic));
|
||||
m_stream.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
|
||||
if (m_use_dx10_extension)
|
||||
{
|
||||
DDS_HEADER_DXT10 dxt10{};
|
||||
PopulateDxt10Header(dxt10);
|
||||
m_stream.write(reinterpret_cast<const char*>(&dxt10), sizeof(dxt10));
|
||||
}
|
||||
|
||||
const auto mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
|
||||
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
|
||||
{
|
||||
const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel);
|
||||
const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount();
|
||||
m_stream.write(reinterpret_cast<const char*>(buffer), mipLevelSize);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr unsigned Mask1(const unsigned length)
|
||||
{
|
||||
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 = 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;
|
||||
};
|
||||
|
||||
DdsWriter::~DdsWriter() = default;
|
||||
|
||||
bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
return DdsWriterInternal::SupportsImageFormat(imageFormat);
|
||||
}
|
||||
|
||||
std::string DdsWriter::GetFileExtension()
|
||||
{
|
||||
return DdsWriterInternal::GetFileExtension();
|
||||
}
|
||||
|
||||
void DdsWriter::DumpImage(std::ostream& stream, const Texture* texture)
|
||||
{
|
||||
DdsWriterInternal internal(stream, texture);
|
||||
internal.DumpImage();
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "IImageWriter.h"
|
||||
|
||||
class DdsWriter final : public IImageWriter
|
||||
{
|
||||
public:
|
||||
~DdsWriter() override;
|
||||
|
||||
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
|
||||
std::string GetFileExtension() override;
|
||||
void DumpImage(std::ostream& stream, const Texture* texture) override;
|
||||
};
|
@ -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;
|
||||
};
|
@ -1,141 +0,0 @@
|
||||
#include "IwiWriter13.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <ostream>
|
||||
|
||||
using namespace iwi13;
|
||||
|
||||
IwiWriter::IwiWriter() = default;
|
||||
|
||||
IwiWriter::~IwiWriter() = default;
|
||||
|
||||
IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
switch (imageFormat->GetId())
|
||||
{
|
||||
case ImageFormatId::R8_G8_B8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_RGB;
|
||||
|
||||
case ImageFormatId::R8_G8_B8_A8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_RGBA;
|
||||
|
||||
case ImageFormatId::A8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_ALPHA;
|
||||
|
||||
case ImageFormatId::R16_G16_B16_A16_FLOAT:
|
||||
return IwiFormat::IMG_FORMAT_A16B16G16R16F;
|
||||
|
||||
case ImageFormatId::BC1:
|
||||
return IwiFormat::IMG_FORMAT_DXT1;
|
||||
|
||||
case ImageFormatId::BC2:
|
||||
return IwiFormat::IMG_FORMAT_DXT3;
|
||||
|
||||
case ImageFormatId::BC3:
|
||||
return IwiFormat::IMG_FORMAT_DXT5;
|
||||
|
||||
case ImageFormatId::BC5:
|
||||
return IwiFormat::IMG_FORMAT_DXN;
|
||||
|
||||
default:
|
||||
return IwiFormat::IMG_FORMAT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
return GetIwiFormatForImageFormat(imageFormat) != IwiFormat::IMG_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
std::string IwiWriter::GetFileExtension()
|
||||
{
|
||||
return ".iwi";
|
||||
}
|
||||
|
||||
void IwiWriter::WriteVersion(std::ostream& stream)
|
||||
{
|
||||
IwiVersion version{};
|
||||
version.tag[0] = 'I';
|
||||
version.tag[1] = 'W';
|
||||
version.tag[2] = 'i';
|
||||
version.version = 13;
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = 1;
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = 1;
|
||||
header.flags |= IMG_FLAG_CUBEMAP;
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = static_cast<uint16_t>(texture.GetDepth());
|
||||
header.flags |= IMG_FLAG_VOLMAP;
|
||||
}
|
||||
|
||||
void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
|
||||
{
|
||||
assert(texture != nullptr);
|
||||
|
||||
WriteVersion(stream);
|
||||
|
||||
IwiHeader header{};
|
||||
header.flags = 0;
|
||||
header.gamma = 0.0f;
|
||||
|
||||
header.format = static_cast<int8_t>(GetIwiFormatForImageFormat(texture->GetFormat()));
|
||||
|
||||
if (!texture->HasMipMaps())
|
||||
header.flags |= IMG_FLAG_NOMIPMAPS;
|
||||
|
||||
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
|
||||
|
||||
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
|
||||
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
currentFileSize += mipLevelSize;
|
||||
|
||||
if (currentMipLevel < static_cast<int>(std::extent_v<decltype(IwiHeader::fileSizeForPicmip)>))
|
||||
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
|
||||
}
|
||||
|
||||
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
|
||||
{
|
||||
FillHeader2D(header, *texture2D);
|
||||
}
|
||||
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
|
||||
{
|
||||
FillHeaderCube(header, *textureCube);
|
||||
}
|
||||
else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
|
||||
{
|
||||
FillHeader3D(header, *texture3D);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&header), sizeof(IwiHeader));
|
||||
|
||||
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IImageWriter.h"
|
||||
#include "Image/IwiTypes.h"
|
||||
|
||||
namespace iwi13
|
||||
{
|
||||
class IwiWriter final : public IImageWriter
|
||||
{
|
||||
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
|
||||
|
||||
static void WriteVersion(std::ostream& stream);
|
||||
static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
|
||||
static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
|
||||
static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
|
||||
|
||||
public:
|
||||
IwiWriter();
|
||||
IwiWriter(const IwiWriter& other) = delete;
|
||||
IwiWriter(IwiWriter&& other) noexcept = delete;
|
||||
~IwiWriter() override;
|
||||
|
||||
IwiWriter& operator=(const IwiWriter& other) = delete;
|
||||
IwiWriter& operator=(IwiWriter&& other) noexcept = delete;
|
||||
|
||||
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
|
||||
std::string GetFileExtension() override;
|
||||
void DumpImage(std::ostream& stream, const Texture* texture) override;
|
||||
};
|
||||
} // namespace iwi13
|
@ -1,144 +0,0 @@
|
||||
#include "IwiWriter27.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <ostream>
|
||||
|
||||
using namespace iwi27;
|
||||
|
||||
IwiWriter::IwiWriter() = default;
|
||||
|
||||
IwiWriter::~IwiWriter() = default;
|
||||
|
||||
IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
switch (imageFormat->GetId())
|
||||
{
|
||||
case ImageFormatId::R8_G8_B8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_RGB;
|
||||
|
||||
case ImageFormatId::R8_G8_B8_A8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_RGBA;
|
||||
|
||||
case ImageFormatId::A8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_ALPHA;
|
||||
|
||||
case ImageFormatId::R16_G16_B16_A16_FLOAT:
|
||||
return IwiFormat::IMG_FORMAT_A16B16G16R16F;
|
||||
|
||||
case ImageFormatId::BC1:
|
||||
return IwiFormat::IMG_FORMAT_DXT1;
|
||||
|
||||
case ImageFormatId::BC2:
|
||||
return IwiFormat::IMG_FORMAT_DXT3;
|
||||
|
||||
case ImageFormatId::BC3:
|
||||
return IwiFormat::IMG_FORMAT_DXT5;
|
||||
|
||||
case ImageFormatId::BC5:
|
||||
return IwiFormat::IMG_FORMAT_DXN;
|
||||
|
||||
default:
|
||||
return IwiFormat::IMG_FORMAT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
return GetIwiFormatForImageFormat(imageFormat) != IwiFormat::IMG_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
std::string IwiWriter::GetFileExtension()
|
||||
{
|
||||
return ".iwi";
|
||||
}
|
||||
|
||||
void IwiWriter::WriteVersion(std::ostream& stream)
|
||||
{
|
||||
IwiVersion version{};
|
||||
version.tag[0] = 'I';
|
||||
version.tag[1] = 'W';
|
||||
version.tag[2] = 'i';
|
||||
version.version = 27;
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = 1;
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = 1;
|
||||
header.flags |= IMG_FLAG_CUBEMAP;
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = static_cast<uint16_t>(texture.GetDepth());
|
||||
header.flags |= IMG_FLAG_VOLMAP;
|
||||
}
|
||||
|
||||
void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
|
||||
{
|
||||
assert(texture != nullptr);
|
||||
|
||||
WriteVersion(stream);
|
||||
|
||||
IwiHeader header{};
|
||||
header.flags = 0;
|
||||
header.gamma = 0.0f;
|
||||
|
||||
header.format = static_cast<int8_t>(GetIwiFormatForImageFormat(texture->GetFormat()));
|
||||
|
||||
if (!texture->HasMipMaps())
|
||||
header.flags |= IMG_FLAG_NOMIPMAPS;
|
||||
|
||||
for (auto& i : header.maxGlossForMip)
|
||||
i = 0;
|
||||
|
||||
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
|
||||
|
||||
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
|
||||
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
currentFileSize += mipLevelSize;
|
||||
|
||||
if (currentMipLevel < static_cast<int>(std::extent_v<decltype(iwi27::IwiHeader::fileSizeForPicmip)>))
|
||||
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
|
||||
}
|
||||
|
||||
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
|
||||
{
|
||||
FillHeader2D(header, *texture2D);
|
||||
}
|
||||
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
|
||||
{
|
||||
FillHeaderCube(header, *textureCube);
|
||||
}
|
||||
else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
|
||||
{
|
||||
FillHeader3D(header, *texture3D);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&header), sizeof(IwiHeader));
|
||||
|
||||
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IImageWriter.h"
|
||||
#include "Image/IwiTypes.h"
|
||||
|
||||
namespace iwi27
|
||||
{
|
||||
class IwiWriter final : public IImageWriter
|
||||
{
|
||||
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
|
||||
|
||||
static void WriteVersion(std::ostream& stream);
|
||||
static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
|
||||
static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
|
||||
static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
|
||||
|
||||
public:
|
||||
IwiWriter();
|
||||
IwiWriter(const IwiWriter& other) = delete;
|
||||
IwiWriter(IwiWriter&& other) noexcept = delete;
|
||||
~IwiWriter() override;
|
||||
|
||||
IwiWriter& operator=(const IwiWriter& other) = delete;
|
||||
IwiWriter& operator=(IwiWriter&& other) noexcept = delete;
|
||||
|
||||
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
|
||||
std::string GetFileExtension() override;
|
||||
void DumpImage(std::ostream& stream, const Texture* texture) override;
|
||||
};
|
||||
} // namespace iwi27
|
@ -1,136 +0,0 @@
|
||||
#include "IwiWriter6.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace iwi6;
|
||||
|
||||
IwiWriter::IwiWriter() = default;
|
||||
|
||||
IwiWriter::~IwiWriter() = default;
|
||||
|
||||
IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
switch (imageFormat->GetId())
|
||||
{
|
||||
case ImageFormatId::R8_G8_B8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_RGB;
|
||||
|
||||
case ImageFormatId::R8_G8_B8_A8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_RGBA;
|
||||
|
||||
case ImageFormatId::A8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_ALPHA;
|
||||
|
||||
case ImageFormatId::BC1:
|
||||
return IwiFormat::IMG_FORMAT_DXT1;
|
||||
|
||||
case ImageFormatId::BC2:
|
||||
return IwiFormat::IMG_FORMAT_DXT3;
|
||||
|
||||
case ImageFormatId::BC3:
|
||||
return IwiFormat::IMG_FORMAT_DXT5;
|
||||
|
||||
case ImageFormatId::BC5:
|
||||
return IwiFormat::IMG_FORMAT_DXN;
|
||||
|
||||
default:
|
||||
return IwiFormat::IMG_FORMAT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
void IwiWriter::WriteVersion(std::ostream& stream)
|
||||
{
|
||||
IwiVersion version{};
|
||||
version.tag[0] = 'I';
|
||||
version.tag[1] = 'W';
|
||||
version.tag[2] = 'i';
|
||||
version.version = 6;
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = 1u;
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = 1u;
|
||||
header.flags |= IMG_FLAG_CUBEMAP;
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = static_cast<uint16_t>(texture.GetDepth());
|
||||
header.flags |= IMG_FLAG_VOLMAP;
|
||||
}
|
||||
|
||||
bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
return GetIwiFormatForImageFormat(imageFormat) != IwiFormat::IMG_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
std::string IwiWriter::GetFileExtension()
|
||||
{
|
||||
return ".iwi";
|
||||
}
|
||||
|
||||
void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
|
||||
{
|
||||
assert(texture != nullptr);
|
||||
|
||||
WriteVersion(stream);
|
||||
|
||||
IwiHeader header{};
|
||||
header.flags = 0;
|
||||
|
||||
header.format = static_cast<int8_t>(GetIwiFormatForImageFormat(texture->GetFormat()));
|
||||
|
||||
if (!texture->HasMipMaps())
|
||||
header.flags |= IMG_FLAG_NOMIPMAPS;
|
||||
|
||||
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
|
||||
|
||||
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
|
||||
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
currentFileSize += mipLevelSize;
|
||||
|
||||
if (currentMipLevel < static_cast<int>(std::extent_v<decltype(IwiHeader::fileSizeForPicmip)>))
|
||||
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
|
||||
}
|
||||
|
||||
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
|
||||
{
|
||||
FillHeader2D(header, *texture2D);
|
||||
}
|
||||
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
|
||||
{
|
||||
FillHeaderCube(header, *textureCube);
|
||||
}
|
||||
else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
|
||||
{
|
||||
FillHeader3D(header, *texture3D);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&header), sizeof(IwiHeader));
|
||||
|
||||
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IImageWriter.h"
|
||||
#include "Image/IwiTypes.h"
|
||||
|
||||
namespace iwi6
|
||||
{
|
||||
class IwiWriter final : public IImageWriter
|
||||
{
|
||||
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
|
||||
|
||||
static void WriteVersion(std::ostream& stream);
|
||||
static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
|
||||
static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
|
||||
static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
|
||||
|
||||
public:
|
||||
IwiWriter();
|
||||
IwiWriter(const IwiWriter& other) = delete;
|
||||
IwiWriter(IwiWriter&& other) noexcept = delete;
|
||||
~IwiWriter() override;
|
||||
|
||||
IwiWriter& operator=(const IwiWriter& other) = delete;
|
||||
IwiWriter& operator=(IwiWriter&& other) noexcept = delete;
|
||||
|
||||
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
|
||||
std::string GetFileExtension() override;
|
||||
void DumpImage(std::ostream& stream, const Texture* texture) override;
|
||||
};
|
||||
} // namespace iwi6
|
@ -1,136 +0,0 @@
|
||||
#include "IwiWriter8.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace iwi8;
|
||||
|
||||
IwiWriter::IwiWriter() = default;
|
||||
|
||||
IwiWriter::~IwiWriter() = default;
|
||||
|
||||
IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
switch (imageFormat->GetId())
|
||||
{
|
||||
case ImageFormatId::R8_G8_B8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_RGB;
|
||||
|
||||
case ImageFormatId::R8_G8_B8_A8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_RGBA;
|
||||
|
||||
case ImageFormatId::A8:
|
||||
return IwiFormat::IMG_FORMAT_BITMAP_ALPHA;
|
||||
|
||||
case ImageFormatId::BC1:
|
||||
return IwiFormat::IMG_FORMAT_DXT1;
|
||||
|
||||
case ImageFormatId::BC2:
|
||||
return IwiFormat::IMG_FORMAT_DXT3;
|
||||
|
||||
case ImageFormatId::BC3:
|
||||
return IwiFormat::IMG_FORMAT_DXT5;
|
||||
|
||||
case ImageFormatId::BC5:
|
||||
return IwiFormat::IMG_FORMAT_DXN;
|
||||
|
||||
default:
|
||||
return IwiFormat::IMG_FORMAT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
void IwiWriter::WriteVersion(std::ostream& stream)
|
||||
{
|
||||
IwiVersion version{};
|
||||
version.tag[0] = 'I';
|
||||
version.tag[1] = 'W';
|
||||
version.tag[2] = 'i';
|
||||
version.version = 8;
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&version), sizeof(IwiVersion));
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeader2D(IwiHeader& header, const Texture2D& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = 1u;
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeaderCube(IwiHeader& header, const TextureCube& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = 1u;
|
||||
header.flags |= IMG_FLAG_MAPTYPE_CUBE;
|
||||
}
|
||||
|
||||
void IwiWriter::FillHeader3D(IwiHeader& header, const Texture3D& texture)
|
||||
{
|
||||
header.dimensions[0] = static_cast<uint16_t>(texture.GetWidth());
|
||||
header.dimensions[1] = static_cast<uint16_t>(texture.GetHeight());
|
||||
header.dimensions[2] = static_cast<uint16_t>(texture.GetDepth());
|
||||
header.flags |= IMG_FLAG_MAPTYPE_3D;
|
||||
}
|
||||
|
||||
bool IwiWriter::SupportsImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
return GetIwiFormatForImageFormat(imageFormat) != IwiFormat::IMG_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
std::string IwiWriter::GetFileExtension()
|
||||
{
|
||||
return ".iwi";
|
||||
}
|
||||
|
||||
void IwiWriter::DumpImage(std::ostream& stream, const Texture* texture)
|
||||
{
|
||||
assert(texture != nullptr);
|
||||
|
||||
WriteVersion(stream);
|
||||
|
||||
IwiHeader header{};
|
||||
header.flags = 0;
|
||||
|
||||
header.format = static_cast<int8_t>(GetIwiFormatForImageFormat(texture->GetFormat()));
|
||||
|
||||
if (!texture->HasMipMaps())
|
||||
header.flags |= IMG_FLAG_NOMIPMAPS;
|
||||
|
||||
auto currentFileSize = sizeof(IwiVersion) + sizeof(IwiHeader);
|
||||
|
||||
const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
|
||||
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
currentFileSize += mipLevelSize;
|
||||
|
||||
if (currentMipLevel < static_cast<int>(std::extent_v<decltype(IwiHeader::fileSizeForPicmip)>))
|
||||
header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
|
||||
}
|
||||
|
||||
if (const auto* texture2D = dynamic_cast<const Texture2D*>(texture))
|
||||
{
|
||||
FillHeader2D(header, *texture2D);
|
||||
}
|
||||
else if (const auto* textureCube = dynamic_cast<const TextureCube*>(texture))
|
||||
{
|
||||
FillHeaderCube(header, *textureCube);
|
||||
}
|
||||
else if (const auto* texture3D = dynamic_cast<const Texture3D*>(texture))
|
||||
{
|
||||
FillHeader3D(header, *texture3D);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
stream.write(reinterpret_cast<char*>(&header), sizeof(IwiHeader));
|
||||
|
||||
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
stream.write(reinterpret_cast<const char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IImageWriter.h"
|
||||
#include "Image/IwiTypes.h"
|
||||
|
||||
namespace iwi8
|
||||
{
|
||||
class IwiWriter final : public IImageWriter
|
||||
{
|
||||
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
|
||||
|
||||
static void WriteVersion(std::ostream& stream);
|
||||
static void FillHeader2D(IwiHeader& header, const Texture2D& texture);
|
||||
static void FillHeaderCube(IwiHeader& header, const TextureCube& texture);
|
||||
static void FillHeader3D(IwiHeader& header, const Texture3D& texture);
|
||||
|
||||
public:
|
||||
IwiWriter();
|
||||
IwiWriter(const IwiWriter& other) = delete;
|
||||
IwiWriter(IwiWriter&& other) noexcept = delete;
|
||||
~IwiWriter() override;
|
||||
|
||||
IwiWriter& operator=(const IwiWriter& other) = delete;
|
||||
IwiWriter& operator=(IwiWriter&& other) noexcept = delete;
|
||||
|
||||
bool SupportsImageFormat(const ImageFormat* imageFormat) override;
|
||||
std::string GetFileExtension() override;
|
||||
void DumpImage(std::ostream& stream, const Texture* texture) override;
|
||||
};
|
||||
} // namespace iwi8
|
Reference in New Issue
Block a user