summaryrefslogtreecommitdiffstats
path: root/TextureLoader/src
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2019-04-28 21:32:59 +0000
committerEgor Yusov <egor.yusov@gmail.com>2019-04-28 21:32:59 +0000
commit450a6606cedbf45aa888637058af4742d5491b01 (patch)
tree820210d82c58b39f42323f23ada328c919effe60 /TextureLoader/src
parentUpdated GLTF loader to use Diligent file system functions (diff)
downloadDiligentTools-450a6606cedbf45aa888637058af4742d5491b01.tar.gz
DiligentTools-450a6606cedbf45aa888637058af4742d5491b01.zip
Implemented loading textures from KTX
Diffstat (limited to 'TextureLoader/src')
-rw-r--r--TextureLoader/src/Image.cpp42
-rw-r--r--TextureLoader/src/KTXLoader.cpp279
-rw-r--r--TextureLoader/src/TextureLoader.cpp360
-rw-r--r--TextureLoader/src/TextureUtilities.cpp95
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");
+ }
}
}