Add dumper for DDS and texture converter for reordering colors

This commit is contained in:
Jan 2020-09-04 12:51:13 +02:00
parent 362094b6f0
commit ccef1dca28
11 changed files with 708 additions and 362 deletions

View File

@ -163,11 +163,13 @@ group ""
-- ======================== -- ========================
-- Tests -- Tests
-- ======================== -- ========================
include "test/ObjCommonTests.lua"
include "test/ZoneCodeGeneratorTests.lua" include "test/ZoneCodeGeneratorTests.lua"
include "test/ZoneCommonTests.lua" include "test/ZoneCommonTests.lua"
-- Tests group: Unit test and other tests projects -- Tests group: Unit test and other tests projects
group "Tests" group "Tests"
ObjCommonTests:project()
ZoneCodeGeneratorTests:project() ZoneCodeGeneratorTests:project()
ZoneCommonTests:project() ZoneCommonTests:project()
group "" group ""

View File

@ -1,16 +1,13 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <dxgiformat.h>
namespace dds constexpr uint32_t MakeFourCc(const char ch0, const char ch1, const char ch2, const char ch3)
{ {
constexpr uint32_t MakeFourCc(const char c0, const char c1, const char c2, const char c3) return static_cast<uint32_t>(ch0)
{ | static_cast<uint32_t>(ch1) << 8
return static_cast<uint32_t>(c0) | static_cast<uint32_t>(ch2) << 16
| static_cast<uint32_t>(c1) << 8 | static_cast<uint32_t>(ch3) << 24;
| static_cast<uint32_t>(c2) << 16
| static_cast<uint32_t>(c3) << 24;
} }
enum DDP_FLAGS enum DDP_FLAGS
@ -23,18 +20,6 @@ namespace dds
DDPF_LUMINANCE = 0x20000 DDPF_LUMINANCE = 0x20000
}; };
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;
};
enum DDS_HEADER_FLAGS enum DDS_HEADER_FLAGS
{ {
DDSD_CAPS = 0x1, DDSD_CAPS = 0x1,
@ -66,6 +51,18 @@ namespace dds
DDSCAPS2_VOLUME = 0x200000, 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_HEADER struct DDS_HEADER
{ {
uint32_t dwSize; uint32_t dwSize;
@ -84,24 +81,34 @@ namespace dds
uint32_t dwReserved2; uint32_t dwReserved2;
}; };
enum DDS_DIMENSION enum D3D10_RESOURCE_DIMENSION
{ {
DDS_DIMENSION_TEXTURE1D = 0x2, D3D10_RESOURCE_DIMENSION_UNKNOWN,
DDS_DIMENSION_TEXTURE2D, D3D10_RESOURCE_DIMENSION_BUFFER,
DDS_DIMENSION_TEXTURE3D D3D10_RESOURCE_DIMENSION_TEXTURE1D,
D3D10_RESOURCE_DIMENSION_TEXTURE2D,
D3D10_RESOURCE_DIMENSION_TEXTURE3D
}; };
enum DDS_RESOURCE_MISC enum DDS_HEADER_DXT10_MISC
{ {
DDS_RESOURCE_MISC_TEXTURECUBE = 0x4 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,
};
struct DDS_HEADER_DXT10 struct DDS_HEADER_DXT10
{ {
DXGI_FORMAT dxgiFormat; DXGI_FORMAT dxgiFormat;
DDS_DIMENSION resourceDimension; D3D10_RESOURCE_DIMENSION resourceDimension;
uint32_t miscFlag; uint32_t miscFlag;
uint32_t arraySize; uint32_t arraySize;
uint32_t miscFlags2; uint32_t miscFlags2;
}; };
}

View File

@ -1,6 +1,5 @@
#include "ImageFormat.h" #include "ImageFormat.h"
ImageFormat::ImageFormat(const ImageFormatId id, const DXGI_FORMAT dxgiFormat) ImageFormat::ImageFormat(const ImageFormatId id, const DXGI_FORMAT dxgiFormat)
{ {
m_id = id; m_id = id;
@ -21,25 +20,17 @@ ImageFormatUnsigned::ImageFormatUnsigned(const ImageFormatId id, const DXGI_FORM
const unsigned bitsPerPixel, const unsigned rOffset, const unsigned rSize, const unsigned bitsPerPixel, const unsigned rOffset, const unsigned rSize,
const unsigned gOffset, const unsigned gSize, const unsigned bOffset, const unsigned gOffset, const unsigned gSize, const unsigned bOffset,
const unsigned bSize, const unsigned aOffset, const unsigned aSize) const unsigned bSize, const unsigned aOffset, const unsigned aSize)
: ImageFormat(id, dxgiFormat) : ImageFormat(id, 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)
{ {
m_bits_per_pixel = bitsPerPixel;
m_r_offset = rOffset;
m_r_size = rSize;
m_r_mask = (UINT64_MAX << rOffset) & ~(UINT64_MAX << (rOffset + rSize));
m_g_offset = gOffset;
m_g_size = gSize;
m_g_mask = (UINT64_MAX << gOffset) & ~(UINT64_MAX << (gOffset + gSize));
m_b_offset = bOffset;
m_b_size = bSize;
m_b_mask = (UINT64_MAX << bOffset) & ~(UINT64_MAX << (bOffset + bSize));
m_a_offset = aOffset;
m_a_size = aSize;
m_a_mask = (UINT64_MAX << aOffset) & ~(UINT64_MAX << (aOffset + aSize));
} }
ImageFormatType ImageFormatUnsigned::GetType() const ImageFormatType ImageFormatUnsigned::GetType() const
@ -47,6 +38,15 @@ ImageFormatType ImageFormatUnsigned::GetType() const
return ImageFormatType::UNSIGNED; return ImageFormatType::UNSIGNED;
} }
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;
}
size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height, size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height,
const unsigned depth) const const unsigned depth) const
{ {
@ -64,17 +64,12 @@ size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const uns
return mipWidth * mipHeight * mipDepth * m_bits_per_pixel / 8; return mipWidth * mipHeight * mipDepth * m_bits_per_pixel / 8;
} }
size_t ImageFormatUnsigned::GetPitch(const unsigned width) const
{
return (width * m_bits_per_pixel + 7) / 8;
}
ImageFormatBlockCompressed::ImageFormatBlockCompressed(const ImageFormatId id, const DXGI_FORMAT dxgiFormat, ImageFormatBlockCompressed::ImageFormatBlockCompressed(const ImageFormatId id, const DXGI_FORMAT dxgiFormat,
const unsigned blockSize, const unsigned bitsPerBlock) const unsigned blockSize, const unsigned bitsPerBlock)
: ImageFormat(id, dxgiFormat) : ImageFormat(id, dxgiFormat),
m_block_size(blockSize),
m_bits_per_block(bitsPerBlock)
{ {
m_block_size = blockSize;
m_bits_per_block = bitsPerBlock;
} }
ImageFormatType ImageFormatBlockCompressed::GetType() const ImageFormatType ImageFormatBlockCompressed::GetType() const
@ -82,6 +77,18 @@ ImageFormatType ImageFormatBlockCompressed::GetType() const
return ImageFormatType::BLOCK_COMPRESSED; return ImageFormatType::BLOCK_COMPRESSED;
} }
size_t ImageFormatBlockCompressed::GetPitch(const unsigned mipLevel, const unsigned width) const
{
unsigned mipWidth = width >> mipLevel;
if (mipWidth == 0)
mipWidth = 1;
const unsigned blockCount = (mipWidth + m_block_size - 1) / m_block_size;
return blockCount * m_bits_per_block / 8;
}
size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width,
const unsigned height, const unsigned depth) const const unsigned height, const unsigned depth) const
{ {
@ -103,15 +110,34 @@ size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, co
return blockCount * m_bits_per_block / 8; return blockCount * m_bits_per_block / 8;
} }
size_t ImageFormatBlockCompressed::GetPitch(const unsigned width) const bool ImageFormatUnsigned::HasR() const
{ {
return (width + m_block_size - 1) / m_block_size * (m_bits_per_block / 8); return m_r_size > 0;
}
bool ImageFormatUnsigned::HasG() const
{
return m_g_size > 0;
}
bool ImageFormatUnsigned::HasB() const
{
return m_b_size > 0;
}
bool ImageFormatUnsigned::HasA() const
{
return m_a_size > 0;
} }
const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8(ImageFormatId::R8_G8_B8, DXGI_FORMAT_UNKNOWN, const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8(ImageFormatId::R8_G8_B8, DXGI_FORMAT_UNKNOWN,
24, 0, 8, 8, 8, 16, 8, 0, 0); 24, 0, 8, 8, 8, 16, 8, 0, 0);
const ImageFormatUnsigned ImageFormat::FORMAT_B8_G8_R8_X8(ImageFormatId::B8_G8_R8_X8, 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, DXGI_FORMAT_R8G8B8A8_UNORM, const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8_A8(ImageFormatId::R8_G8_B8_A8, DXGI_FORMAT_R8G8B8A8_UNORM,
32, 0, 8, 8, 8, 16, 8, 24, 8); 32, 0, 8, 8, 8, 16, 8, 24, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_B8_G8_R8_A8(ImageFormatId::B8_G8_R8_A8, DXGI_FORMAT_B8G8R8A8_UNORM,
32, 16, 8, 8, 8, 0, 8, 24, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_A8(ImageFormatId::A8, DXGI_FORMAT_A8_UNORM, const ImageFormatUnsigned ImageFormat::FORMAT_A8(ImageFormatId::A8, DXGI_FORMAT_A8_UNORM,
8, 0, 0, 0, 0, 0, 0, 0, 8); 8, 0, 0, 0, 0, 0, 0, 0, 8);
const ImageFormatUnsigned ImageFormat::FORMAT_R16_G16_B16_A16_FLOAT(ImageFormatId::R16_G16_B16_A16_FLOAT, const ImageFormatUnsigned ImageFormat::FORMAT_R16_G16_B16_A16_FLOAT(ImageFormatId::R16_G16_B16_A16_FLOAT,
@ -122,3 +148,18 @@ const ImageFormatBlockCompressed ImageFormat::FORMAT_BC2(ImageFormatId::BC2, DXG
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(ImageFormatId::BC3, DXGI_FORMAT_BC3_UNORM, 4, 128); const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(ImageFormatId::BC3, DXGI_FORMAT_BC3_UNORM, 4, 128);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC4(ImageFormatId::BC4, DXGI_FORMAT_BC4_UNORM, 4, 64); const ImageFormatBlockCompressed ImageFormat::FORMAT_BC4(ImageFormatId::BC4, DXGI_FORMAT_BC4_UNORM, 4, 64);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC5(ImageFormatId::BC5, DXGI_FORMAT_BC5_UNORM, 4, 128); const ImageFormatBlockCompressed ImageFormat::FORMAT_BC5(ImageFormatId::BC5, 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_BC1,
&FORMAT_BC2,
&FORMAT_BC3,
&FORMAT_BC4,
&FORMAT_BC5,
};

View File

@ -5,16 +5,20 @@
enum class ImageFormatId enum class ImageFormatId
{ {
UNKNOWN, UNKNOWN = -1,
R8_G8_B8, R8_G8_B8,
B8_G8_R8_X8,
R8_G8_B8_A8, R8_G8_B8_A8,
B8_G8_R8_A8,
A8, A8,
R16_G16_B16_A16_FLOAT, R16_G16_B16_A16_FLOAT,
BC1, BC1,
BC2, BC2,
BC3, BC3,
BC4, BC4,
BC5 BC5,
MAX
}; };
enum class ImageFormatType enum class ImageFormatType
@ -42,11 +46,13 @@ public:
DXGI_FORMAT GetDxgiFormat() const; DXGI_FORMAT GetDxgiFormat() const;
virtual ImageFormatType GetType() const = 0; virtual ImageFormatType GetType() const = 0;
virtual size_t GetPitch(unsigned mipLevel, unsigned width) const = 0;
virtual size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const = 0; virtual size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const = 0;
virtual size_t GetPitch(unsigned width) const = 0;
static const ImageFormatUnsigned FORMAT_R8_G8_B8; 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_R8_G8_B8_A8;
static const ImageFormatUnsigned FORMAT_B8_G8_R8_A8;
static const ImageFormatUnsigned FORMAT_A8; static const ImageFormatUnsigned FORMAT_A8;
static const ImageFormatUnsigned FORMAT_R16_G16_B16_A16_FLOAT; //TODO: Float not unsigned static const ImageFormatUnsigned FORMAT_R16_G16_B16_A16_FLOAT; //TODO: Float not unsigned
static const ImageFormatBlockCompressed FORMAT_BC1; static const ImageFormatBlockCompressed FORMAT_BC1;
@ -54,6 +60,7 @@ public:
static const ImageFormatBlockCompressed FORMAT_BC3; static const ImageFormatBlockCompressed FORMAT_BC3;
static const ImageFormatBlockCompressed FORMAT_BC4; static const ImageFormatBlockCompressed FORMAT_BC4;
static const ImageFormatBlockCompressed FORMAT_BC5; static const ImageFormatBlockCompressed FORMAT_BC5;
static const ImageFormat* const ALL_FORMATS[static_cast<unsigned>(ImageFormatId::MAX)];
}; };
class ImageFormatUnsigned final : public ImageFormat class ImageFormatUnsigned final : public ImageFormat
@ -62,24 +69,25 @@ public:
unsigned m_bits_per_pixel; unsigned m_bits_per_pixel;
unsigned m_r_offset; unsigned m_r_offset;
unsigned m_r_size; unsigned m_r_size;
uint64_t m_r_mask;
unsigned m_g_offset; unsigned m_g_offset;
unsigned m_g_size; unsigned m_g_size;
uint64_t m_g_mask;
unsigned m_b_offset; unsigned m_b_offset;
unsigned m_b_size; unsigned m_b_size;
uint64_t m_b_mask;
unsigned m_a_offset; unsigned m_a_offset;
unsigned m_a_size; unsigned m_a_size;
uint64_t m_a_mask;
ImageFormatUnsigned(ImageFormatId id, DXGI_FORMAT dxgiFormat, unsigned bitsPerPixel, unsigned rOffset, ImageFormatUnsigned(ImageFormatId id, DXGI_FORMAT dxgiFormat, unsigned bitsPerPixel, unsigned rOffset,
unsigned rSize, unsigned gOffset, unsigned gSize, unsigned bOffset, unsigned bSize, unsigned rSize, unsigned gOffset, unsigned gSize, unsigned bOffset, unsigned bSize,
unsigned aOffset, unsigned aSize); unsigned aOffset, unsigned aSize);
ImageFormatType GetType() const override; ImageFormatType GetType() const override;
size_t GetPitch(unsigned mipLevel, unsigned width) const override;
size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override; size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
size_t GetPitch(unsigned width) const override;
bool HasR() const;
bool HasG() const;
bool HasB() const;
bool HasA() const;
}; };
class ImageFormatBlockCompressed final : public ImageFormat class ImageFormatBlockCompressed final : public ImageFormat
@ -91,6 +99,6 @@ public:
ImageFormatBlockCompressed(ImageFormatId id, DXGI_FORMAT dxgiFormat, unsigned blockSize, unsigned bitsPerBlock); ImageFormatBlockCompressed(ImageFormatId id, DXGI_FORMAT dxgiFormat, unsigned blockSize, unsigned bitsPerBlock);
ImageFormatType GetType() const override; ImageFormatType GetType() const override;
size_t GetPitch(unsigned mipLevel, unsigned width) const override;
size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override; size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
size_t GetPitch(unsigned width) const override;
}; };

