ObjCommon: Refactor classes for holding Texture information

This commit is contained in:
Jan 2020-02-06 19:01:45 +01:00
parent 63330ff908
commit 75f6caab54
7 changed files with 520 additions and 45 deletions

View File

@ -1,23 +0,0 @@
#pragma once
#include "ImageFormat.h"
#include <cstdint>
class IImageData
{
public:
virtual ~IImageData() = default;
virtual unsigned GetWidth() = 0;
virtual unsigned GetHeight() = 0;
virtual unsigned GetDepth() = 0;
virtual ImageFormat* GetFormat() = 0;
virtual size_t GetSizeOfMipLevel(unsigned mipLevel) = 0;
virtual uint8_t* GetDataForMipLevel(unsigned mipLevel) = 0;
virtual bool HasMipMaps() = 0;
virtual int GetMipMapCount() = 0;
virtual void GenerateMipMaps() = 0;
virtual void DiscardMipMaps() = 0;
};

View File

@ -1,16 +0,0 @@
#pragma once
#include "IImageData.h"
class ImageDataIWI final : public IImageData
{
public:
ImageFormat* GetFormat() override;
size_t GetSizeOfMipLevel(unsigned mipLevel) override;
uint8_t* GetDataForMipLevel(unsigned mipLevel) override;
bool HasMipMaps() override;
int GetMipMapCount() override;
void GenerateMipMaps() override;
void DiscardMipMaps() override;
};

View File

@ -0,0 +1,81 @@
#include "ImageFormat.h"
ImageFormatUnsigned::ImageFormatUnsigned(const unsigned bitPerPixel, const unsigned rOffset, const unsigned rSize,
const unsigned gOffset, const unsigned gSize, const unsigned bOffset,
const unsigned bSize, const unsigned aOffset, const unsigned aSize,
DXGI_FORMAT dxgiFormat)
{
m_bit_per_pixel = bitPerPixel;
m_dxgi_format = dxgiFormat;
}
ImageFormatType ImageFormatUnsigned::GetType() const
{
return ImageFormatType::UNSIGNED;
}
DXGI_FORMAT ImageFormatUnsigned::GetDXGIFormat() const
{
return m_dxgi_format;
}
size_t ImageFormatUnsigned::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width, const unsigned height,
const unsigned depth) const
{
unsigned mipWidth = width >> mipLevel;
unsigned mipHeight = height >> mipLevel;
unsigned mipDepth = depth >> mipLevel;
if (mipWidth == 0)
mipWidth = 1;
if (mipHeight == 0)
mipHeight = 1;
if (mipDepth == 0)
mipDepth = 1;
return mipWidth * mipHeight * mipDepth * m_bit_per_pixel / 8;
}
ImageFormatBlockCompressed::ImageFormatBlockCompressed(const unsigned blockSize, const unsigned bitsPerBlock,
DXGI_FORMAT dxgiFormat)
{
m_block_size = blockSize;
m_bits_per_block = bitsPerBlock;
m_dxgi_format = dxgiFormat;
}
ImageFormatType ImageFormatBlockCompressed::GetType() const
{
return ImageFormatType::BLOCK_COMPRESSED;
}
DXGI_FORMAT ImageFormatBlockCompressed::GetDXGIFormat() const
{
return m_dxgi_format;
}
size_t ImageFormatBlockCompressed::GetSizeOfMipLevel(const unsigned mipLevel, const unsigned width,
const unsigned height, const unsigned depth) const
{
unsigned mipWidth = width >> mipLevel;
unsigned mipHeight = height >> mipLevel;
unsigned mipDepth = depth >> mipLevel;
if (mipWidth == 0)
mipWidth = 1;
if (mipHeight == 0)
mipHeight = 1;
if (mipDepth == 0)
mipDepth = 1;
const unsigned blockCount = ((mipWidth + m_block_size - 1) / m_block_size)
* ((mipHeight + m_block_size - 1) / m_block_size)
* mipDepth;
return blockCount * m_bits_per_block / 8;
}
const ImageFormatUnsigned ImageFormat::FORMAT_R8G8B8(24, 0, 8, 8, 8, 16, 8, 0, 0, DXGI_FORMAT_UNKNOWN);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC1(4, 8, DXGI_FORMAT_BC1_UNORM);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC2(4, 16, DXGI_FORMAT_BC2_UNORM);
const ImageFormatBlockCompressed ImageFormat::FORMAT_BC3(4, 16, DXGI_FORMAT_BC3_UNORM);

