HiresTextures: Support DXT10 extended header in DDS loader

This commit is contained in:
Stenzek 2017-04-21 19:33:05 +10:00
parent 8761c8244d
commit a6a13f51c1
1 changed files with 51 additions and 26 deletions

View File

@ -196,7 +196,8 @@ static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
return false;
DDS_HEADER header;
if (!file.ReadBytes(&header, sizeof(header)) || header.dwSize < sizeof(header))
size_t header_size = sizeof(header);
if (!file.ReadBytes(&header, header_size) || header.dwSize < header_size)
return false;
// Required fields.
@ -229,26 +230,44 @@ static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
info->mip_count = 1;
}
// Handle fourcc formats vs uncompressed formats.
bool has_fourcc = (header.ddspf.dwFlags & DDS_FOURCC) != 0;
bool needs_s3tc = false;
if (has_fourcc)
{
// Handle DX10 extension header.
u32 dxt10_format = 0;
if (header.ddspf.dwFourCC == MAKEFOURCC('D', 'X', '1', '0'))
{
DDS_HEADER_DXT10 dxt10_header;
if (!file.ReadBytes(&dxt10_header, sizeof(dxt10_header)))
return false;
// Can't handle array textures here. Doesn't make sense to use them, anyway.
if (dxt10_header.resourceDimension != DDS_DIMENSION_TEXTURE2D || dxt10_header.arraySize != 1)
return false;
header_size += sizeof(dxt10_header);
dxt10_format = dxt10_header.dxgiFormat;
}
// Currently, we only handle compressed textures here, and leave the rest to the SOIL loader.
// In the future, this could be extended, but these isn't much benefit in doing so currently.
// TODO: DX10 extension header handling.
// TODO: Support RGBA8 and friends.
bool needs_s3tc = false;
if (header.ddspf.dwFourCC == MAKEFOURCC('D', 'X', 'T', '1'))
if (header.ddspf.dwFourCC == MAKEFOURCC('D', 'X', 'T', '1') || dxt10_format == 71)
{
info->format = HostTextureFormat::DXT1;
info->block_size = 4;
info->bytes_per_block = 8;
needs_s3tc = true;
}
else if (header.ddspf.dwFourCC == MAKEFOURCC('D', 'X', 'T', '3'))
else if (header.ddspf.dwFourCC == MAKEFOURCC('D', 'X', 'T', '3') || dxt10_format == 74)
{
info->format = HostTextureFormat::DXT3;
info->block_size = 4;
info->bytes_per_block = 16;
needs_s3tc = true;
}
else if (header.ddspf.dwFourCC == MAKEFOURCC('D', 'X', 'T', '5'))
else if (header.ddspf.dwFourCC == MAKEFOURCC('D', 'X', 'T', '5') || dxt10_format == 77)
{
info->format = HostTextureFormat::DXT5;
info->block_size = 4;
@ -260,6 +279,12 @@ static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
// Leave all remaining formats to SOIL.
return false;
}
}
else
{
// TODO: Support RGBA8 and friends.
return false;
}
// We also need to ensure the backend supports these formats natively before loading them,
// otherwise, fallback to SOIL, which will decompress them to RGBA.
@ -295,7 +320,7 @@ static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
}
// Check for truncated or corrupted files.
info->first_mip_offset = sizeof(magic) + sizeof(DDS_HEADER);
info->first_mip_offset = sizeof(magic) + header_size;
if (info->first_mip_offset >= file.GetSize())
return false;