mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
ObjWriting: Implement writing textures as DDS files
This commit is contained in:
parent
000022afe9
commit
5ef1e585c6
107
src/ObjCommon/Image/DdsTypes.h
Normal file
107
src/ObjCommon/Image/DdsTypes.h
Normal file
@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <dxgiformat.h>
|
||||
|
||||
namespace dds
|
||||
{
|
||||
constexpr uint32_t MakeFourCc(const char c0, const char c1, const char c2, const char c3)
|
||||
{
|
||||
return static_cast<uint32_t>(c0)
|
||||
| static_cast<uint32_t>(c1) << 8
|
||||
| static_cast<uint32_t>(c2) << 16
|
||||
| static_cast<uint32_t>(c3) << 24;
|
||||
}
|
||||
|
||||
enum DDP_FLAGS
|
||||
{
|
||||
DDPF_ALPHAPIXELS = 0x1,
|
||||
DDPF_ALPHA = 0x2,
|
||||
DDPF_FOURCC = 0x4,
|
||||
DDPF_RGB = 0x40,
|
||||
DDPF_YUV = 0x200,
|
||||
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
|
||||
{
|
||||
DDSD_CAPS = 0x1,
|
||||
DDSD_HEIGHT = 0x2,
|
||||
DDSD_WIDTH = 0x4,
|
||||
DDSD_PITCH = 0x8,
|
||||
DDSD_PIXELFORMAT = 0x1000,
|
||||
DDSD_MIPMAPCOUNT = 0x20000,
|
||||
DDSD_LINEARSIZE = 0x80000,
|
||||
DDSD_DEPTH = 0x800000,
|
||||
};
|
||||
|
||||
enum DDS_HEADER_CAPS
|
||||
{
|
||||
DDSCAPS_COMPLEX = 0x8,
|
||||
DDSCAPS_TEXTURE = 0x1000,
|
||||
DDSCAPS_MIPMAP = 0x400000,
|
||||
};
|
||||
|
||||
enum DDS_HEADER_CAPS2
|
||||
{
|
||||
DDSCAPS2_CUBEMAP = 0x200,
|
||||
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
|
||||
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
|
||||
DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
|
||||
DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
|
||||
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
|
||||
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
|
||||
DDSCAPS2_VOLUME = 0x200000,
|
||||
};
|
||||
|
||||
struct DDS_HEADER
|
||||
{
|
||||
uint32_t dwSize;
|
||||
uint32_t dwFlags;
|
||||
uint32_t dwHeight;
|
||||
uint32_t dwWidth;
|
||||
uint32_t dwPitchOrLinearSize;
|
||||
uint32_t dwDepth;
|
||||
uint32_t dwMipMapCount;
|
||||
uint32_t dwReserved1[11];
|
||||
DDS_PIXELFORMAT ddspf;
|
||||
uint32_t dwCaps;
|
||||
uint32_t dwCaps2;
|
||||
uint32_t dwCaps3;
|
||||
uint32_t dwCaps4;
|
||||
uint32_t dwReserved2;
|
||||
};
|
||||
|
||||
enum DDS_DIMENSION
|
||||
{
|
||||
DDS_DIMENSION_TEXTURE1D = 0x2,
|
||||
DDS_DIMENSION_TEXTURE2D,
|
||||
DDS_DIMENSION_TEXTURE3D
|
||||
};
|
||||
|
||||
enum DDS_RESOURCE_MISC
|
||||
{
|
||||
DDS_RESOURCE_MISC_TEXTURECUBE = 0x4
|
||||
};
|
||||
|
||||
struct DDS_HEADER_DXT10
|
||||
{
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
DDS_DIMENSION resourceDimension;
|
||||
uint32_t miscFlag;
|
||||
uint32_t arraySize;
|
||||
uint32_t miscFlags2;
|
||||
};
|
||||
}
|
@ -18,12 +18,28 @@ DXGI_FORMAT ImageFormat::GetDxgiFormat() const
|
||||
}
|
||||
|
||||
ImageFormatUnsigned::ImageFormatUnsigned(const ImageFormatId id, const DXGI_FORMAT dxgiFormat,
|
||||
const unsigned bitPerPixel, 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 bSize, const unsigned aOffset, const unsigned aSize)
|
||||
: ImageFormat(id, dxgiFormat)
|
||||
{
|
||||
m_bit_per_pixel = bitPerPixel;
|
||||
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
|
||||
@ -45,7 +61,12 @@ size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const uns
|
||||
if (mipDepth == 0)
|
||||
mipDepth = 1;
|
||||
|
||||
return mipWidth * mipHeight * mipDepth * m_bit_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,
|
||||
@ -82,6 +103,11 @@ size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, co
|
||||
return blockCount * m_bits_per_block / 8;
|
||||
}
|
||||
|
||||
size_t ImageFormatBlockCompressed::GetPitch(const unsigned width) const
|
||||
{
|
||||
return (width + m_block_size - 1) / m_block_size * (m_bits_per_block / 8);
|
||||
}
|
||||
|
||||
const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8(ImageFormatId::R8_G8_B8, DXGI_FORMAT_UNKNOWN,
|
||||
24, 0, 8, 8, 8, 16, 8, 0, 0);
|
||||
const ImageFormatUnsigned ImageFormat::FORMAT_R8_G8_B8_A8(ImageFormatId::R8_G8_B8_A8, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <dxgiformat.h>
|
||||
|
||||
enum class ImageFormatId
|
||||
@ -42,6 +43,7 @@ public:
|
||||
|
||||
virtual ImageFormatType GetType() 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_A8;
|
||||
@ -56,25 +58,39 @@ public:
|
||||
|
||||
class ImageFormatUnsigned final : public ImageFormat
|
||||
{
|
||||
unsigned m_bit_per_pixel;
|
||||
|
||||
public:
|
||||
ImageFormatUnsigned(ImageFormatId id, DXGI_FORMAT dxgiFormat, unsigned bitPerPixel, unsigned rOffset,
|
||||
unsigned m_bits_per_pixel;
|
||||
unsigned m_r_offset;
|
||||
unsigned m_r_size;
|
||||
uint64_t m_r_mask;
|
||||
unsigned m_g_offset;
|
||||
unsigned m_g_size;
|
||||
uint64_t m_g_mask;
|
||||
unsigned m_b_offset;
|
||||
unsigned m_b_size;
|
||||
uint64_t m_b_mask;
|
||||
unsigned m_a_offset;
|
||||
unsigned m_a_size;
|
||||
uint64_t m_a_mask;
|
||||
|
||||
ImageFormatUnsigned(ImageFormatId id, DXGI_FORMAT dxgiFormat, unsigned bitsPerPixel, unsigned rOffset,
|
||||
unsigned rSize, unsigned gOffset, unsigned gSize, unsigned bOffset, unsigned bSize,
|
||||
unsigned aOffset, unsigned aSize);
|
||||
|
||||
ImageFormatType GetType() const override;
|
||||
size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
|
||||
size_t GetPitch(unsigned width) const override;
|
||||
};
|
||||
|
||||
class ImageFormatBlockCompressed final : public ImageFormat
|
||||
{
|
||||
public:
|
||||
unsigned m_block_size;
|
||||
unsigned m_bits_per_block;
|
||||
|
||||
public:
|
||||
ImageFormatBlockCompressed(ImageFormatId id, DXGI_FORMAT dxgiFormat, unsigned blockSize, unsigned bitsPerBlock);
|
||||
|
||||
ImageFormatType GetType() const override;
|
||||
size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
|
||||
size_t GetPitch(unsigned width) const override;
|
||||
};
|
||||
|
@ -50,7 +50,7 @@ void Texture::Allocate()
|
||||
|
||||
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++)
|
||||
{
|
||||
storageRequirement += GetSizeOfMipLevel(currentMipLevel);
|
||||
storageRequirement += GetSizeOfMipLevel(currentMipLevel) * GetFaceCount();
|
||||
}
|
||||
|
||||
if (storageRequirement > 0)
|
||||
@ -70,6 +70,11 @@ bool Texture::HasMipMaps() const
|
||||
return m_has_mip_maps;
|
||||
}
|
||||
|
||||
uint8_t* Texture::GetBufferForMipLevel(const int mipLevel)
|
||||
{
|
||||
return GetBufferForMipLevel(mipLevel, 0);
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// ================ Texture2D ===================
|
||||
// ==============================================
|
||||
@ -106,6 +111,11 @@ Texture2D& Texture2D::operator=(Texture2D&& other) noexcept
|
||||
return *this;
|
||||
}
|
||||
|
||||
Texture::Type Texture2D::GetType() const
|
||||
{
|
||||
return Type::TYPE_2D;
|
||||
}
|
||||
|
||||
unsigned Texture2D::GetWidth() const
|
||||
{
|
||||
return m_width;
|
||||
@ -116,6 +126,16 @@ unsigned Texture2D::GetHeight() const
|
||||
return m_height;
|
||||
}
|
||||
|
||||
unsigned Texture2D::GetDepth() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Texture2D::GetFaceCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t Texture2D::GetSizeOfMipLevel(const int mipLevel) const
|
||||
{
|
||||
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, 1);
|
||||
@ -136,15 +156,19 @@ int Texture2D::GetMipMapCount() const
|
||||
return mipMapCount;
|
||||
}
|
||||
|
||||
uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel)
|
||||
uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel, const int face)
|
||||
{
|
||||
assert(mipLevel >= 0);
|
||||
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
|
||||
assert(face == 0);
|
||||
assert(m_data);
|
||||
|
||||
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
|
||||
return nullptr;
|
||||
|
||||
if (face != 0)
|
||||
return nullptr;
|
||||
|
||||
if (!m_data)
|
||||
return nullptr;
|
||||
|
||||
@ -189,9 +213,40 @@ TextureCube& TextureCube::operator=(TextureCube&& other) noexcept
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t TextureCube::GetSizeOfMipLevel(const int mipLevel) const
|
||||
Texture::Type TextureCube::GetType() const
|
||||
{
|
||||
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, 1) * FACE_COUNT;
|
||||
return Type::TYPE_CUBE;
|
||||
}
|
||||
|
||||
int TextureCube::GetFaceCount() const
|
||||
{
|
||||
return FACE_COUNT;
|
||||
}
|
||||
|
||||
uint8_t* TextureCube::GetBufferForMipLevel(const int mipLevel, const int face)
|
||||
{
|
||||
assert(mipLevel >= 0);
|
||||
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
|
||||
assert(face >= 0);
|
||||
assert(face < FACE_COUNT);
|
||||
assert(m_data);
|
||||
|
||||
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
|
||||
return nullptr;
|
||||
|
||||
if (face < 0 || face >= FACE_COUNT)
|
||||
return nullptr;
|
||||
|
||||
if (!m_data)
|
||||
return nullptr;
|
||||
|
||||
size_t bufferOffset = 0;
|
||||
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
|
||||
{
|
||||
bufferOffset += GetSizeOfMipLevel(previousMipLevel) * FACE_COUNT;
|
||||
}
|
||||
|
||||
return &m_data[bufferOffset + GetSizeOfMipLevel(mipLevel) * face];
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
@ -235,6 +290,11 @@ Texture3D& Texture3D::operator=(Texture3D&& other) noexcept
|
||||
return *this;
|
||||
}
|
||||
|
||||
Texture::Type Texture3D::GetType() const
|
||||
{
|
||||
return Type::TYPE_3D;
|
||||
}
|
||||
|
||||
unsigned Texture3D::GetWidth() const
|
||||
{
|
||||
return m_width;
|
||||
@ -250,6 +310,11 @@ unsigned Texture3D::GetDepth() const
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
int Texture3D::GetFaceCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t Texture3D::GetSizeOfMipLevel(const int mipLevel) const
|
||||
{
|
||||
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, m_depth);
|
||||
@ -270,15 +335,19 @@ int Texture3D::GetMipMapCount() const
|
||||
return mipMapCount;
|
||||
}
|
||||
|
||||
uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel)
|
||||
uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel, const int face)
|
||||
{
|
||||
assert(mipLevel >= 0);
|
||||
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
|
||||
assert(face == 0);
|
||||
assert(m_data);
|
||||
|
||||
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
|
||||
return nullptr;
|
||||
|
||||
if (face != 0)
|
||||
return nullptr;
|
||||
|
||||
if (!m_data)
|
||||
return nullptr;
|
||||
|
||||
|
@ -4,6 +4,14 @@
|
||||
|
||||
class Texture
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
TYPE_2D,
|
||||
TYPE_CUBE,
|
||||
TYPE_3D
|
||||
};
|
||||
|
||||
protected:
|
||||
const ImageFormat* m_format;
|
||||
bool m_has_mip_maps;
|
||||
@ -21,12 +29,19 @@ public:
|
||||
Texture& operator=(const Texture& other) = delete;
|
||||
|
||||
const ImageFormat* GetFormat() const;
|
||||
virtual Type GetType() const = 0;
|
||||
|
||||
virtual unsigned GetWidth() const = 0;
|
||||
virtual unsigned GetHeight() const = 0;
|
||||
virtual unsigned GetDepth() const = 0;
|
||||
virtual int GetFaceCount() const = 0;
|
||||
|
||||
void Allocate();
|
||||
bool Empty() const;
|
||||
|
||||
virtual size_t GetSizeOfMipLevel(int mipLevel) const = 0;
|
||||
virtual uint8_t* GetBufferForMipLevel(int mipLevel) = 0;
|
||||
virtual uint8_t* GetBufferForMipLevel(int mipLevel, int face) = 0;
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel);
|
||||
|
||||
bool HasMipMaps() const;
|
||||
virtual int GetMipMapCount() const = 0;
|
||||
@ -48,11 +63,15 @@ public:
|
||||
Texture2D& operator=(const Texture2D& other) = delete;
|
||||
Texture2D& operator=(Texture2D&& other) noexcept;
|
||||
|
||||
unsigned GetWidth() const;
|
||||
unsigned GetHeight() const;
|
||||
Type GetType() const override;
|
||||
|
||||
unsigned GetWidth() const override;
|
||||
unsigned GetHeight() const override;
|
||||
unsigned GetDepth() const override;
|
||||
int GetFaceCount() const override;
|
||||
|
||||
size_t GetSizeOfMipLevel(int mipLevel) const override;
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel) override;
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
|
||||
|
||||
int GetMipMapCount() const override;
|
||||
};
|
||||
@ -71,7 +90,11 @@ public:
|
||||
TextureCube& operator=(const TextureCube& other) = delete;
|
||||
TextureCube& operator=(TextureCube&& other) noexcept;
|
||||
|
||||
size_t GetSizeOfMipLevel(int mipLevel) const override;
|
||||
Type GetType() const override;
|
||||
|
||||
int GetFaceCount() const override;
|
||||
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
|
||||
};
|
||||
|
||||
class Texture3D final : public Texture
|
||||
@ -90,12 +113,15 @@ public:
|
||||
Texture3D& operator=(const Texture3D& other) = delete;
|
||||
Texture3D& operator=(Texture3D&& other) noexcept;
|
||||
|
||||
unsigned GetWidth() const;
|
||||
unsigned GetHeight() const;
|
||||
unsigned GetDepth() const;
|
||||
Type GetType() const override;
|
||||
|
||||
unsigned GetWidth() const override;
|
||||
unsigned GetHeight() const override;
|
||||
unsigned GetDepth() const override;
|
||||
int GetFaceCount() const override;
|
||||
|
||||
size_t GetSizeOfMipLevel(int mipLevel) const override;
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel) override;
|
||||
uint8_t* GetBufferForMipLevel(int mipLevel, int face) override;
|
||||
|
||||
int GetMipMapCount() const override;
|
||||
};
|
@ -1,11 +1,278 @@
|
||||
#include "DdsWriter.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "Image/DdsTypes.h"
|
||||
|
||||
using namespace dds;
|
||||
|
||||
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;
|
||||
Texture* m_texture;
|
||||
ImageFormatSupportStatus m_support_status;
|
||||
|
||||
void PrepareHeader(DDS_HEADER* header) const
|
||||
{
|
||||
header->dwSize = sizeof DDS_HEADER;
|
||||
header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
|
||||
|
||||
if (m_texture->HasMipMaps())
|
||||
header->dwFlags |= DDSD_MIPMAPCOUNT;
|
||||
|
||||
if (m_texture->GetFormat()->GetType() == ImageFormatType::BLOCK_COMPRESSED)
|
||||
header->dwFlags |= DDSD_LINEARSIZE;
|
||||
else
|
||||
header->dwFlags |= DDSD_PITCH;
|
||||
|
||||
if (m_texture->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;
|
||||
header->dwCaps4 = 0;
|
||||
header->dwReserved2 = 0;
|
||||
}
|
||||
|
||||
void SetPixelFormat(DDS_PIXELFORMAT* pixelFormat) const
|
||||
{
|
||||
pixelFormat->dwSize = sizeof DDS_PIXELFORMAT;
|
||||
pixelFormat->dwFlags = 0;
|
||||
|
||||
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;
|
||||
case ImageFormatType::BLOCK_COMPRESSED:
|
||||
{
|
||||
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;
|
||||
case ImageFormatId::BC2:
|
||||
pixelFormat->dwFourCC = DDS_PF_BC2;
|
||||
break;
|
||||
case ImageFormatId::BC3:
|
||||
pixelFormat->dwFourCC = DDS_PF_BC3;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void MarkHeaderAsExtendedByHeaderDxt10(DDS_PIXELFORMAT* pixelFormat)
|
||||
{
|
||||
pixelFormat->dwSize = sizeof DDS_PIXELFORMAT;
|
||||
pixelFormat->dwFlags = DDPF_FOURCC;
|
||||
pixelFormat->dwFourCC = DDS_PF_DXT10_EXTENSION;
|
||||
pixelFormat->dwRGBBitCount = 0;
|
||||
pixelFormat->dwRBitMask = 0;
|
||||
pixelFormat->dwGBitMask = 0;
|
||||
pixelFormat->dwBBitMask = 0;
|
||||
pixelFormat->dwABitMask = 0;
|
||||
}
|
||||
|
||||
void PrepareHeaderDxt10(DDS_HEADER_DXT10* header)
|
||||
{
|
||||
header->dxgiFormat = m_texture->GetFormat()->GetDxgiFormat();
|
||||
|
||||
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;
|
||||
if (m_texture->GetType() == Texture::Type::TYPE_CUBE)
|
||||
header->miscFlag |= DDS_RESOURCE_MISC_TEXTURECUBE;
|
||||
|
||||
header->arraySize = m_texture->GetFaceCount();
|
||||
header->miscFlags2 = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
static ImageFormatSupportStatus GetSupportStatusForImageFormat(const ImageFormat* format)
|
||||
{
|
||||
assert(format != nullptr);
|
||||
|
||||
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
|
||||
? ImageFormatSupportStatus::SUPPORTED_WITH_DXT10_HEADER
|
||||
: ImageFormatSupportStatus::UNSUPPORTED;
|
||||
}
|
||||
|
||||
DdsWriterInternal(FileAPI::IFile* file, Texture* texture)
|
||||
{
|
||||
m_file = file;
|
||||
m_texture = texture;
|
||||
m_support_status = GetSupportStatusForImageFormat(texture->GetFormat());
|
||||
}
|
||||
|
||||
bool DumpImage()
|
||||
{
|
||||
if (m_file->Write(&DDS_MAGIC, sizeof uint32_t, 1) != 1)
|
||||
return false;
|
||||
|
||||
DDS_HEADER ddsHeader{};
|
||||
PrepareHeader(&ddsHeader);
|
||||
if (m_support_status == ImageFormatSupportStatus::SUPPORTED_WITH_SIMPLE_HEADER)
|
||||
{
|
||||
SetPixelFormat(&ddsHeader.ddspf);
|
||||
|
||||
if (m_file->Write(&ddsHeader, sizeof DDS_HEADER, 1) != 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;
|
||||
for (int face = 0; face < m_texture->GetFaceCount(); face++)
|
||||
{
|
||||
for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
|
||||
{
|
||||
const size_t sizeOfMipLevel = m_texture->GetSizeOfMipLevel(mipLevel);
|
||||
|
||||
if (m_file->Write(m_texture->GetBufferForMipLevel(mipLevel, face), 1, sizeOfMipLevel) != sizeOfMipLevel)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
DdsWriter::~DdsWriter()
|
||||
= default;
|
||||
|
||||
bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat)
|
||||
{
|
||||
return true;
|
||||
return DdsWriterInternal::GetSupportStatusForImageFormat(imageFormat)
|
||||
!= DdsWriterInternal::ImageFormatSupportStatus::UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::string DdsWriter::GetFileExtension()
|
||||
@ -15,4 +282,6 @@ std::string DdsWriter::GetFileExtension()
|
||||
|
||||
void DdsWriter::DumpImage(FileAPI::IFile* file, Texture* texture)
|
||||
{
|
||||
DdsWriterInternal writer(file, texture);
|
||||
writer.DumpImage();
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ public:
|
||||
|
||||
bool SupportsImageFormat(const ImageFormat * imageFormat) override;
|
||||
std::string GetFileExtension() override;
|
||||
void DumpImage(FileAPI::IFile * file, Texture * texture) override;
|
||||
void DumpImage(FileAPI::IFile* file, Texture* texture) override;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user