View File

@ -2,18 +2,58 @@
#include <dxgiformat.h> #include <dxgiformat.h>
enum class ImageFormatType
{
UNKNOWN,
UNSIGNED,
BLOCK_COMPRESSED
};
class IImageFormat class IImageFormat
{ {
public: public:
virtual DXGI_FORMAT GetDXGIFormat() = 0; virtual ~IImageFormat() = default;
virtual size_t GetSizeForMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth);
virtual ImageFormatType GetType() const = 0;
virtual DXGI_FORMAT GetDXGIFormat() const = 0;
virtual size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const = 0;
};
class ImageFormatUnsigned final : public IImageFormat
{
unsigned m_bit_per_pixel;
DXGI_FORMAT m_dxgi_format;
public:
ImageFormatUnsigned(unsigned bitPerPixel, unsigned rOffset, unsigned rSize, unsigned gOffset, unsigned gSize,
unsigned bOffset, unsigned bSize, unsigned aOffset, unsigned aSize, DXGI_FORMAT dxgiFormat);
ImageFormatType GetType() const override;
DXGI_FORMAT GetDXGIFormat() const override;
size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
};
class ImageFormatBlockCompressed final : public IImageFormat
{
unsigned m_block_size;
unsigned m_bits_per_block;
DXGI_FORMAT m_dxgi_format;
public:
ImageFormatBlockCompressed(unsigned blockSize, unsigned bitsPerBlock, DXGI_FORMAT dxgiFormat);
ImageFormatType GetType() const override;
DXGI_FORMAT GetDXGIFormat() const override;
size_t GetSizeOfMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth) const override;
}; };
class ImageFormat class ImageFormat
{ {
public: public:
ImageFormat(unsigned bitPerPixel, unsigned rOffset, unsigned rSize, unsigned gOffset, unsigned gSize, unsigned bOffset, unsigned bSize, unsigned aOffset, unsigned aSize); ImageFormat() = delete;
DXGI_FORMAT GetDXGIFormat(); static const ImageFormatUnsigned FORMAT_R8G8B8;
size_t GetSizeForMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth); static const ImageFormatBlockCompressed FORMAT_BC1;
static const ImageFormatBlockCompressed FORMAT_BC2;
static const ImageFormatBlockCompressed FORMAT_BC3;
}; };

View File

