mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
Add dumper for DDS and texture converter for reordering colors
This commit is contained in:
parent
362094b6f0
commit
ccef1dca28
@ -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 ""
|
@ -1,42 +1,27 @@
|
|||||||
#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
|
||||||
{
|
{
|
||||||
DDPF_ALPHAPIXELS = 0x1,
|
DDPF_ALPHAPIXELS = 0x1,
|
||||||
DDPF_ALPHA = 0x2,
|
DDPF_ALPHA = 0x2,
|
||||||
DDPF_FOURCC = 0x4,
|
DDPF_FOURCC = 0x4,
|
||||||
DDPF_RGB = 0x40,
|
DDPF_RGB = 0x40,
|
||||||
DDPF_YUV = 0x200,
|
DDPF_YUV = 0x200,
|
||||||
DDPF_LUMINANCE = 0x20000
|
DDPF_LUMINANCE = 0x20000
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DDS_PIXELFORMAT
|
enum DDS_HEADER_FLAGS
|
||||||
{
|
{
|
||||||
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
|
|
||||||
{
|
|
||||||
DDSD_CAPS = 0x1,
|
DDSD_CAPS = 0x1,
|
||||||
DDSD_HEIGHT = 0x2,
|
DDSD_HEIGHT = 0x2,
|
||||||
DDSD_WIDTH = 0x4,
|
DDSD_WIDTH = 0x4,
|
||||||
@ -45,17 +30,17 @@ namespace dds
|
|||||||
DDSD_MIPMAPCOUNT = 0x20000,
|
DDSD_MIPMAPCOUNT = 0x20000,
|
||||||
DDSD_LINEARSIZE = 0x80000,
|
DDSD_LINEARSIZE = 0x80000,
|
||||||
DDSD_DEPTH = 0x800000,
|
DDSD_DEPTH = 0x800000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_HEADER_CAPS
|
enum DDS_HEADER_CAPS
|
||||||
{
|
{
|
||||||
DDSCAPS_COMPLEX = 0x8,
|
DDSCAPS_COMPLEX = 0x8,
|
||||||
DDSCAPS_TEXTURE = 0x1000,
|
DDSCAPS_TEXTURE = 0x1000,
|
||||||
DDSCAPS_MIPMAP = 0x400000,
|
DDSCAPS_MIPMAP = 0x400000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_HEADER_CAPS2
|
enum DDS_HEADER_CAPS2
|
||||||
{
|
{
|
||||||
DDSCAPS2_CUBEMAP = 0x200,
|
DDSCAPS2_CUBEMAP = 0x200,
|
||||||
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
|
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
|
||||||
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
|
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
|
||||||
@ -64,10 +49,22 @@ namespace dds
|
|||||||
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
|
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
|
||||||
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
|
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
|
||||||
DDSCAPS2_VOLUME = 0x200000,
|
DDSCAPS2_VOLUME = 0x200000,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DDS_HEADER
|
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 dwSize;
|
||||||
uint32_t dwFlags;
|
uint32_t dwFlags;
|
||||||
uint32_t dwHeight;
|
uint32_t dwHeight;
|
||||||
@ -82,26 +79,36 @@ namespace dds
|
|||||||
uint32_t dwCaps3;
|
uint32_t dwCaps3;
|
||||||
uint32_t dwCaps4;
|
uint32_t dwCaps4;
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DDS_HEADER_DXT10
|
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
|
||||||
|
{
|
||||||
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;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
@ -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,
|
||||||
|
};
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
@ -2,16 +2,15 @@
|
|||||||
#include "ImageFormat.h"
|
#include "ImageFormat.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class TextureType
|
||||||
|
{
|
||||||
|
T_2D,
|
||||||
|
T_CUBE,
|
||||||
|
T_3D
|
||||||
|
};
|
||||||
|
|
||||||
class Texture
|
class Texture
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
TYPE_2D,
|
|
||||||
TYPE_CUBE,
|
|
||||||
TYPE_3D
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
||||||
|
229
src/ObjCommon/Image/TextureConverter.cpp
Normal file
229
src/ObjCommon/Image/TextureConverter.cpp
Normal 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;
|
||||||
|
}
|
30
src/ObjCommon/Image/TextureConverter.h
Normal file
30
src/ObjCommon/Image/TextureConverter.h
Normal 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();
|
||||||
|
};
|
@ -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
43
test/ObjCommonTests.lua
Normal 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
|
22
test/ObjCommonTests/Image/ImageFormatTests.cpp
Normal file
22
test/ObjCommonTests/Image/ImageFormatTests.cpp
Normal 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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user