View File

@ -111,9 +111,9 @@ Texture2D& Texture2D::operator=(Texture2D&& other) noexcept
return *this; return *this;
} }
Texture::Type Texture2D::GetType() const TextureType Texture2D::GetTextureType() const
{ {
return Type::TYPE_2D; return TextureType::T_2D;
} }
unsigned Texture2D::GetWidth() const unsigned Texture2D::GetWidth() const
@ -213,12 +213,17 @@ TextureCube& TextureCube::operator=(TextureCube&& other) noexcept
return *this; return *this;
} }
Texture::Type TextureCube::GetType() const TextureType TextureCube::GetTextureType() const
{ {
return Type::TYPE_CUBE; return TextureType::T_CUBE;
} }
int TextureCube::GetFaceCount() const int TextureCube::GetFaceCount() const
{
return 6;
}
size_t TextureCube::GetSizeOfMipLevel(const int mipLevel) const
{ {
return FACE_COUNT; return FACE_COUNT;
} }
@ -290,9 +295,9 @@ Texture3D& Texture3D::operator=(Texture3D&& other) noexcept
return *this; return *this;
} }
Texture::Type Texture3D::GetType() const TextureType Texture3D::GetTextureType() const
{ {
return Type::TYPE_3D; return TextureType::T_3D;
} }
unsigned Texture3D::GetWidth() const unsigned Texture3D::GetWidth() const

