diff --git a/src/ObjCommon/Image/IImageData.h b/src/ObjCommon/Image/IImageData.h deleted file mode 100644 index 8c1c1464..00000000 --- a/src/ObjCommon/Image/IImageData.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "ImageFormat.h" -#include - -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; -}; diff --git a/src/ObjCommon/Image/ImageDataIWI.cpp b/src/ObjCommon/Image/ImageDataIWI.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/src/ObjCommon/Image/ImageDataIWI.h b/src/ObjCommon/Image/ImageDataIWI.h deleted file mode 100644 index e5e70a23..00000000 --- a/src/ObjCommon/Image/ImageDataIWI.h +++ /dev/null @@ -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; -}; diff --git a/src/ObjCommon/Image/ImageFormat.cpp b/src/ObjCommon/Image/ImageFormat.cpp index e69de29b..37f742f2 100644 --- a/src/ObjCommon/Image/ImageFormat.cpp +++ b/src/ObjCommon/Image/ImageFormat.cpp @@ -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); diff --git a/src/ObjCommon/Image/ImageFormat.h b/src/ObjCommon/Image/ImageFormat.h index 38742145..a955a9ad 100644 --- a/src/ObjCommon/Image/ImageFormat.h +++ b/src/ObjCommon/Image/ImageFormat.h @@ -2,18 +2,58 @@ #include +enum class ImageFormatType +{ + UNKNOWN, + UNSIGNED, + BLOCK_COMPRESSED +}; + class IImageFormat { public: - virtual DXGI_FORMAT GetDXGIFormat() = 0; - virtual size_t GetSizeForMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth); + virtual ~IImageFormat() = default; + + 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 { 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(); - size_t GetSizeForMipLevel(unsigned mipLevel, unsigned width, unsigned height, unsigned depth); -}; \ No newline at end of file + static const ImageFormatUnsigned FORMAT_R8G8B8; + static const ImageFormatBlockCompressed FORMAT_BC1; + static const ImageFormatBlockCompressed FORMAT_BC2; + static const ImageFormatBlockCompressed FORMAT_BC3; +}; diff --git a/src/ObjCommon/Image/Texture.cpp b/src/ObjCommon/Image/Texture.cpp new file mode 100644 index 00000000..61b30362 --- /dev/null +++ b/src/ObjCommon/Image/Texture.cpp @@ -0,0 +1,292 @@ +#include "Texture.h" +#include +#include + +// ============================================== +// ================= 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]; +} diff --git a/src/ObjCommon/Image/Texture.h b/src/ObjCommon/Image/Texture.h new file mode 100644 index 00000000..8d8c91c3 --- /dev/null +++ b/src/ObjCommon/Image/Texture.h @@ -0,0 +1,101 @@ +#pragma once +#include "ImageFormat.h" +#include + +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; +}; \ No newline at end of file