@ -0,0 +1,292 @@
#include "Texture.h"
#include <algorithm>
#include <cassert>
// ==============================================
// ================= Texture ====================
// ==============================================
Texture::Texture(const IImageFormat* format, const bool mipMaps)
{
m_format = format;
m_has_mip_maps = mipMaps;
m_data = nullptr;
}
Texture::Texture(Texture&& other) noexcept
{
m_format = other.m_format;
m_has_mip_maps = other.m_has_mip_maps;
m_data = other.m_data;
other.m_data = nullptr;
}
Texture& Texture::operator=(Texture&& other) noexcept
{
m_format = other.m_format;
m_has_mip_maps = other.m_has_mip_maps;
m_data = other.m_data;
other.m_data = nullptr;
return *this;
}
Texture::~Texture()
{
delete[] m_data;
m_data = nullptr;
}
const IImageFormat* Texture::GetFormat() const
{
return m_format;
}
void Texture::Allocate()
{
size_t storageRequirement = 0;
const int mipLevelCount = m_has_mip_maps ? GetMipMapCount() : 1;
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++)
{
storageRequirement += GetSizeOfMipLevel(currentMipLevel);
}
if (storageRequirement > 0)
{
m_data = new uint8_t[storageRequirement];
memset(m_data, 0, storageRequirement);
}
}
bool Texture::Empty() const
{
return m_data == nullptr;
}
bool Texture::HasMipMaps() const
{
return m_has_mip_maps;
}
// ==============================================
// ================ Texture2D ===================
// ==============================================
Texture2D::Texture2D(const IImageFormat* format, const unsigned width, const unsigned height)
: Texture2D(format, width, height, false)
{
}
Texture2D::Texture2D(const IImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps)
: Texture(format, mipMaps)
{
m_width = width;
m_height = height;
}
Texture2D::Texture2D(Texture2D&& other) noexcept
: Texture(std::move(other)),
m_width(other.m_width),
m_height(other.m_height)
{
}
Texture2D::~Texture2D() = default;
Texture2D& Texture2D::operator=(Texture2D&& other) noexcept
{
if (this == &other)
return *this;
Texture::operator=(std::move(other));
m_width = other.m_width;
m_height = other.m_height;
return *this;
}
unsigned Texture2D::GetWidth() const
{
return m_width;
}
unsigned Texture2D::GetHeight() const
{
return m_height;
}
size_t Texture2D::GetSizeOfMipLevel(const int mipLevel) const
{
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, 1);
}
int Texture2D::GetMipMapCount() const
{
unsigned maxDimension = std::max(m_width, m_height);
int mipMapCount = 0;
while (maxDimension != 0)
{
maxDimension >>= 1;
mipMapCount++;
}
return mipMapCount;
}
uint8_t* Texture2D::GetBufferForMipLevel(const int mipLevel)
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
}
return &m_data[bufferOffset];
}
// ==============================================
// =============== TextureCube ==================
// ==============================================
const int TextureCube::FACE_COUNT = 6;
TextureCube::TextureCube(const IImageFormat* format, const unsigned width, const unsigned height)
: Texture2D(format, width, height)
{
}
TextureCube::TextureCube(const IImageFormat* format, const unsigned width, const unsigned height, const bool mipMaps)
: Texture2D(format, width, height, mipMaps)
{
}
TextureCube::TextureCube(TextureCube&& other) noexcept
: Texture2D(std::move(other))
{
}
TextureCube::~TextureCube() = default;
TextureCube& TextureCube::operator=(TextureCube&& other) noexcept
{
if (this == &other)
return *this;
Texture2D::operator=(std::move(other));
return *this;
}
size_t TextureCube::GetSizeOfMipLevel(const int mipLevel) const
{
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, 1) * FACE_COUNT;
}
// ==============================================
// ================ Texture3D ===================
// ==============================================
Texture3D::Texture3D(const IImageFormat* format, const unsigned width, const unsigned height, const unsigned depth)
: Texture3D(format, width, height, depth, false)
{
}
Texture3D::Texture3D(const IImageFormat* format, const unsigned width, const unsigned height, const unsigned depth,
const bool mipMaps)
: Texture(format, mipMaps)
{
m_width = width;
m_height = height;
m_depth = depth;
}
Texture3D::Texture3D(Texture3D&& other) noexcept
: Texture(std::move(other)),
m_width(other.m_width),
m_height(other.m_height),
m_depth(other.m_depth)
{
}
Texture3D::~Texture3D() = default;
Texture3D& Texture3D::operator=(Texture3D&& other) noexcept
{
if (this == &other)
return *this;
Texture::operator=(std::move(other));
m_width = other.m_width;
m_height = other.m_height;
m_depth = other.m_depth;
return *this;
}
unsigned Texture3D::GetWidth() const
{
return m_width;
}
unsigned Texture3D::GetHeight() const
{
return m_height;
}
unsigned Texture3D::GetDepth() const
{
return m_depth;
}
size_t Texture3D::GetSizeOfMipLevel(const int mipLevel) const
{
return m_format->GetSizeOfMipLevel(mipLevel, m_width, m_height, m_depth);
}
int Texture3D::GetMipMapCount() const
{
unsigned maxDimension = std::max(std::max(m_width, m_height), m_depth);
int mipMapCount = 0;
while (maxDimension != 0)
{
maxDimension >>= 1;
mipMapCount++;
}
return mipMapCount;
}
uint8_t* Texture3D::GetBufferForMipLevel(const int mipLevel)
{
assert(mipLevel >= 0);
assert(mipLevel < (m_has_mip_maps ? GetMipMapCount() : 1));
assert(m_data);
if (mipLevel < 0 || mipLevel >= (m_has_mip_maps ? GetMipMapCount() : 1))
return nullptr;
if (!m_data)
return nullptr;
size_t bufferOffset = 0;
for (int previousMipLevel = 0; previousMipLevel < mipLevel; previousMipLevel++)
{
bufferOffset += GetSizeOfMipLevel(previousMipLevel);
}
return &m_data[bufferOffset];
}

