Add support for missing BC4 and BC5 DDS FourCC codes
The ReadPixelFormatFourCc only recognizes DXT1, DXT3, DXT5, and DX10 FourCC codes. This omits several common codes used for BC4 (ATI1) and BC5 (ATI2) formats, as well as their signed and explicit unsigned variants.
This causes the tool to fail when loading valid DDS files that use these alternative codes, especially important for any BC4 or BC5 which will not load at all with the current ReadPixelFormatFourCc.
Missing FourCC Codes:
-
BC4 Unsigned:
-
ATI1(FileUtils::MakeMagic32('A', 'T', 'I', '1')) -
BC4U(FileUtils::MakeMagic32('B', 'C', '4', 'U'))
-
-
BC4 Signed:
-
BC4S(FileUtils::MakeMagic32('B', 'C', '4', 'S'))
-
-
BC5 Unsigned:
-
ATI2(FileUtils::MakeMagic32('A', 'T', 'I', '2')) -
A2XY(FileUtils::MakeMagic32('A', '2', 'X', 'Y')) -
BC5U(FileUtils::MakeMagic32('B', 'C', '5', 'U'))
-
-
BC5 Signed:
-
BC5S(FileUtils::MakeMagic32('B', 'C', '5', 'S'))
-
The ReadPixelFormatFourCc function could be updated to include these new cases.
[[nodiscard]] bool ReadPixelFormatFourCc(DDS_PIXELFORMAT& pf)
{
switch (pf.dwFourCC)
{
case FileUtils::MakeMagic32('D', 'X', 'T', '1'):
m_format = &ImageFormat::FORMAT_BC1;
return true;
case FileUtils::MakeMagic32('D', 'X', 'T', '3'):
m_format = &ImageFormat::FORMAT_BC2;
return true;
case FileUtils::MakeMagic32('D', 'X', 'T', '5'):
m_format = &ImageFormat::FORMAT_BC3;
return true;
// BC4 Unsigned
case FileUtils::MakeMagic32('A', 'T', 'I', '1'):
case FileUtils::MakeMagic32('B', 'C', '4', 'U'):
m_format = &ImageFormat::FORMAT_BC4;
return true;
// BC5 Unsigned
case FileUtils::MakeMagic32('A', 'T', 'I', '2'):
case FileUtils::MakeMagic32('A', '2', 'X', 'Y'):
case FileUtils::MakeMagic32('B', 'C', '5', 'U'):
m_format = &ImageFormat::FORMAT_BC5;
return true;
case FileUtils::MakeMagic32('D', 'X', '1', '0'):
return ReadDxt10Header();
default:
con::error("Unknown dds FourCC {}", pf.dwFourCC);
return false;
}
}
Hey there, thanks for the suggestion. Yeah, it's true that creating this addition will make OAT be able to parse the FourCC variants you are suggesting. The thing is that there needs to be additional functionality for these formats to make loading them useful.
As of right now OAT is using DDS parsing for two things:
- Creating IWIs with Linker when creating image assets for IW3 only (nice job me for feature parity... - didn't even remember that one)
- For ImageConverter for converting DDS files to IWI
Since the first feature is kind of niche i guess what is important for you is mostly the second point 😅
There are two things to notice for this when it comes to ImageConverter:
-
The ImageConverter as of right now does not convert the raw image data yet. It just translates headers and metadata and rearranges the mipmaps correctly, but it does not convert from one format to another (like R8G8B8 to B8G8R8, BC5 to BC3 or whatever). Additionally, while there is a TextureConverter in the code already that can convert data, there is no implementation yet for any block compressed formats like BC1-5.
-
The IWI formats only supports a limited subset of formats that are available for DDS. Additionally, the game also only supports a subset of these IWI formats for loading as well. This limits the use of being able to load these two formats from DDS files. As far as I can tell there is exactly 1 game (that OAT supports) which supports BC5 which is T6 (even though it does not seem to make use of it whatsoever on PC). BC4 is not supported by any game nor does it have an IWI format code.
So maybe you can clarify what behaviour you would expect from being able to load these two DDS format types 😅 Do you expect some conversion to happen into another format? Or is there something I am misunderstanding?
Hello, thanks for coming back.
I believe it does relate more to the second point than the first - I've had people ask me why textures that have been exported from Saluki are not compatible with the OAT image converter, but the same ones converted through Greyhound work fine - and I believe this is due to Saluki exporting DDS images as is (retaining the original format) - Whereas Greyhound does not do this so the images can be used as is.
The specifics of what I was being asked was in regards to T6 - mainly for BC5, as I had a report of the above, so I had tested with BC5 images exported from BO2 specifically and had the same 'Unknown dds FourCC'.
Alright i see. Idk how many textures of T6 are BC5, but there seem to be some, so supporting that format from DDS seems like a good idea. Since there can't be any BC4 textures though idk if supporting it makes much sense.
Alright i see. Idk how many textures of T6 are BC5, but there seem to be some, so supporting that format from DDS seems like a good idea. Since there can't be any BC4 textures though idk if supporting it makes much sense.
I'm fairly certain every single normal map is required to be BC5. When trying with BC1 & BC3 normal maps are wrong.
Alright i see. Idk how many textures of T6 are BC5, but there seem to be some, so supporting that format from DDS seems like a good idea. Since there can't be any BC4 textures though idk if supporting it makes much sense.
I'm fairly certain every single normal map is required to be BC5. When trying with BC1 & BC3 normal maps are wrong.
if BC5 is what T6 is using for normal maps, it should definitely be supported, so I will look into it
So I tested what OAT does for T6 normal textures because I was wondering how it comes to be that OAT can dump those textures but not convert it since I thought I tested that.
Since it has been a bit I didn't not remember exactly but it seems like I did based my implementation on the Microsoft documentation of the DDS field: https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-pixelformat
Four-character codes for specifying compressed or custom formats. Possible values include: DXT1, DXT2, DXT3, DXT4, or DXT5. A FourCC of DX10 indicates the prescense of the DDS_HEADER_DXT10 extended header, and the dxgiFormat member of that structure indicates the true format.
So dumping of BC5 files happens by using a DXT10 extended header that contains the DXGI_FORMAT value. So OAT can read BC5 files, it just needs an extended header. I did not know there are additional fourCC conventions for additional formats that are not listed here, but after searching for a bit I was able to find a "Programming guide for DDS" which actually lists more fourCC values that the field documentation (Unfortunately it is not linked in the field reference...)
For your named ATI1 values i could find this: https://github.com/Microsoft/DirectXTK/wiki/DDSTextureLoader#remarks
idk which sources you have for the possible fourCC values.
I can't find anything for A2XY though?
So to follow the robustness principle I'll implement the additional fourCC values for sure. But maybe it's a good information for you as well that there is this DXT10 header extension that does cover this usecase for >=DXT10 (which T6 is) 😛
(idk how common these fourCC values are compared to the header extension though)