Add BC4, BC5 and BC7 formats decompression support on non-Windows platforms

This commit is contained in:
Wojtek Figat
2023-02-28 15:51:05 +01:00
parent 127c575752
commit b2f7ffa545
9 changed files with 1196 additions and 56 deletions

View File

@@ -460,6 +460,21 @@ TextureTool::PixelFormatSampler PixelFormatSamplers[] =
*(Color32*)ptr = Color32(srgb);
},
},
{
PixelFormat::R8G8_UNorm,
sizeof(uint16),
[](const void* ptr)
{
const uint8* rg = (const uint8*)ptr;
return Color((float)rg[0] / MAX_uint8, (float)rg[1] / MAX_uint8, 0, 1);
},
[](const void* ptr, const Color& color)
{
uint8* rg = (uint8*)ptr;
rg[0] = (uint8)(color.R * MAX_uint8);
rg[1] = (uint8)(color.G * MAX_uint8);
},
},
{
PixelFormat::R16G16_Float,
sizeof(Half2),

View File

@@ -63,7 +63,21 @@ static TextureData const* stbDecompress(const TextureData& textureData, TextureD
{
if (!PixelFormatExtensions::IsCompressed(textureData.Format))
return &textureData;
decompressed.Format = PixelFormatExtensions::IsSRGB(textureData.Format) ? PixelFormat::R8G8B8A8_UNorm_sRGB : PixelFormat::R8G8B8A8_UNorm;
const bool srgb = PixelFormatExtensions::IsSRGB(textureData.Format);
switch (textureData.Format)
{
case PixelFormat::BC4_UNorm:
case PixelFormat::BC4_SNorm:
decompressed.Format = PixelFormat::R8_UNorm;
break;
case PixelFormat::BC5_UNorm:
case PixelFormat::BC5_SNorm:
decompressed.Format = PixelFormat::R8G8_UNorm;
break;
default:
decompressed.Format = srgb ? PixelFormat::R8G8B8A8_UNorm_sRGB : PixelFormat::R8G8B8A8_UNorm;
break;
}
decompressed.Width = textureData.Width;
decompressed.Height = textureData.Height;
decompressed.Depth = textureData.Depth;
@@ -71,7 +85,7 @@ static TextureData const* stbDecompress(const TextureData& textureData, TextureD
decompressed.Items[0].Mips.Resize(1);
TextureMipData* decompressedData = decompressed.GetData(0, 0);
decompressedData->RowPitch = textureData.Width * sizeof(Color32);
decompressedData->RowPitch = textureData.Width * PixelFormatExtensions::SizeInBytes(decompressed.Format);
decompressedData->Lines = textureData.Height;
decompressedData->DepthPitch = decompressedData->RowPitch * decompressedData->Lines;
decompressedData->Data.Allocate(decompressedData->DepthPitch);
@@ -83,72 +97,74 @@ static TextureData const* stbDecompress(const TextureData& textureData, TextureD
const TextureMipData* blocksData = textureData.GetData(0, 0);
const byte* blocksBytes = blocksData->Data.Get();
typedef bool (*detexDecompressBlockFuncType)(const uint8_t* bitstring, uint32_t mode_mask, uint32_t flags, uint8_t* pixel_buffer);
detexDecompressBlockFuncType detexDecompressBlockFunc;
int32 pixelSize, blockSize;
switch (textureData.Format)
{
case PixelFormat::BC1_UNorm:
case PixelFormat::BC1_UNorm_sRGB:
{
for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++)
{
for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++)
{
const byte* block = blocksBytes + yBlock * blocksData->RowPitch + xBlock * 8;
detexDecompressBlockBC1(block, 0, 0, (byte*)&colors);
for (int32 y = 0; y < 4; y++)
{
for (int32 x = 0; x < 4; x++)
{
*((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x];
}
}
}
}
detexDecompressBlockFunc = detexDecompressBlockBC1;
pixelSize = 4;
blockSize = 8;
break;
}
case PixelFormat::BC2_UNorm:
case PixelFormat::BC2_UNorm_sRGB:
{
for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++)
{
for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++)
{
const byte* block = blocksBytes + yBlock * blocksData->RowPitch + xBlock * 16;
detexDecompressBlockBC2(block, 0, 0, (byte*)&colors);
for (int32 y = 0; y < 4; y++)
{
for (int32 x = 0; x < 4; x++)
{
*((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x];
}
}
}
}
detexDecompressBlockFunc = detexDecompressBlockBC2;
pixelSize = 4;
blockSize = 16;
break;
}
case PixelFormat::BC3_UNorm:
case PixelFormat::BC3_UNorm_sRGB:
{
for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++)
{
for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++)
{
const byte* block = blocksBytes + yBlock * blocksData->RowPitch + xBlock * 16;
detexDecompressBlockBC3(block, 0, 0, (byte*)&colors);
for (int32 y = 0; y < 4; y++)
{
for (int32 x = 0; x < 4; x++)
{
*((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x];
}
}
}
}
detexDecompressBlockFunc = detexDecompressBlockBC3;
pixelSize = 4;
blockSize = 16;
break;
case PixelFormat::BC4_UNorm:
detexDecompressBlockFunc = detexDecompressBlockRGTC1;
pixelSize = 1;
blockSize = 8;
break;
case PixelFormat::BC5_UNorm:
detexDecompressBlockFunc = detexDecompressBlockRGTC2;
pixelSize = 2;
blockSize = 16;
break;
case PixelFormat::BC7_UNorm:
case PixelFormat::BC7_UNorm_sRGB:
detexDecompressBlockFunc = detexDecompressBlockBPTC;
pixelSize = 4;
blockSize = 16;
break;
}
default:
LOG(Warning, "Texture data format {0} is not supported by stb library.", (int32)textureData.Format);
LOG(Warning, "Texture data format {0} is not supported by detex library.", (int32)textureData.Format);
return nullptr;
}
uint8 blockBuffer[DETEX_MAX_BLOCK_SIZE];
for (int32 y = 0; y < blocksHeight; y++)
{
int32 rows;
if (y * 4 + 3 >= textureData.Height)
rows = textureData.Height - y * 4;
else
rows = 4;
for (int32 x = 0; x < blocksWidth; x++)
{
const byte* block = blocksBytes + y * blocksData->RowPitch + x * blockSize;
if (!detexDecompressBlockFunc(block, DETEX_MODE_MASK_ALL, 0, blockBuffer))
memset(blockBuffer, 0, DETEX_MAX_BLOCK_SIZE);
uint8* pixels = decompressedBytes + y * 4 * textureData.Width * pixelSize + x * 4 * pixelSize;
int32 columns;
if (x * 4 + 3 >= textureData.Width)
columns = textureData.Width - x * 4;
else
columns = 4;
for (int32 row = 0; row < rows; row++)
memcpy(pixels + row * textureData.Width * pixelSize, blockBuffer + row * 4 * pixelSize, columns * pixelSize);
}
}
return &decompressed;
}