diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2019-04-28 21:32:59 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2019-04-28 21:32:59 +0000 |
| commit | 450a6606cedbf45aa888637058af4742d5491b01 (patch) | |
| tree | 820210d82c58b39f42323f23ada328c919effe60 /TextureLoader/src | |
| parent | Updated GLTF loader to use Diligent file system functions (diff) | |
| download | DiligentTools-450a6606cedbf45aa888637058af4742d5491b01.tar.gz DiligentTools-450a6606cedbf45aa888637058af4742d5491b01.zip | |
Implemented loading textures from KTX
Diffstat (limited to 'TextureLoader/src')
| -rw-r--r-- | TextureLoader/src/Image.cpp | 42 | ||||
| -rw-r--r-- | TextureLoader/src/KTXLoader.cpp | 279 | ||||
| -rw-r--r-- | TextureLoader/src/TextureLoader.cpp | 360 | ||||
| -rw-r--r-- | TextureLoader/src/TextureUtilities.cpp | 95 |
4 files changed, 558 insertions, 218 deletions
diff --git a/TextureLoader/src/Image.cpp b/TextureLoader/src/Image.cpp index 2fcbf63..209b5b2 100644 --- a/TextureLoader/src/Image.cpp +++ b/TextureLoader/src/Image.cpp @@ -391,8 +391,8 @@ void Image::LoadJpegFile( IDataBlob *pFileData, const ImageLoadInfo& LoadInfo ) // warnings occurred (test whether jerr.pub.num_warnings is nonzero). } -Image::Image( IReferenceCounters *pRefCounters, - IDataBlob *pFileData, +Image::Image( IReferenceCounters* pRefCounters, + IDataBlob* pFileData, const ImageLoadInfo& LoadInfo ) : TBase(pRefCounters), m_pData( MakeNewRCObj<DataBlobImpl>()(0) ) @@ -409,6 +409,14 @@ Image::Image( IReferenceCounters *pRefCounters, { LoadJpegFile(pFileData, LoadInfo ); } + else if( LoadInfo.Format == EImageFileFormat::dds ) + { + LOG_ERROR("An image can't be created from DDS file. Use CreateTextureFromFile() or CreateTextureFromDDS() functions."); + } + else if( LoadInfo.Format == EImageFileFormat::ktx ) + { + LOG_ERROR("An image can't be created from KTX file. Use CreateTextureFromFile() or CreateTextureFromKTX() functions."); + } } void Image::CreateFromDataBlob(IDataBlob *pFileData, @@ -646,4 +654,34 @@ void Image::Encode(const EncodeInfo& Info, IDataBlob** ppEncodedData) pEncodedData->QueryInterface(IID_DataBlob, reinterpret_cast<IObject**>(ppEncodedData)); } +EImageFileFormat Image::GetFileFormat(const Uint8* pData, size_t Size) +{ + if (Size >= 3 && pData[0] == 0xFF && pData[1] == 0xD8 && pData[2] == 0xFF) + return EImageFileFormat::jpeg; + + if (Size >= 8 && + pData[0] == 0x89 && pData[1] == 0x50 && pData[2] == 0x4E && pData[3] == 0x47 && + pData[4] == 0x0D && pData[5] == 0x0A && pData[6] == 0x1A && pData[7] == 0x0A) + return EImageFileFormat::png; + + if (Size >= 4 && + (pData[0] == 0x49 && pData[1] == 0x20 && pData[2] == 0x49 || + pData[0] == 0x49 && pData[1] == 0x49 && pData[2] == 0x2A && pData[3] == 0x00 || + pData[0] == 0x4D && pData[1] == 0x4D && pData[2] == 0x00 && pData[3] == 0x2A || + pData[0] == 0x4D && pData[1] == 0x4D && pData[2] == 0x00 && pData[3] == 0x2B)) + return EImageFileFormat::tiff; + + if (Size >= 4 && pData[0] == 0x44 && pData[1] == 0x44 && pData[2] == 0x53 && pData[3] == 0x20) + return EImageFileFormat::dds; + + static constexpr Uint8 KTX10FileIdentifier[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}; + static constexpr Uint8 KTX20FileIdentifier[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}; + if (Size >= 12 && + (memcmp(pData, KTX10FileIdentifier, sizeof(KTX10FileIdentifier)) == 0 || + memcmp(pData, KTX20FileIdentifier, sizeof(KTX20FileIdentifier)) == 0)) + return EImageFileFormat::ktx; + + return EImageFileFormat::unknown; +} + } // namespace Diligent diff --git a/TextureLoader/src/KTXLoader.cpp b/TextureLoader/src/KTXLoader.cpp new file mode 100644 index 0000000..fc679f4 --- /dev/null +++ b/TextureLoader/src/KTXLoader.cpp @@ -0,0 +1,279 @@ +/* Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include <algorithm> +#include "TextureLoader.h" +#include "GraphicsAccessories.h" +#include "Align.h" + +#define GL_RGBA32F 0x8814 +#define GL_RGBA32UI 0x8D70 +#define GL_RGBA32I 0x8D82 +#define GL_RGB32F 0x8815 +#define GL_RGB32UI 0x8D71 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16F 0x881A +#define GL_RGBA16 0x805B +#define GL_RGBA16UI 0x8D76 +#define GL_RGBA16_SNORM 0x8F9B +#define GL_RGBA16I 0x8D88 +#define GL_RG32F 0x8230 +#define GL_RG32UI 0x823C +#define GL_RG32I 0x823B +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_RGB10_A2 0x8059 +#define GL_RGB10_A2UI 0x906F +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_RGBA8 0x8058 +#define GL_RGBA8UI 0x8D7C +#define GL_RGBA8_SNORM 0x8F97 +#define GL_RGBA8I 0x8D8E +#define GL_RG16F 0x822F +#define GL_RG16 0x822C +#define GL_RG16UI 0x823A +#define GL_RG16_SNORM 0x8F99 +#define GL_RG16I 0x8239 +#define GL_R32F 0x822E +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_R32UI 0x8236 +#define GL_R32I 0x8235 +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_RG8 0x822B +#define GL_RG8UI 0x8238 +#define GL_RG8_SNORM 0x8F95 +#define GL_RG8I 0x8237 +#define GL_R16F 0x822D +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_R16 0x822A +#define GL_R16UI 0x8234 +#define GL_R16_SNORM 0x8F98 +#define GL_R16I 0x8233 +#define GL_R8 0x8229 +#define GL_R8UI 0x8232 +#define GL_R8_SNORM 0x8F94 +#define GL_R8I 0x8231 +#define GL_RGB9_E5 0x8C3D + + +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F + +namespace Diligent +{ + +namespace +{ + +TEXTURE_FORMAT FindDiligentTextureFormat(std::uint32_t GLInternalFormat) +{ + switch (GLInternalFormat) + { + case GL_RGBA32F: return TEX_FORMAT_RGBA32_FLOAT; + case GL_RGBA32UI: return TEX_FORMAT_RGBA32_UINT; + case GL_RGBA32I: return TEX_FORMAT_RGBA32_SINT; + + case GL_RGB32F: return TEX_FORMAT_RGB32_FLOAT; + case GL_RGB32UI: return TEX_FORMAT_RGB32_UINT; + case GL_RGB32I: return TEX_FORMAT_RGB32_SINT; + + case GL_RGBA16F: return TEX_FORMAT_RGBA16_FLOAT; + case GL_RGBA16: return TEX_FORMAT_RGBA16_UNORM; + case GL_RGBA16UI: return TEX_FORMAT_RGBA16_UINT; + case GL_RGBA16_SNORM: return TEX_FORMAT_RGBA16_SNORM; + case GL_RGBA16I: return TEX_FORMAT_RGBA16_SINT; + + case GL_RG32F: return TEX_FORMAT_RG32_FLOAT; + case GL_RG32UI: return TEX_FORMAT_RG32_UINT; + case GL_RG32I: return TEX_FORMAT_RG32_SINT; + + case GL_DEPTH32F_STENCIL8: return TEX_FORMAT_D32_FLOAT_S8X24_UINT; + + case GL_RGB10_A2: return TEX_FORMAT_RGB10A2_UNORM; + case GL_RGB10_A2UI: return TEX_FORMAT_RGB10A2_UINT; + case GL_R11F_G11F_B10F: return TEX_FORMAT_R11G11B10_FLOAT; + + case GL_RGBA8: return TEX_FORMAT_RGBA8_UNORM; + case GL_RGBA8UI: return TEX_FORMAT_RGBA8_UINT; + case GL_RGBA8_SNORM: return TEX_FORMAT_RGBA8_SNORM; + case GL_RGBA8I: return TEX_FORMAT_RGBA8_SINT; + + case GL_RG16F: return TEX_FORMAT_RG16_FLOAT; + case GL_RG16: return TEX_FORMAT_RG16_UNORM; + case GL_RG16UI: return TEX_FORMAT_RG16_UINT; + case GL_RG16_SNORM: return TEX_FORMAT_RG16_SNORM; + case GL_RG16I: return TEX_FORMAT_RG16_SINT; + + case GL_R32F: return TEX_FORMAT_R32_FLOAT; + case GL_DEPTH_COMPONENT32F: return TEX_FORMAT_D32_FLOAT; + case GL_R32UI: return TEX_FORMAT_R32_UINT; + case GL_R32I: return TEX_FORMAT_R32_SINT; + + case GL_DEPTH24_STENCIL8: return TEX_FORMAT_D24_UNORM_S8_UINT; + + case GL_RG8: return TEX_FORMAT_RG8_UNORM; + case GL_RG8UI: return TEX_FORMAT_RG8_UINT; + case GL_RG8_SNORM: return TEX_FORMAT_RG8_SNORM; + case GL_RG8I: return TEX_FORMAT_RG8_SINT; + + case GL_R16F: return TEX_FORMAT_R16_FLOAT; + case GL_DEPTH_COMPONENT16: return TEX_FORMAT_D16_UNORM; + case GL_R16: return TEX_FORMAT_R16_UNORM; + case GL_R16UI: return TEX_FORMAT_R16_UINT; + case GL_R16_SNORM: return TEX_FORMAT_R16_SNORM; + case GL_R16I: return TEX_FORMAT_R16_SINT; + + case GL_R8: return TEX_FORMAT_R8_UNORM; + case GL_R8UI: return TEX_FORMAT_R8_UINT; + case GL_R8_SNORM: return TEX_FORMAT_R8_SNORM; + case GL_R8I: return TEX_FORMAT_R8_SINT; + + case GL_RGB9_E5: return TEX_FORMAT_RGB9E5_SHAREDEXP; + + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return TEX_FORMAT_BC1_UNORM; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: return TEX_FORMAT_BC1_UNORM_SRGB; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return TEX_FORMAT_BC2_UNORM; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return TEX_FORMAT_BC2_UNORM_SRGB; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return TEX_FORMAT_BC3_UNORM; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return TEX_FORMAT_BC3_UNORM_SRGB; + case GL_COMPRESSED_RED_RGTC1: return TEX_FORMAT_BC4_UNORM; + case GL_COMPRESSED_SIGNED_RED_RGTC1: return TEX_FORMAT_BC4_SNORM; + case GL_COMPRESSED_RG_RGTC2: return TEX_FORMAT_BC5_UNORM; + case GL_COMPRESSED_SIGNED_RG_RGTC2: return TEX_FORMAT_BC5_SNORM; + + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: return TEX_FORMAT_BC6H_UF16; + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: return TEX_FORMAT_BC6H_SF16; + case GL_COMPRESSED_RGBA_BPTC_UNORM: return TEX_FORMAT_BC7_UNORM; + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: return TEX_FORMAT_BC7_UNORM_SRGB; + default: + UNSUPPORTED("Unsupported internal format"); + return TEX_FORMAT_UNKNOWN; + } +} + +} // namespace + + +struct KTX10Header +{ + std::uint32_t Endianness; + std::uint32_t GLType; + std::uint32_t GLTypeSize; + std::uint32_t GLFormat; + std::uint32_t GLInternalFormat; + std::uint32_t GLBaseInternalFormat; + std::uint32_t Width; + std::uint32_t Height; + std::uint32_t Depth; + std::uint32_t NumberOfArrayElements; + std::uint32_t NumberOfFaces; + std::uint32_t NumberOfMipmapLevels; + std::uint32_t BytesOfKeyValueData; +}; + +void CreateTextureFromKTX( IDataBlob* pKTXData, + const TextureLoadInfo& TexLoadInfo, + IRenderDevice* pDevice, + ITexture** ppTexture ) +{ + static constexpr Uint8 KTX10FileIdentifier[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}; + const Uint8* pData = reinterpret_cast<const Uint8*>(pKTXData->GetDataPtr()); + const auto DataSize = pKTXData->GetSize(); + if (DataSize >= 12 && memcmp(pData, KTX10FileIdentifier, sizeof(KTX10FileIdentifier)) == 0) + { + pData += sizeof(KTX10FileIdentifier); + const KTX10Header& Header = *reinterpret_cast<KTX10Header const*>(pData); + pData += sizeof(KTX10Header); + // Skip key value data + pData += Header.BytesOfKeyValueData; + + TextureDesc TexDesc; + TexDesc.Name = TexLoadInfo.Name; + TexDesc.Format = FindDiligentTextureFormat(Header.GLInternalFormat); + if (TexDesc.Format == TEX_FORMAT_UNKNOWN) + LOG_ERROR_AND_THROW("Failed to find appropriate Diligent format for internal gl format ", Header.GLInternalFormat); + TexDesc.Width = Header.Width; + TexDesc.Height = std::max(Header.Height, 1u); + TexDesc.Depth = std::max(Header.Depth, 1u); + TexDesc.MipLevels = std::max(Header.NumberOfMipmapLevels, 1u); + TexDesc.BindFlags = TexLoadInfo.BindFlags; + TexDesc.Usage = TexLoadInfo.Usage; + auto NumFaces = std::max(Header.NumberOfFaces, 1u); + if (NumFaces == 6) + { + TexDesc.ArraySize = std::max(Header.NumberOfArrayElements, 1u) * NumFaces; + TexDesc.Type = TexDesc.ArraySize > 6 ? RESOURCE_DIM_TEX_CUBE_ARRAY : RESOURCE_DIM_TEX_CUBE; + } + else + { + if (TexDesc.Depth > 1) + { + TexDesc.ArraySize = 1; + TexDesc.Type = RESOURCE_DIM_TEX_3D; + } + else + { + TexDesc.ArraySize = std::max(Header.NumberOfArrayElements, 1u); + TexDesc.Type = TexDesc.ArraySize > 1 ? RESOURCE_DIM_TEX_2D_ARRAY : RESOURCE_DIM_TEX_2D; + } + } + + auto ArraySize = (TexDesc.Type != RESOURCE_DIM_TEX_3D ? TexDesc.ArraySize : 1); + std::vector<TextureSubResData> SubresData(TexDesc.MipLevels * ArraySize); + for (Uint32 mip = 0; mip < TexDesc.MipLevels; ++mip) + { + pData += sizeof(std::uint32_t); + auto MipInfo = GetMipLevelProperties(TexDesc, mip); + + for (Uint32 layer = 0; layer < ArraySize; ++layer) + { + SubresData[mip + layer * TexDesc.MipLevels] = + TextureSubResData{pData, MipInfo.RowSize, MipInfo.DepthSliceSize}; + pData += Align(MipInfo.MipSize, 4u); + } + } + VERIFY(pData - reinterpret_cast<const Uint8*>(pKTXData->GetDataPtr()) == DataSize, "Unexpected data size"); + + TextureData InitData(SubresData.data(), static_cast<Uint32>(SubresData.size())); + pDevice->CreateTexture(TexDesc, &InitData, ppTexture); + } + else + { + LOG_ERROR_AND_THROW("ktx2.0 is not currently supported"); + } +} + +} diff --git a/TextureLoader/src/TextureLoader.cpp b/TextureLoader/src/TextureLoader.cpp index 1f63aae..50ba00a 100644 --- a/TextureLoader/src/TextureLoader.cpp +++ b/TextureLoader/src/TextureLoader.cpp @@ -34,209 +34,211 @@ namespace Diligent { - template<typename ChannelType> - ChannelType SRGBAverage(ChannelType c0, ChannelType c1, ChannelType c2, ChannelType c3) - { - constexpr float NormVal = static_cast<float>(std::numeric_limits<ChannelType>::max()); - float fc0 = static_cast<float>(c0) / NormVal; - float fc1 = static_cast<float>(c1) / NormVal; - float fc2 = static_cast<float>(c2) / NormVal; - float fc3 = static_cast<float>(c3) / NormVal; - - float fLinearAverage = (SRGBToLinear( fc0 ) + SRGBToLinear( fc1 ) + SRGBToLinear( fc2 ) + SRGBToLinear( fc3 )) / 4.f; - float fSRGBAverage = LinearToSRGB(fLinearAverage); - Int32 SRGBAverage = static_cast<Int32>(fSRGBAverage * NormVal); - SRGBAverage = std::min(SRGBAverage, static_cast<Int32>( std::numeric_limits<ChannelType>::max()) ); - SRGBAverage = std::max(SRGBAverage, static_cast<Int32>( std::numeric_limits<ChannelType>::min()) ); - return static_cast<ChannelType>(SRGBAverage); - } - template < typename ChannelType > - void ComputeCoarseMip(Uint32 NumChannels, bool IsSRGB, - const void* pFineMip, - Uint32 FineMipStride, - void* pCoarseMip, - Uint32 CoarseMipStride, - Uint32 CoarseMipWidth, - Uint32 CoarseMipHeight) - { - for( size_t row = 0; row < size_t{CoarseMipHeight}; ++row ) - for( size_t col = 0; col < size_t{CoarseMipWidth}; ++col ) - { - auto FineRow0 = reinterpret_cast<const ChannelType*>( reinterpret_cast<const Uint8*>(pFineMip) + row * 2 * size_t{FineMipStride} ); - auto FineRow1 = reinterpret_cast<const ChannelType*>( reinterpret_cast<const Uint8*>(pFineMip) + (row * 2 + 1 ) * size_t{FineMipStride} ); +template<typename ChannelType> +ChannelType SRGBAverage(ChannelType c0, ChannelType c1, ChannelType c2, ChannelType c3) +{ + constexpr float NormVal = static_cast<float>(std::numeric_limits<ChannelType>::max()); + float fc0 = static_cast<float>(c0) / NormVal; + float fc1 = static_cast<float>(c1) / NormVal; + float fc2 = static_cast<float>(c2) / NormVal; + float fc3 = static_cast<float>(c3) / NormVal; + + float fLinearAverage = (SRGBToLinear( fc0 ) + SRGBToLinear( fc1 ) + SRGBToLinear( fc2 ) + SRGBToLinear( fc3 )) / 4.f; + float fSRGBAverage = LinearToSRGB(fLinearAverage); + Int32 SRGBAverage = static_cast<Int32>(fSRGBAverage * NormVal); + SRGBAverage = std::min(SRGBAverage, static_cast<Int32>( std::numeric_limits<ChannelType>::max()) ); + SRGBAverage = std::max(SRGBAverage, static_cast<Int32>( std::numeric_limits<ChannelType>::min()) ); + return static_cast<ChannelType>(SRGBAverage); +} + +template < typename ChannelType > +void ComputeCoarseMip(Uint32 NumChannels, bool IsSRGB, + const void* pFineMip, + Uint32 FineMipStride, + void* pCoarseMip, + Uint32 CoarseMipStride, + Uint32 CoarseMipWidth, + Uint32 CoarseMipHeight) +{ + for( size_t row = 0; row < size_t{CoarseMipHeight}; ++row ) + for( size_t col = 0; col < size_t{CoarseMipWidth}; ++col ) + { + auto FineRow0 = reinterpret_cast<const ChannelType*>( reinterpret_cast<const Uint8*>(pFineMip) + row * 2 * size_t{FineMipStride} ); + auto FineRow1 = reinterpret_cast<const ChannelType*>( reinterpret_cast<const Uint8*>(pFineMip) + (row * 2 + 1 ) * size_t{FineMipStride} ); - for( Uint32 c = 0; c < NumChannels; ++c ) - { - auto Col00 = FineRow0[ col*2 * NumChannels + c ]; - auto Col01 = FineRow0[ (col*2+1) * NumChannels + c ]; - auto Col10 = FineRow1[ col*2 * NumChannels + c ]; - auto Col11 = FineRow1[ (col*2+1) * NumChannels + c ]; - auto &DstCol = reinterpret_cast<ChannelType*>(reinterpret_cast<Uint8*>(pCoarseMip) + row * size_t{CoarseMipStride})[col * NumChannels + c]; - if( IsSRGB ) - DstCol = SRGBAverage( Col00, Col01, Col10, Col11 ); - else - DstCol = (Col00 + Col01 + Col10 + Col11)/4; - } + for( Uint32 c = 0; c < NumChannels; ++c ) + { + auto Col00 = FineRow0[ col*2 * NumChannels + c ]; + auto Col01 = FineRow0[ (col*2+1) * NumChannels + c ]; + auto Col10 = FineRow1[ col*2 * NumChannels + c ]; + auto Col11 = FineRow1[ (col*2+1) * NumChannels + c ]; + auto &DstCol = reinterpret_cast<ChannelType*>(reinterpret_cast<Uint8*>(pCoarseMip) + row * size_t{CoarseMipStride})[col * NumChannels + c]; + if( IsSRGB ) + DstCol = SRGBAverage( Col00, Col01, Col10, Col11 ); + else + DstCol = (Col00 + Col01 + Col10 + Col11)/4; } - } + } +} - template < typename ChannelType > - void RGBToRGBA(const void* pRGBData, - Uint32 RGBStride, - void* pRGBAData, - Uint32 RGBAStride, - Uint32 Width, - Uint32 Height) - { - for( size_t row = 0; row < size_t{Height}; ++row ) - for( size_t col = 0; col < size_t{Width}; ++col ) +template < typename ChannelType > +void RGBToRGBA(const void* pRGBData, + Uint32 RGBStride, + void* pRGBAData, + Uint32 RGBAStride, + Uint32 Width, + Uint32 Height) +{ + for( size_t row = 0; row < size_t{Height}; ++row ) + for( size_t col = 0; col < size_t{Width}; ++col ) + { + for( int c = 0; c < 3; ++c ) { - for( int c = 0; c < 3; ++c ) - { - reinterpret_cast<ChannelType*>( (reinterpret_cast<Uint8*>(pRGBAData) + size_t{RGBAStride} * row) ) [col *4 + c] = - reinterpret_cast<const ChannelType*>( (reinterpret_cast<const Uint8*>(pRGBData) + size_t{RGBStride} * row))[col*3 + c]; - } - reinterpret_cast<ChannelType*>( (reinterpret_cast<Uint8*>(pRGBAData) + size_t{RGBAStride} * row) ) [col *4 + 3] = std::numeric_limits<ChannelType>::max(); + reinterpret_cast<ChannelType*>( (reinterpret_cast<Uint8*>(pRGBAData) + size_t{RGBAStride} * row) ) [col *4 + c] = + reinterpret_cast<const ChannelType*>( (reinterpret_cast<const Uint8*>(pRGBData) + size_t{RGBStride} * row))[col*3 + c]; } - } + reinterpret_cast<ChannelType*>( (reinterpret_cast<Uint8*>(pRGBAData) + size_t{RGBAStride} * row) ) [col *4 + 3] = std::numeric_limits<ChannelType>::max(); + } +} - void CreateTextureFromImage( Image* pSrcImage, - const TextureLoadInfo& TexLoadInfo, - IRenderDevice* pDevice, - ITexture** ppTexture ) +void CreateTextureFromImage( Image* pSrcImage, + const TextureLoadInfo& TexLoadInfo, + IRenderDevice* pDevice, + ITexture** ppTexture ) +{ + const auto& ImgDesc = pSrcImage->GetDesc(); + TextureDesc TexDesc; + TexDesc.Name = TexLoadInfo.Name; + TexDesc.Type = RESOURCE_DIM_TEX_2D; + TexDesc.Width = ImgDesc.Width; + TexDesc.Height = ImgDesc.Height; + TexDesc.MipLevels = ComputeMipLevelsCount( TexDesc.Width, TexDesc.Height ); + if( TexLoadInfo.MipLevels > 0 ) + TexDesc.MipLevels = std::min(TexDesc.MipLevels, TexLoadInfo.MipLevels); + TexDesc.Usage = TexLoadInfo.Usage; + TexDesc.BindFlags = TexLoadInfo.BindFlags; + TexDesc.Format = TexLoadInfo.Format; + TexDesc.CPUAccessFlags = TexLoadInfo.CPUAccessFlags; + auto ChannelDepth = ImgDesc.BitsPerPixel / ImgDesc.NumComponents; + + Uint32 NumComponents = ImgDesc.NumComponents == 3 ? 4 : ImgDesc.NumComponents; + bool IsSRGB = (ImgDesc.NumComponents >= 3 && ChannelDepth == 8) ? TexLoadInfo.IsSRGB : false; + if( TexDesc.Format == TEX_FORMAT_UNKNOWN ) { - const auto& ImgDesc = pSrcImage->GetDesc(); - TextureDesc TexDesc; - TexDesc.Name = TexLoadInfo.Name; - TexDesc.Type = RESOURCE_DIM_TEX_2D; - TexDesc.Width = ImgDesc.Width; - TexDesc.Height = ImgDesc.Height; - TexDesc.MipLevels = ComputeMipLevelsCount( TexDesc.Width, TexDesc.Height ); - if( TexLoadInfo.MipLevels > 0 ) - TexDesc.MipLevels = std::min(TexDesc.MipLevels, TexLoadInfo.MipLevels); - TexDesc.Usage = TexLoadInfo.Usage; - TexDesc.BindFlags = TexLoadInfo.BindFlags; - TexDesc.Format = TexLoadInfo.Format; - TexDesc.CPUAccessFlags = TexLoadInfo.CPUAccessFlags; - auto ChannelDepth = ImgDesc.BitsPerPixel / ImgDesc.NumComponents; - - Uint32 NumComponents = ImgDesc.NumComponents == 3 ? 4 : ImgDesc.NumComponents; - bool IsSRGB = (ImgDesc.NumComponents >= 3 && ChannelDepth == 8) ? TexLoadInfo.IsSRGB : false; - if( TexDesc.Format == TEX_FORMAT_UNKNOWN ) + if( ChannelDepth == 8 ) { - if( ChannelDepth == 8 ) + switch( NumComponents ) { - switch( NumComponents ) - { - case 1: TexDesc.Format = TEX_FORMAT_R8_UNORM; break; - case 2: TexDesc.Format = TEX_FORMAT_RG8_UNORM; break; - case 4: TexDesc.Format = IsSRGB ? TEX_FORMAT_RGBA8_UNORM_SRGB : TEX_FORMAT_RGBA8_UNORM; break; - default: LOG_ERROR_AND_THROW( "Unexpected number of color channels (", ImgDesc.NumComponents, ")" ); - } + case 1: TexDesc.Format = TEX_FORMAT_R8_UNORM; break; + case 2: TexDesc.Format = TEX_FORMAT_RG8_UNORM; break; + case 4: TexDesc.Format = IsSRGB ? TEX_FORMAT_RGBA8_UNORM_SRGB : TEX_FORMAT_RGBA8_UNORM; break; + default: LOG_ERROR_AND_THROW( "Unexpected number of color channels (", ImgDesc.NumComponents, ")" ); } - else if( ChannelDepth == 16 ) + } + else if( ChannelDepth == 16 ) + { + switch( NumComponents ) { - switch( NumComponents ) - { - case 1: TexDesc.Format = TEX_FORMAT_R16_UNORM; break; - case 2: TexDesc.Format = TEX_FORMAT_RG16_UNORM; break; - case 4: TexDesc.Format = TEX_FORMAT_RGBA16_UNORM; break; - default: LOG_ERROR_AND_THROW( "Unexpected number of color channels (", ImgDesc.NumComponents, ")" ); - } + case 1: TexDesc.Format = TEX_FORMAT_R16_UNORM; break; + case 2: TexDesc.Format = TEX_FORMAT_RG16_UNORM; break; + case 4: TexDesc.Format = TEX_FORMAT_RGBA16_UNORM; break; + default: LOG_ERROR_AND_THROW( "Unexpected number of color channels (", ImgDesc.NumComponents, ")" ); } - else - LOG_ERROR_AND_THROW( "Unsupported color channel depth (", ChannelDepth, ")" ); } else - { - const auto& TexFmtDesc = GetTextureFormatAttribs( TexDesc.Format ); - if( TexFmtDesc.NumComponents != NumComponents ) - LOG_ERROR_AND_THROW( "Incorrect number of components ", ImgDesc.NumComponents, ") for texture format ", TexFmtDesc.Name ); - if( TexFmtDesc.ComponentSize != ChannelDepth / 8 ) - LOG_ERROR_AND_THROW( "Incorrect channel size ", ChannelDepth, ") for texture format ", TexFmtDesc.Name ); - } + LOG_ERROR_AND_THROW( "Unsupported color channel depth (", ChannelDepth, ")" ); + } + else + { + const auto& TexFmtDesc = GetTextureFormatAttribs( TexDesc.Format ); + if( TexFmtDesc.NumComponents != NumComponents ) + LOG_ERROR_AND_THROW( "Incorrect number of components ", ImgDesc.NumComponents, ") for texture format ", TexFmtDesc.Name ); + if( TexFmtDesc.ComponentSize != ChannelDepth / 8 ) + LOG_ERROR_AND_THROW( "Incorrect channel size ", ChannelDepth, ") for texture format ", TexFmtDesc.Name ); + } - std::vector<TextureSubResData> pSubResources(TexDesc.MipLevels); - std::vector< std::vector<Uint8> > Mips(TexDesc.MipLevels); + std::vector<TextureSubResData> pSubResources(TexDesc.MipLevels); + std::vector< std::vector<Uint8> > Mips(TexDesc.MipLevels); - if( ImgDesc.NumComponents == 3 ) - { - VERIFY_EXPR( NumComponents == 4 ); - auto RGBAStride = ImgDesc.Width * NumComponents * ChannelDepth / 8; - RGBAStride = (RGBAStride + 3) & (-4); - Mips[0].resize(size_t{RGBAStride} * size_t{ImgDesc.Height}); - pSubResources[0].pData = Mips[0].data(); - pSubResources[0].Stride = RGBAStride; - if( ChannelDepth == 8 ) - RGBToRGBA<Uint8>( pSrcImage->GetData()->GetDataPtr(), ImgDesc.RowStride, - Mips[0].data(), RGBAStride, - ImgDesc.Width, ImgDesc.Height); - else if( ChannelDepth == 16 ) - RGBToRGBA<Uint16>( pSrcImage->GetData()->GetDataPtr(), ImgDesc.RowStride, - Mips[0].data(), RGBAStride, - ImgDesc.Width, ImgDesc.Height); - } - else - { - pSubResources[0].pData = pSrcImage->GetData()->GetDataPtr(); - pSubResources[0].Stride = ImgDesc.RowStride; - } + if( ImgDesc.NumComponents == 3 ) + { + VERIFY_EXPR( NumComponents == 4 ); + auto RGBAStride = ImgDesc.Width * NumComponents * ChannelDepth / 8; + RGBAStride = (RGBAStride + 3) & (-4); + Mips[0].resize(size_t{RGBAStride} * size_t{ImgDesc.Height}); + pSubResources[0].pData = Mips[0].data(); + pSubResources[0].Stride = RGBAStride; + if( ChannelDepth == 8 ) + RGBToRGBA<Uint8>( pSrcImage->GetData()->GetDataPtr(), ImgDesc.RowStride, + Mips[0].data(), RGBAStride, + ImgDesc.Width, ImgDesc.Height); + else if( ChannelDepth == 16 ) + RGBToRGBA<Uint16>( pSrcImage->GetData()->GetDataPtr(), ImgDesc.RowStride, + Mips[0].data(), RGBAStride, + ImgDesc.Width, ImgDesc.Height); + } + else + { + pSubResources[0].pData = pSrcImage->GetData()->GetDataPtr(); + pSubResources[0].Stride = ImgDesc.RowStride; + } - auto MipWidth = TexDesc.Width; - auto MipHeight = TexDesc.Height; - for( Uint32 m = 1; m < TexDesc.MipLevels; ++m ) + auto MipWidth = TexDesc.Width; + auto MipHeight = TexDesc.Height; + for( Uint32 m = 1; m < TexDesc.MipLevels; ++m ) + { + auto CoarseMipWidth = std::max(MipWidth/2u, 1u); + auto CoarseMipHeight = std::max(MipHeight/2u, 1u); + auto CoarseMipStride = CoarseMipWidth * NumComponents * ChannelDepth / 8; + CoarseMipStride = (CoarseMipStride + 3) & (-4); + Mips[m].resize(size_t{CoarseMipStride} * size_t{CoarseMipHeight}); + + if (TexLoadInfo.GenerateMips) { - auto CoarseMipWidth = std::max(MipWidth/2u, 1u); - auto CoarseMipHeight = std::max(MipHeight/2u, 1u); - auto CoarseMipStride = CoarseMipWidth * NumComponents * ChannelDepth / 8; - CoarseMipStride = (CoarseMipStride + 3) & (-4); - Mips[m].resize(size_t{CoarseMipStride} * size_t{CoarseMipHeight}); + if (ChannelDepth == 8) + ComputeCoarseMip<Uint8>(NumComponents, IsSRGB, + pSubResources[m - 1].pData, pSubResources[m - 1].Stride, + Mips[m].data(), CoarseMipStride, + CoarseMipWidth, CoarseMipHeight); + else if (ChannelDepth == 16) + ComputeCoarseMip<Uint16>(NumComponents, IsSRGB, + pSubResources[m - 1].pData, pSubResources[m - 1].Stride, + Mips[m].data(), CoarseMipStride, + CoarseMipWidth, CoarseMipHeight); + } - if (TexLoadInfo.GenerateMips) - { - if (ChannelDepth == 8) - ComputeCoarseMip<Uint8>(NumComponents, IsSRGB, - pSubResources[m - 1].pData, pSubResources[m - 1].Stride, - Mips[m].data(), CoarseMipStride, - CoarseMipWidth, CoarseMipHeight); - else if (ChannelDepth == 16) - ComputeCoarseMip<Uint16>(NumComponents, IsSRGB, - pSubResources[m - 1].pData, pSubResources[m - 1].Stride, - Mips[m].data(), CoarseMipStride, - CoarseMipWidth, CoarseMipHeight); - } + pSubResources[m].pData = Mips[m].data(); + pSubResources[m].Stride = CoarseMipStride; - pSubResources[m].pData = Mips[m].data(); - pSubResources[m].Stride = CoarseMipStride; + MipWidth = CoarseMipWidth; + MipHeight = CoarseMipHeight; + } - MipWidth = CoarseMipWidth; - MipHeight = CoarseMipHeight; - } + TextureData TexData; + TexData.pSubResources = pSubResources.data(); + TexData.NumSubresources = TexDesc.MipLevels; - TextureData TexData; - TexData.pSubResources = pSubResources.data(); - TexData.NumSubresources = TexDesc.MipLevels; + pDevice->CreateTexture( TexDesc, &TexData, ppTexture ); +} - pDevice->CreateTexture( TexDesc, &TexData, ppTexture ); - } +void CreateTextureFromDDS( IDataBlob* pDDSData, + const TextureLoadInfo& TexLoadInfo, + IRenderDevice* pDevice, + ITexture** ppTexture ) +{ + CreateDDSTextureFromMemoryEx(pDevice, + reinterpret_cast<const Uint8*>(pDDSData->GetDataPtr()), + static_cast<size_t>(pDDSData->GetSize()), + 0, // maxSize + TexLoadInfo.Usage, + TexLoadInfo.Name, + TexLoadInfo.BindFlags, + TexLoadInfo.CPUAccessFlags, + MISC_TEXTURE_FLAG_NONE, // miscFlags + TexLoadInfo.IsSRGB, // forceSRGB + ppTexture ); +} - void CreateTextureFromDDS( IDataBlob *pDDSData, - const TextureLoadInfo& TexLoadInfo, - IRenderDevice *pDevice, - ITexture **ppTexture ) - { - CreateDDSTextureFromMemoryEx(pDevice, - reinterpret_cast<const Uint8*>(pDDSData->GetDataPtr()), - static_cast<size_t>(pDDSData->GetSize()), - 0, // maxSize - TexLoadInfo.Usage, - TexLoadInfo.Name, - TexLoadInfo.BindFlags, - TexLoadInfo.CPUAccessFlags, - MISC_TEXTURE_FLAG_NONE, // miscFlags - TexLoadInfo.IsSRGB, // forceSRGB - ppTexture ); - } } diff --git a/TextureLoader/src/TextureUtilities.cpp b/TextureLoader/src/TextureUtilities.cpp index 74bd302..7a41c7a 100644 --- a/TextureLoader/src/TextureUtilities.cpp +++ b/TextureLoader/src/TextureUtilities.cpp @@ -36,69 +36,90 @@ using namespace Diligent; namespace Diligent { -void CreateImageFromFile( const Char *FilePath, - Image **ppImage, - IDataBlob **ppDDSData) +EImageFileFormat CreateImageFromFile(const Char* FilePath, + Image** ppImage, + IDataBlob** ppRawData) { + EImageFileFormat ImgFileFormat = EImageFileFormat::unknown; try { - auto *pDotPos = strrchr(FilePath, '.'); - if (pDotPos == nullptr) - LOG_ERROR_AND_THROW("File path \"", FilePath, "\" does not contain extension"); - - auto *pExtension = pDotPos + 1; - if (*pExtension == 0) - LOG_ERROR_AND_THROW("File path \"", FilePath, "\" contains empty extension"); - - String Extension = StrToLower(pExtension); RefCntAutoPtr<BasicFileStream> pFileStream(MakeNewRCObj<BasicFileStream>()(FilePath, EFileAccessMode::Read)); if(!pFileStream->IsValid()) LOG_ERROR_AND_THROW("Failed to open image file \"", FilePath, '\"'); - if (Extension == "dds") - { - VERIFY_EXPR(ppDDSData != nullptr); - *ppDDSData = MakeNewRCObj<DataBlobImpl>()(0); - pFileStream->Read(*ppDDSData); - (*ppDDSData)->AddRef(); - } - else + RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0)); + pFileStream->Read(pFileData); + + ImgFileFormat = Image::GetFileFormat(reinterpret_cast<Uint8*>(pFileData->GetDataPtr()), pFileData->GetSize()); + if (ImgFileFormat == EImageFileFormat::unknown) { - ImageLoadInfo ImgLoadInfo; + LOG_WARNING_MESSAGE("Unable to derive image format from the header for file \"", FilePath, "\". Trying to analyze extension."); + + // Try to use extension to derive format + auto *pDotPos = strrchr(FilePath, '.'); + if (pDotPos == nullptr) + LOG_ERROR_AND_THROW("Unable to recognize file format: file name \"", FilePath, "\" does not contain extension"); + + auto *pExtension = pDotPos + 1; + if (*pExtension == 0) + LOG_ERROR_AND_THROW("Unable to recognize file format: file name \"", FilePath, "\" contain empty extension"); + + String Extension = StrToLower(pExtension); if (Extension == "png") - ImgLoadInfo.Format = EImageFileFormat::png; + ImgFileFormat = EImageFileFormat::png; else if (Extension == "jpeg" || Extension == "jpg") - ImgLoadInfo.Format = EImageFileFormat::jpeg; + ImgFileFormat = EImageFileFormat::jpeg; else if (Extension == "tiff" || Extension == "tif") - ImgLoadInfo.Format = EImageFileFormat::tiff; + ImgFileFormat = EImageFileFormat::tiff; + else if (Extension == "dds") + ImgFileFormat = EImageFileFormat::dds; + else if (Extension == "ktx") + ImgFileFormat = EImageFileFormat::ktx; else LOG_ERROR_AND_THROW("Unsupported file format ", Extension); + } - RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0)); - pFileStream->Read(pFileData); - + if (ImgFileFormat == EImageFileFormat::png || + ImgFileFormat == EImageFileFormat::jpeg || + ImgFileFormat == EImageFileFormat::tiff) + { + ImageLoadInfo ImgLoadInfo; + ImgLoadInfo.Format = ImgFileFormat; Image::CreateFromDataBlob(pFileData, ImgLoadInfo, ppImage); } + else + { + *ppRawData = pFileData.Detach(); + } } catch (std::runtime_error &err) { LOG_ERROR("Failed to create image from file: ", err.what()); } + + return ImgFileFormat; } -void CreateTextureFromFile( const Char *FilePath, - const TextureLoadInfo& TexLoadInfo, - IRenderDevice *pDevice, - ITexture **ppTexture ) +void CreateTextureFromFile(const Char* FilePath, + const TextureLoadInfo& TexLoadInfo, + IRenderDevice* pDevice, + ITexture** ppTexture ) { - RefCntAutoPtr<Image> pImage; - RefCntAutoPtr<IDataBlob> pDDSData; - CreateImageFromFile( FilePath, &pImage, &pDDSData ); + RefCntAutoPtr<Image> pImage; + RefCntAutoPtr<IDataBlob> pRawData; + auto ImgFmt = CreateImageFromFile( FilePath, &pImage, &pRawData ); - if( pImage ) + if (pImage) CreateTextureFromImage( pImage, TexLoadInfo, pDevice, ppTexture ); - else if(pDDSData) - CreateTextureFromDDS( pDDSData, TexLoadInfo, pDevice, ppTexture ); + else if (pRawData) + { + if (ImgFmt == EImageFileFormat::dds) + CreateTextureFromDDS( pRawData, TexLoadInfo, pDevice, ppTexture ); + else if (ImgFmt == EImageFileFormat::ktx) + CreateTextureFromKTX( pRawData, TexLoadInfo, pDevice, ppTexture ); + else + UNEXPECTED("Unexpected format"); + } } } |