View File

@ -2,16 +2,15 @@
#include "ImageFormat.h" #include "ImageFormat.h"
#include <cstdint> #include <cstdint>
class Texture enum class TextureType
{ {
public: T_2D,
enum class Type T_CUBE,
{ T_3D
TYPE_2D,
TYPE_CUBE,
TYPE_3D
}; };
class Texture
{
protected: protected:
const ImageFormat* m_format; const ImageFormat* m_format;
bool m_has_mip_maps; bool m_has_mip_maps;
@ -28,8 +27,8 @@ public:
Texture& operator=(const Texture& other) = delete; Texture& operator=(const Texture& other) = delete;
virtual TextureType GetTextureType() const = 0;
const ImageFormat* GetFormat() const; const ImageFormat* GetFormat() const;
virtual Type GetType() const = 0;
virtual unsigned GetWidth() const = 0; virtual unsigned GetWidth() const = 0;
virtual unsigned GetHeight() const = 0; virtual unsigned GetHeight() const = 0;
@ -63,7 +62,7 @@ public:
Texture2D& operator=(const Texture2D& other) = delete; Texture2D& operator=(const Texture2D& other) = delete;
Texture2D& operator=(Texture2D&& other) noexcept; Texture2D& operator=(Texture2D&& other) noexcept;
Type GetType() const override; TextureType GetTextureType() const override;
unsigned GetWidth() const override; unsigned GetWidth() const override;
unsigned GetHeight() const override; unsigned GetHeight() const override;
@ -90,10 +89,11 @@ public:
TextureCube& operator=(const TextureCube& other) = delete; TextureCube& operator=(const TextureCube& other) = delete;
TextureCube& operator=(TextureCube&& other) noexcept; TextureCube& operator=(TextureCube&& other) noexcept;
Type GetType() const override; TextureType GetTextureType() const override;
int GetFaceCount() const override; int GetFaceCount() const override;
size_t GetSizeOfMipLevel(int mipLevel) const override;
uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
}; };
@ -113,7 +113,7 @@ public:
Texture3D& operator=(const Texture3D& other) = delete; Texture3D& operator=(const Texture3D& other) = delete;
Texture3D& operator=(Texture3D&& other) noexcept; Texture3D& operator=(Texture3D&& other) noexcept;
Type GetType() const override; TextureType GetTextureType() const override;
unsigned GetWidth() const override; unsigned GetWidth() const override;
unsigned GetHeight() const override; unsigned GetHeight() const override;

