From ccef1dca283fbec2be8053a82fce0f0fff9c129e Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 4 Sep 2020 12:51:13 +0200 Subject: [PATCH] Add dumper for DDS and texture converter for reordering colors --- premake5.lua | 2 + src/ObjCommon/Image/DdsTypes.h | 209 +++++----- src/ObjCommon/Image/ImageFormat.cpp | 99 +++-- src/ObjCommon/Image/ImageFormat.h | 26 +- src/ObjCommon/Image/Texture.cpp | 17 +- src/ObjCommon/Image/Texture.h | 24 +- src/ObjCommon/Image/TextureConverter.cpp | 229 +++++++++++ src/ObjCommon/Image/TextureConverter.h | 30 ++ src/ObjWriting/Image/DdsWriter.cpp | 369 ++++++++---------- test/ObjCommonTests.lua | 43 ++ .../ObjCommonTests/Image/ImageFormatTests.cpp | 22 ++ 11 files changed, 708 insertions(+), 362 deletions(-) create mode 100644 src/ObjCommon/Image/TextureConverter.cpp create mode 100644 src/ObjCommon/Image/TextureConverter.h create mode 100644 test/ObjCommonTests.lua create mode 100644 test/ObjCommonTests/Image/ImageFormatTests.cpp diff --git a/premake5.lua b/premake5.lua index e27ad52b..415c9483 100644 --- a/premake5.lua +++ b/premake5.lua @@ -163,11 +163,13 @@ group "" -- ======================== -- Tests -- ======================== +include "test/ObjCommonTests.lua" include "test/ZoneCodeGeneratorTests.lua" include "test/ZoneCommonTests.lua" -- Tests group: Unit test and other tests projects group "Tests" + ObjCommonTests:project() ZoneCodeGeneratorTests:project() ZoneCommonTests:project() group "" \ No newline at end of file diff --git a/src/ObjCommon/Image/DdsTypes.h b/src/ObjCommon/Image/DdsTypes.h index 9ffe589e..320381f9 100644 --- a/src/ObjCommon/Image/DdsTypes.h +++ b/src/ObjCommon/Image/DdsTypes.h @@ -1,107 +1,114 @@ #pragma once #include -#include -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(c0) - | static_cast(c1) << 8 - | static_cast(c2) << 16 - | static_cast(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; - }; + return static_cast(ch0) + | static_cast(ch1) << 8 + | static_cast(ch2) << 16 + | static_cast(ch3) << 24; } + +enum DDP_FLAGS +{ + DDPF_ALPHAPIXELS = 0x1, + DDPF_ALPHA = 0x2, + DDPF_FOURCC = 0x4, + DDPF_RGB = 0x40, + DDPF_YUV = 0x200, + DDPF_LUMINANCE = 0x20000 +}; + +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_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 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 D3D10_RESOURCE_DIMENSION +{ + D3D10_RESOURCE_DIMENSION_UNKNOWN, + D3D10_RESOURCE_DIMENSION_BUFFER, + D3D10_RESOURCE_DIMENSION_TEXTURE1D, + D3D10_RESOURCE_DIMENSION_TEXTURE2D, + D3D10_RESOURCE_DIMENSION_TEXTURE3D +}; + +enum DDS_HEADER_DXT10_MISC +{ + DDS_RESOURCE_MISC_TEXTURECUBE = 0x4 +}; + +enum DDS_HEADER_DXT10_MISC2 +{ + DDS_ALPHA_MODE_UNKNOWN = 0x0, + DDS_ALPHA_MODE_STRAIGHT = 0x1, + DDS_ALPHA_MODE_PREMULTIPLIED = 0x2, + DDS_ALPHA_MODE_OPAQUE = 0x3, + DDS_ALPHA_MODE_CUSTOM = 0x4, +}; + +struct DDS_HEADER_DXT10 +{ + DXGI_FORMAT dxgiFormat; + D3D10_RESOURCE_DIMENSION resourceDimension; + uint32_t miscFlag; + uint32_t arraySize; + uint32_t miscFlags2; +}; diff --git a/src/ObjCommon/Image/ImageFormat.cpp b/src/ObjCommon/Image/ImageFormat.cpp index ec010e6d..477eee1b 100644 --- a/src/ObjCommon/Image/ImageFormat.cpp +++ b/src/ObjCommon/Image/ImageFormat.cpp @@ -1,6 +1,5 @@ #include "ImageFormat.h" - ImageFormat::ImageFormat(const ImageFormatId id, const DXGI_FORMAT dxgiFormat) { 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 gOffset, const unsigned gSize, const unsigned bOffset, 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 @@ -47,6 +38,15 @@ ImageFormatType ImageFormatUnsigned::GetType() const 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, 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; } -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, 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 @@ -82,6 +77,18 @@ ImageFormatType ImageFormatBlockCompressed::GetType() const 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, 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; } -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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 8); 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_BC4(ImageFormatId::BC4, DXGI_FORMAT_BC4_UNORM, 4, 64); const ImageFormatBlockCompressed ImageFormat::FORMAT_BC5(ImageFormatId::BC5, DXGI_FORMAT_BC5_UNORM, 4, 128); + +const ImageFormat* const ImageFormat::ALL_FORMATS[static_cast(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, +}; diff --git a/src/ObjCommon/Image/ImageFormat.h b/src/ObjCommon/Image/ImageFormat.h index 11b14a5e..66437aa7 100644 --- a/src/ObjCommon/Image/ImageFormat.h +++ b/src/ObjCommon/Image/ImageFormat.h @@ -5,16 +5,20 @@ enum class ImageFormatId { - UNKNOWN, + UNKNOWN = -1, R8_G8_B8, + B8_G8_R8_X8, R8_G8_B8_A8, + B8_G8_R8_A8, A8, R16_G16_B16_A16_FLOAT, BC1, BC2, BC3, BC4, - BC5 + BC5, + + MAX }; enum class ImageFormatType @@ -42,11 +46,13 @@ public: DXGI_FORMAT GetDxgiFormat() const; 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 GetPitch(unsigned width) const = 0; 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_B8_G8_R8_A8; static const ImageFormatUnsigned FORMAT_A8; static const ImageFormatUnsigned FORMAT_R16_G16_B16_A16_FLOAT; //TODO: Float not unsigned static const ImageFormatBlockCompressed FORMAT_BC1; @@ -54,6 +60,7 @@ public: static const ImageFormatBlockCompressed FORMAT_BC3; static const ImageFormatBlockCompressed FORMAT_BC4; static const ImageFormatBlockCompressed FORMAT_BC5; + static const ImageFormat* const ALL_FORMATS[static_cast(ImageFormatId::MAX)]; }; class ImageFormatUnsigned final : public ImageFormat @@ -62,24 +69,25 @@ public: 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 GetPitch(unsigned mipLevel, unsigned width) 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 @@ -91,6 +99,6 @@ public: ImageFormatBlockCompressed(ImageFormatId id, DXGI_FORMAT dxgiFormat, unsigned blockSize, unsigned bitsPerBlock); 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 GetPitch(unsigned width) const override; }; diff --git a/src/ObjCommon/Image/Texture.cpp b/src/ObjCommon/Image/Texture.cpp index 8835d5e1..db106765 100644 --- a/src/ObjCommon/Image/Texture.cpp +++ b/src/ObjCommon/Image/Texture.cpp @@ -111,9 +111,9 @@ Texture2D& Texture2D::operator=(Texture2D&& other) noexcept return *this; } -Texture::Type Texture2D::GetType() const +TextureType Texture2D::GetTextureType() const { - return Type::TYPE_2D; + return TextureType::T_2D; } unsigned Texture2D::GetWidth() const @@ -213,12 +213,17 @@ TextureCube& TextureCube::operator=(TextureCube&& other) noexcept return *this; } -Texture::Type TextureCube::GetType() const +TextureType TextureCube::GetTextureType() const { - return Type::TYPE_CUBE; + return TextureType::T_CUBE; } int TextureCube::GetFaceCount() const +{ + return 6; +} + +size_t TextureCube::GetSizeOfMipLevel(const int mipLevel) const { return FACE_COUNT; } @@ -290,9 +295,9 @@ Texture3D& Texture3D::operator=(Texture3D&& other) noexcept return *this; } -Texture::Type Texture3D::GetType() const +TextureType Texture3D::GetTextureType() const { - return Type::TYPE_3D; + return TextureType::T_3D; } unsigned Texture3D::GetWidth() const diff --git a/src/ObjCommon/Image/Texture.h b/src/ObjCommon/Image/Texture.h index fb6727ca..5545724f 100644 --- a/src/ObjCommon/Image/Texture.h +++ b/src/ObjCommon/Image/Texture.h @@ -2,16 +2,15 @@ #include "ImageFormat.h" #include +enum class TextureType +{ + T_2D, + T_CUBE, + T_3D +}; + class Texture { -public: - enum class Type - { - TYPE_2D, - TYPE_CUBE, - TYPE_3D - }; - protected: const ImageFormat* m_format; bool m_has_mip_maps; @@ -28,8 +27,8 @@ public: Texture& operator=(const Texture& other) = delete; + virtual TextureType GetTextureType() const = 0; const ImageFormat* GetFormat() const; - virtual Type GetType() const = 0; virtual unsigned GetWidth() const = 0; virtual unsigned GetHeight() const = 0; @@ -63,7 +62,7 @@ public: Texture2D& operator=(const Texture2D& other) = delete; Texture2D& operator=(Texture2D&& other) noexcept; - Type GetType() const override; + TextureType GetTextureType() const override; unsigned GetWidth() const override; unsigned GetHeight() const override; @@ -90,10 +89,11 @@ public: TextureCube& operator=(const TextureCube& other) = delete; TextureCube& operator=(TextureCube&& other) noexcept; - Type GetType() const override; + TextureType GetTextureType() const override; int GetFaceCount() const override; + size_t GetSizeOfMipLevel(int mipLevel) const override; uint8_t* GetBufferForMipLevel(int mipLevel, int face) override; }; @@ -113,7 +113,7 @@ public: Texture3D& operator=(const Texture3D& other) = delete; Texture3D& operator=(Texture3D&& other) noexcept; - Type GetType() const override; + TextureType GetTextureType() const override; unsigned GetWidth() const override; unsigned GetHeight() const override; diff --git a/src/ObjCommon/Image/TextureConverter.cpp b/src/ObjCommon/Image/TextureConverter.cpp new file mode 100644 index 00000000..531a621d --- /dev/null +++ b/src/ObjCommon/Image/TextureConverter.cpp @@ -0,0 +1,229 @@ +#include "TextureConverter.h" + +#include + +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(*static_cast(offset)); + }; + break; + + case 32: + m_read_pixel_func = [](const void* offset, unsigned bitCount) + { + return static_cast(*static_cast(offset)); + }; + break; + + case 64: + m_read_pixel_func = [](const void* offset, unsigned bitCount) + { + return *static_cast(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(*(static_cast(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(offset) = static_cast(pixel); + }; + break; + + case 32: + m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount) + { + *static_cast(offset) = static_cast(pixel); + }; + break; + + case 64: + m_write_pixel_func = [](void* offset, const uint64_t pixel, unsigned bitCount) + { + *static_cast(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(offset) + (pixelOffset / 8)) = static_cast(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(m_input_format); + const auto* outputFormat = dynamic_cast(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(m_input_format); + const auto* outputFormat = dynamic_cast(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; +} diff --git a/src/ObjCommon/Image/TextureConverter.h b/src/ObjCommon/Image/TextureConverter.h new file mode 100644 index 00000000..b1cacfb9 --- /dev/null +++ b/src/ObjCommon/Image/TextureConverter.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#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 m_read_pixel_func; + std::function 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(); +}; \ No newline at end of file diff --git a/src/ObjWriting/Image/DdsWriter.cpp b/src/ObjWriting/Image/DdsWriter.cpp index 7bae2309..5c2b958b 100644 --- a/src/ObjWriting/Image/DdsWriter.cpp +++ b/src/ObjWriting/Image/DdsWriter.cpp @@ -1,268 +1,228 @@ #include "DdsWriter.h" #include +#include +#include + #include "Image/DdsTypes.h" +#include "Image/TextureConverter.h" -using namespace dds; +const std::map DDS_CONVERSION_TABLE +{ + {ImageFormatId::R8_G8_B8, ImageFormatId::B8_G8_R8_X8}, +}; 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; + std::unique_ptr 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; - header->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + if (length >= sizeof(unsigned) * 8) + return UINT32_MAX; + + return UINT32_MAX >> (sizeof(unsigned) * 8 - length); + } + + void PopulatePixelFormatBlockCompressed(DDS_PIXELFORMAT& pf, const ImageFormatBlockCompressed* format) + { + pf.dwSize = sizeof(DDS_PIXELFORMAT); + pf.dwFlags = DDPF_FOURCC; + pf.dwRGBBitCount = 0; + pf.dwRBitMask = 0; + pf.dwGBitMask = 0; + pf.dwBBitMask = 0; + pf.dwABitMask = 0; + + // Use standard pixel format for DXT1-5 for maximum compatibility and only otherwise use DX10 extension + switch (format->GetDxgiFormat()) + { + case DXGI_FORMAT_BC1_UNORM: + pf.dwFourCC = MakeFourCc('D', 'X', 'T', '1'); + 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: + PopulatePixelFormatBlockCompressed(pf, dynamic_cast(format)); + break; + case ImageFormatType::UNSIGNED: + PopulatePixelFormatUnsigned(pf, dynamic_cast(format)); + break; + default: + assert(false); + break; + } + } + + void PopulateDdsHeader(DDS_HEADER& header) + { + header.dwSize = sizeof header; + header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; if (m_texture->HasMipMaps()) - header->dwFlags |= DDSD_MIPMAPCOUNT; + header.dwFlags |= DDSD_MIPMAPCOUNT; if (m_texture->GetFormat()->GetType() == ImageFormatType::BLOCK_COMPRESSED) - header->dwFlags |= DDSD_LINEARSIZE; + header.dwFlags |= DDSD_LINEARSIZE; else - header->dwFlags |= DDSD_PITCH; + header.dwFlags |= DDSD_PITCH; - if (m_texture->GetType() == Texture::Type::TYPE_3D) - header->dwFlags |= DDSD_DEPTH; + if (m_texture->GetDepth() > 1) + 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; + 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; - memset(header->dwReserved1, 0, sizeof DDS_HEADER::dwReserved1); + PopulatePixelFormat(header.ddspf); + + header.dwCaps = DDSCAPS_TEXTURE; - 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.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; - header->dwCaps2 = 0; - if (m_texture->GetType() == Texture::Type::TYPE_CUBE) + if (m_texture->GetTextureType() == TextureType::T_CUBE) + header.dwCaps |= DDSCAPS_COMPLEX; + + header.dwCaps2 = 0; + + if (m_texture->GetTextureType() == TextureType::T_CUBE) { - header->dwCaps2 |= + 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; + header.dwCaps3 = 0; + header.dwCaps4 = 0; + header.dwReserved2 = 0; } - void SetPixelFormat(DDS_PIXELFORMAT* pixelFormat) const + void PopulateDxt10Header(DDS_HEADER_DXT10& header) const { - pixelFormat->dwSize = sizeof DDS_PIXELFORMAT; - pixelFormat->dwFlags = 0; + header.dxgiFormat = m_texture->GetFormat()->GetDxgiFormat(); + header.miscFlag = 0; + header.miscFlags2 = 0; - const auto* imageFormat = m_texture->GetFormat(); - switch (imageFormat->GetType()) + switch (m_texture->GetTextureType()) { - case ImageFormatType::UNSIGNED: - { - const auto* imageFormatUnsigned = dynamic_cast(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(imageFormatUnsigned->m_r_mask); - pixelFormat->dwGBitMask = static_cast(imageFormatUnsigned->m_g_mask); - pixelFormat->dwBBitMask = static_cast(imageFormatUnsigned->m_b_mask); - pixelFormat->dwABitMask = static_cast(imageFormatUnsigned->m_a_mask); - } + case TextureType::T_2D: + header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + header.arraySize = 1; 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; - } - } + case TextureType::T_CUBE: + header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + header.arraySize = 6; + header.miscFlag |= DDS_RESOURCE_MISC_TEXTURECUBE; break; - default: + case TextureType::T_3D: + header.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D; + header.arraySize = 1; break; } } - static void MarkHeaderAsExtendedByHeaderDxt10(DDS_PIXELFORMAT* pixelFormat) + void ConvertTextureIfNecessary() { - 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; - } + auto entry = DDS_CONVERSION_TABLE.find(m_texture->GetFormat()->GetId()); - void PrepareHeaderDxt10(DDS_HEADER_DXT10* header) - { - header->dxgiFormat = m_texture->GetFormat()->GetDxgiFormat(); - - switch (m_texture->GetType()) + if(entry != DDS_CONVERSION_TABLE.end()) { - 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; + TextureConverter converter(m_texture, ImageFormat::ALL_FORMATS[static_cast(entry->second)]); + m_converted_texture = std::unique_ptr(converter.Convert()); + m_texture = m_converted_texture.get(); } - - 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) + static bool SupportsImageFormat(const ImageFormat* imageFormat) { - assert(format != nullptr); + return true; + } - if (auto* imageFormatUnsigned = dynamic_cast(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; + static std::string GetFileExtension() + { + return ".dds"; } 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) - return false; + ConvertTextureIfNecessary(); - DDS_HEADER ddsHeader{}; - PrepareHeader(&ddsHeader); - if (m_support_status == ImageFormatSupportStatus::SUPPORTED_WITH_SIMPLE_HEADER) + DDS_HEADER header{}; + PopulateDdsHeader(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); - - 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; + DDS_HEADER_DXT10 dxt10{}; + PopulateDxt10Header(dxt10); + m_file->Write(&dxt10, sizeof dxt10, 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 size_t sizeOfMipLevel = m_texture->GetSizeOfMipLevel(mipLevel); - - if (m_file->Write(m_texture->GetBufferForMipLevel(mipLevel, face), 1, sizeOfMipLevel) != sizeOfMipLevel) - return false; - } + const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel); + const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel); + m_file->Write(buffer, 1, mipLevelSize); } - - return true; } }; @@ -271,17 +231,16 @@ DdsWriter::~DdsWriter() bool DdsWriter::SupportsImageFormat(const ImageFormat* imageFormat) { - return DdsWriterInternal::GetSupportStatusForImageFormat(imageFormat) - != DdsWriterInternal::ImageFormatSupportStatus::UNSUPPORTED; + return DdsWriterInternal::SupportsImageFormat(imageFormat); } std::string DdsWriter::GetFileExtension() { - return ".dds"; + return DdsWriterInternal::GetFileExtension(); } void DdsWriter::DumpImage(FileAPI::IFile* file, Texture* texture) { - DdsWriterInternal writer(file, texture); - writer.DumpImage(); + DdsWriterInternal internal(file, texture); + internal.DumpImage(); } diff --git a/test/ObjCommonTests.lua b/test/ObjCommonTests.lua new file mode 100644 index 00000000..91b5c1ce --- /dev/null +++ b/test/ObjCommonTests.lua @@ -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 diff --git a/test/ObjCommonTests/Image/ImageFormatTests.cpp b/test/ObjCommonTests/Image/ImageFormatTests.cpp new file mode 100644 index 00000000..6acbc169 --- /dev/null +++ b/test/ObjCommonTests/Image/ImageFormatTests.cpp @@ -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(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(ImageFormat::ALL_FORMATS[i]->GetId())); + } + } + }; +} \ No newline at end of file