View File

@ -0,0 +1,101 @@
#pragma once
#include "ImageFormat.h"
#include <cstdint>
class Texture
{
protected:
const IImageFormat* m_format;
bool m_has_mip_maps;
uint8_t* m_data;
Texture(const IImageFormat* format, bool mipMaps);
Texture(Texture&& other) noexcept;
Texture& operator=(Texture&& other) noexcept;
public:
Texture(const Texture& other) = delete;
virtual ~Texture();
Texture& operator=(const Texture& other) = delete;
const IImageFormat* GetFormat() const;
void Allocate();
bool Empty() const;
virtual size_t GetSizeOfMipLevel(int mipLevel) const = 0;
virtual uint8_t* GetBufferForMipLevel(int mipLevel) = 0;
bool HasMipMaps() const;
virtual int GetMipMapCount() const = 0;
};
class Texture2D : public Texture
{
protected:
unsigned m_width;
unsigned m_height;
public:
Texture2D(const IImageFormat* format, unsigned width, unsigned height);
Texture2D(const IImageFormat* format, unsigned width, unsigned height, bool mipMaps);
Texture2D(const Texture2D& other) = delete;
Texture2D(Texture2D&& other) noexcept;
~Texture2D() override;
Texture2D& operator=(const Texture2D& other) = delete;
Texture2D& operator=(Texture2D&& other) noexcept;
unsigned GetWidth() const;
unsigned GetHeight() const;
size_t GetSizeOfMipLevel(int mipLevel) const override;
uint8_t* GetBufferForMipLevel(int mipLevel) override;
int GetMipMapCount() const override;
};
class TextureCube final : public Texture2D
{
static const int FACE_COUNT;
public:
TextureCube(const IImageFormat* format, unsigned width, unsigned height);
TextureCube(const IImageFormat* format, unsigned width, unsigned height, bool mipMaps);
TextureCube(const TextureCube& other) = delete;
TextureCube(TextureCube&& other) noexcept;
~TextureCube() override;
TextureCube& operator=(const TextureCube& other) = delete;
TextureCube& operator=(TextureCube&& other) noexcept;
size_t GetSizeOfMipLevel(int mipLevel) const override;
};
class Texture3D final : public Texture
{
unsigned m_width;
unsigned m_height;
unsigned m_depth;
public:
Texture3D(const IImageFormat* format, unsigned width, unsigned height, unsigned depth);
Texture3D(const IImageFormat* format, unsigned width, unsigned height, unsigned depth, bool mipMaps);
Texture3D(const Texture3D& other) = delete;
Texture3D(Texture3D&& other) noexcept;
~Texture3D() override;
Texture3D& operator=(const Texture3D& other) = delete;
Texture3D& operator=(Texture3D&& other) noexcept;
unsigned GetWidth() const;
unsigned GetHeight() const;
unsigned GetDepth() const;
size_t GetSizeOfMipLevel(int mipLevel) const override;
uint8_t* GetBufferForMipLevel(int mipLevel) override;
int GetMipMapCount() const override;
};