View File

@ -0,0 +1,229 @@
#include "TextureConverter.h"
#include <cassert>
constexpr uint64_t TextureConverter::Mask1(const unsigned length)
{
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)
{
case 16:
m_read_pixel_func = [](const void* offset, unsigned bitCount)
{
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 0ui64;
};
}
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;
}
}
TextureConverter::TextureConverter(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 = new Texture2D(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(),
m_input_texture->HasMipMaps());
break;
case TextureType::T_CUBE:
m_output_texture = new TextureCube(m_output_format, m_input_texture->GetWidth(), m_input_texture->GetHeight(),
m_input_texture->HasMipMaps());
break;
case TextureType::T_3D:
m_output_texture = new 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++)
{
const auto mipLevelSize = m_input_texture->GetSizeOfMipLevel(mipLevel);
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)
{
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);
}
}
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 m_output_texture;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <functional>
#include "Texture.h"
class TextureConverter
{
Texture* m_input_texture;
Texture* m_output_texture;
const ImageFormat* m_input_format;
const ImageFormat* m_output_format;
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;
static constexpr uint64_t Mask1(unsigned length);
void SetPixelFunctions(unsigned inBitCount, unsigned outBitCount);
void CreateOutputTexture();
void ReorderUnsignedToUnsigned() const;
void ConvertUnsignedToUnsigned();
public:
TextureConverter(Texture* inputTexture, const ImageFormat* targetFormat);
Texture* Convert();
};

View File

@ -1,269 +1,229 @@
#include "DdsWriter.h" #include "DdsWriter.h"
#include <cassert> #include <cassert>
#include <map>
#include <memory>
#include "Image/DdsTypes.h" #include "Image/DdsTypes.h"
#include "Image/TextureConverter.h"
using namespace dds; const std::map<ImageFormatId, ImageFormatId> DDS_CONVERSION_TABLE
{
{ImageFormatId::R8_G8_B8, ImageFormatId::B8_G8_R8_X8},
};
class DdsWriterInternal class DdsWriterInternal
{ {
static constexpr uint32_t DDS_MAGIC = MakeFourCc('D', 'D', 'S', ' ');
static constexpr uint32_t DDS_PF_DXT10_EXTENSION = MakeFourCc('D', 'X', '1', '0');
static constexpr uint32_t DDS_PF_BC1 = MakeFourCc('D', 'X', 'T', '1');
static constexpr uint32_t DDS_PF_BC2 = MakeFourCc('D', 'X', 'T', '3');
static constexpr uint32_t DDS_PF_BC3 = MakeFourCc('D', 'X', 'T', '5');
public:
enum class ImageFormatSupportStatus
{
UNSUPPORTED,
SUPPORTED_WITH_SIMPLE_HEADER,
SUPPORTED_WITH_DXT10_HEADER
};
private:
FileAPI::IFile* m_file; FileAPI::IFile* m_file;
Texture* m_texture; Texture* m_texture;
ImageFormatSupportStatus m_support_status; std::unique_ptr<Texture> m_converted_texture;
bool m_use_dx10_extension;
void PrepareHeader(DDS_HEADER* header) const static constexpr unsigned Mask1(const unsigned length)
{ {
header->dwSize = sizeof DDS_HEADER; if (length >= sizeof(unsigned) * 8)
header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; return UINT32_MAX;
if (m_texture->HasMipMaps()) return UINT32_MAX >> (sizeof(unsigned) * 8 - length);
header->dwFlags |= DDSD_MIPMAPCOUNT;
if (m_texture->GetFormat()->GetType() == ImageFormatType::BLOCK_COMPRESSED)
header->dwFlags |= DDSD_LINEARSIZE;
else
header->dwFlags |= DDSD_PITCH;
if (m_texture->GetType() == Texture::Type::TYPE_3D)
header->dwFlags |= DDSD_DEPTH;
header->dwWidth = m_texture->GetWidth();
header->dwHeight = m_texture->GetHeight();
header->dwDepth = m_texture->GetDepth();
header->dwPitchOrLinearSize = m_texture->GetFormat()->GetPitch(m_texture->GetWidth());
header->dwMipMapCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
memset(header->dwReserved1, 0, sizeof DDS_HEADER::dwReserved1);
header->dwCaps = DDSCAPS_TEXTURE;
if (m_texture->HasMipMaps())
header->dwCaps |= DDSCAPS_MIPMAP;
if (m_texture->GetType() == Texture::Type::TYPE_CUBE || m_texture->HasMipMaps())
header->dwCaps |= DDSCAPS_COMPLEX;
header->dwCaps2 = 0;
if (m_texture->GetType() == Texture::Type::TYPE_CUBE)
{
header->dwCaps2 |=
DDSCAPS2_CUBEMAP
| DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX
| DDSCAPS2_CUBEMAP_POSITIVEY | DDSCAPS2_CUBEMAP_NEGATIVEY
| DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ;
}
else if (m_texture->GetType() == Texture::Type::TYPE_3D)
{
header->dwCaps2 |= DDSCAPS2_VOLUME;
} }
header->dwCaps3 = 0; void PopulatePixelFormatBlockCompressed(DDS_PIXELFORMAT& pf, const ImageFormatBlockCompressed* format)
header->dwCaps4 = 0; {
header->dwReserved2 = 0; pf.dwSize = sizeof(DDS_PIXELFORMAT);
} pf.dwFlags = DDPF_FOURCC;
pf.dwRGBBitCount = 0;
pf.dwRBitMask = 0;
pf.dwGBitMask = 0;
pf.dwBBitMask = 0;
pf.dwABitMask = 0;
void SetPixelFormat(DDS_PIXELFORMAT* pixelFormat) const // Use standard pixel format for DXT1-5 for maximum compatibility and only otherwise use DX10 extension
switch (format->GetDxgiFormat())
{ {
pixelFormat->dwSize = sizeof DDS_PIXELFORMAT; case DXGI_FORMAT_BC1_UNORM:
pixelFormat->dwFlags = 0; pf.dwFourCC = MakeFourCc('D', 'X', 'T', '1');
const auto* imageFormat = m_texture->GetFormat();
switch (imageFormat->GetType())
{
case ImageFormatType::UNSIGNED:
{
const auto* imageFormatUnsigned = dynamic_cast<const ImageFormatUnsigned*>(imageFormat);
if (imageFormatUnsigned->m_r_size == 0
&& imageFormatUnsigned->m_g_size == 0
&& imageFormatUnsigned->m_b_size == 0
&& imageFormatUnsigned->m_a_size > 0)
{
pixelFormat->dwFlags |= DDPF_ALPHA;
}
else
{
if (imageFormatUnsigned->m_r_size > 0
&& imageFormatUnsigned->m_g_size == 0
&& imageFormatUnsigned->m_b_size == 0)
{
pixelFormat->dwFlags |= DDPF_LUMINANCE;
}
else if (imageFormatUnsigned->m_r_size > 0
|| imageFormatUnsigned->m_g_size > 0
|| imageFormatUnsigned->m_b_size > 0)
{
pixelFormat->dwFlags |= DDPF_RGB;
}
if (imageFormatUnsigned->m_a_size > 0)
{
pixelFormat->dwFlags |= DDPF_ALPHAPIXELS;
}
}
pixelFormat->dwRGBBitCount = imageFormatUnsigned->m_bits_per_pixel;
pixelFormat->dwRBitMask = static_cast<uint32_t>(imageFormatUnsigned->m_r_mask);
pixelFormat->dwGBitMask = static_cast<uint32_t>(imageFormatUnsigned->m_g_mask);
pixelFormat->dwBBitMask = static_cast<uint32_t>(imageFormatUnsigned->m_b_mask);
pixelFormat->dwABitMask = static_cast<uint32_t>(imageFormatUnsigned->m_a_mask);
}
break; break;
case DXGI_FORMAT_BC2_UNORM:
pf.dwFourCC = MakeFourCc('D', 'X', 'T', '3');
break;
case 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: case ImageFormatType::BLOCK_COMPRESSED:
{ PopulatePixelFormatBlockCompressed(pf, dynamic_cast<const ImageFormatBlockCompressed*>(format));
pixelFormat->dwFlags |= DDPF_FOURCC;
pixelFormat->dwRGBBitCount = 0;
pixelFormat->dwRBitMask = 0;
pixelFormat->dwGBitMask = 0;
pixelFormat->dwBBitMask = 0;
pixelFormat->dwABitMask = 0;
switch (imageFormat->GetId())
{
case ImageFormatId::BC1:
pixelFormat->dwFourCC = DDS_PF_BC1;
break; break;
case ImageFormatId::BC2: case ImageFormatType::UNSIGNED:
pixelFormat->dwFourCC = DDS_PF_BC2; PopulatePixelFormatUnsigned(pf, dynamic_cast<const ImageFormatUnsigned*>(format));
break;
case ImageFormatId::BC3:
pixelFormat->dwFourCC = DDS_PF_BC3;
break; break;
default: default:
assert(false); assert(false);
break; break;
} }
} }
break;
default:
break;
}
}
static void MarkHeaderAsExtendedByHeaderDxt10(DDS_PIXELFORMAT* pixelFormat) void PopulateDdsHeader(DDS_HEADER& header)
{ {
pixelFormat->dwSize = sizeof DDS_PIXELFORMAT; header.dwSize = sizeof header;
pixelFormat->dwFlags = DDPF_FOURCC; header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
pixelFormat->dwFourCC = DDS_PF_DXT10_EXTENSION;
pixelFormat->dwRGBBitCount = 0; if (m_texture->HasMipMaps())
pixelFormat->dwRBitMask = 0; header.dwFlags |= DDSD_MIPMAPCOUNT;
pixelFormat->dwGBitMask = 0;
pixelFormat->dwBBitMask = 0; if (m_texture->GetFormat()->GetType() == ImageFormatType::BLOCK_COMPRESSED)
pixelFormat->dwABitMask = 0; 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;
} }
void PrepareHeaderDxt10(DDS_HEADER_DXT10* header) header.dwCaps3 = 0;
{ header.dwCaps4 = 0;
header->dxgiFormat = m_texture->GetFormat()->GetDxgiFormat(); header.dwReserved2 = 0;
switch (m_texture->GetType())
{
case Texture::Type::TYPE_2D:
case Texture::Type::TYPE_CUBE:
header->resourceDimension = DDS_DIMENSION_TEXTURE2D;
break;
case Texture::Type::TYPE_3D:
header->resourceDimension = DDS_DIMENSION_TEXTURE3D;
break;
} }
header->miscFlag = 0; void PopulateDxt10Header(DDS_HEADER_DXT10& header) const
if (m_texture->GetType() == Texture::Type::TYPE_CUBE) {
header->miscFlag |= DDS_RESOURCE_MISC_TEXTURECUBE; header.dxgiFormat = m_texture->GetFormat()->GetDxgiFormat();
header.miscFlag = 0;
header.miscFlags2 = 0;
header->arraySize = m_texture->GetFaceCount(); switch (m_texture->GetTextureType())
header->miscFlags2 = 0; {
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()
{
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 = std::unique_ptr<Texture>(converter.Convert());
m_texture = m_converted_texture.get();
}
} }
public: public:
static ImageFormatSupportStatus GetSupportStatusForImageFormat(const ImageFormat* format) static bool SupportsImageFormat(const ImageFormat* imageFormat)
{ {
assert(format != nullptr); return true;
if (auto* imageFormatUnsigned = dynamic_cast<const ImageFormatUnsigned*>(format))
{
if (imageFormatUnsigned->m_bits_per_pixel <= sizeof uint32_t * 8)
return ImageFormatSupportStatus::SUPPORTED_WITH_SIMPLE_HEADER;
}
else
{
switch (format->GetId())
{
case ImageFormatId::BC1:
case ImageFormatId::BC2:
case ImageFormatId::BC3:
return ImageFormatSupportStatus::SUPPORTED_WITH_SIMPLE_HEADER;
default:
break;
}
} }
return format->GetDxgiFormat() != DXGI_FORMAT_UNKNOWN static std::string GetFileExtension()
? ImageFormatSupportStatus::SUPPORTED_WITH_DXT10_HEADER {
: ImageFormatSupportStatus::UNSUPPORTED; return ".dds";
} }
DdsWriterInternal(FileAPI::IFile* file, Texture* texture) DdsWriterInternal(FileAPI::IFile* file, Texture* texture)
: m_file(file),
m_texture(texture),
m_use_dx10_extension(false)
{ {
m_file = file;
m_texture = texture;
m_support_status = GetSupportStatusForImageFormat(texture->GetFormat());
} }
bool DumpImage() void DumpImage()
{ {
if (m_file->Write(&DDS_MAGIC, sizeof uint32_t, 1) != 1) ConvertTextureIfNecessary();
return false;
DDS_HEADER ddsHeader{}; DDS_HEADER header{};
PrepareHeader(&ddsHeader); PopulateDdsHeader(header);
if (m_support_status == ImageFormatSupportStatus::SUPPORTED_WITH_SIMPLE_HEADER)
constexpr uint32_t magic = MakeFourCc('D', 'D', 'S', ' ');
m_file->Write(&magic, sizeof magic, 1);
m_file->Write(&header, sizeof header, 1);
if (m_use_dx10_extension)
{ {
SetPixelFormat(&ddsHeader.ddspf); DDS_HEADER_DXT10 dxt10{};
PopulateDxt10Header(dxt10);
if (m_file->Write(&ddsHeader, sizeof DDS_HEADER, 1) != 1) m_file->Write(&dxt10, sizeof dxt10, 1);
return false;
}
else if (m_support_status == ImageFormatSupportStatus::SUPPORTED_WITH_DXT10_HEADER)
{
DDS_HEADER_DXT10 ddsHeaderDxt10{};
MarkHeaderAsExtendedByHeaderDxt10(&ddsHeader.ddspf);
PrepareHeaderDxt10(&ddsHeaderDxt10);
if (m_file->Write(&ddsHeader, sizeof DDS_HEADER, 1) != 1
|| m_file->Write(&ddsHeaderDxt10, sizeof DDS_HEADER_DXT10, 1) != 1)
return false;
} }
const int mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1; const int mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
for (int face = 0; face < m_texture->GetFaceCount(); face++) for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
{ {
for (int mipLevel = 0; mipLevel < mipCount; mipLevel++) const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel);
{ const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel);
const size_t sizeOfMipLevel = m_texture->GetSizeOfMipLevel(mipLevel); m_file->Write(buffer, 1, mipLevelSize);
if (m_file->Write(m_texture->GetBufferForMipLevel(mipLevel, face), 1, sizeOfMipLevel) != sizeOfMipLevel)
return false;
} }
} }
return true;
}
}; };
DdsWriter::~DdsWriter() DdsWriter::~DdsWriter()
@ -271,17 +231,16 @@ DdsWriter::~DdsWriter()
bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat) bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat)
{ {
return DdsWriterInternal::GetSupportStatusForImageFormat(imageFormat) return DdsWriterInternal::SupportsImageFormat(imageFormat);
!= DdsWriterInternal::ImageFormatSupportStatus::UNSUPPORTED;
} }
std::string DdsWriter::GetFileExtension() std::string DdsWriter::GetFileExtension()
{ {
return ".dds"; return DdsWriterInternal::GetFileExtension();
} }
void DdsWriter::DumpImage(FileAPI::IFile* file, Texture* texture) void DdsWriter::DumpImage(FileAPI::IFile* file, Texture* texture)
{ {
DdsWriterInternal writer(file, texture); DdsWriterInternal internal(file, texture);
writer.DumpImage(); internal.DumpImage();
} }

43
test/ObjCommonTests.lua Normal file
View File

@ -0,0 +1,43 @@
ObjCommonTests = {}
function ObjCommonTests:include()
end
function ObjCommonTests:link()
if References:link("ObjCommonTests") then
links "ObjCommonTests"
end
end
function ObjCommonTests:use()
end
function ObjCommonTests:project()
References:reset()
local folder = TestFolder();
project "ObjCommonTests"
targetdir(TargetDirectoryTest)
location "%{wks.location}/test/%{prj.name}"
kind "SharedLib"
language "C++"
files {
path.join(folder, "ObjCommonTests/**.h"),
path.join(folder, "ObjCommonTests/**.cpp")
}
vpaths {
["*"] = {
path.join(folder, "ObjCommonTests"),
path.join(BuildFolder(), "src/ZoneCode")
}
}
self:include()
ObjCommon:include()
ObjCommon:link()
end

View File

@ -0,0 +1,22 @@
#include "CppUnitTest.h"
#include "Image/ImageFormat.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace ObjCommonTests
{
TEST_CLASS(ImageFormatTests)
{
public:
TEST_METHOD(EnsureAllFormatsArrayIndicesAreIds)
{
Assert::AreEqual(static_cast<unsigned int>(ImageFormatId::MAX), _countof(ImageFormat::ALL_FORMATS));
for(unsigned i = 0; i < _countof(ImageFormat::ALL_FORMATS); i++)
{
Assert::IsNotNull(ImageFormat::ALL_FORMATS[i]);
Assert::AreEqual(i, static_cast<unsigned>(ImageFormat::ALL_FORMATS[i]->GetId()));
}
}
};
}