Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support loading more DDS formats #81220

Merged
merged 1 commit into from
Dec 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 204 additions & 2 deletions modules/dds/texture_loader_dds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,39 @@ enum DDSFourCC {
DDFCC_BC4U = PF_FOURCC("BC4U"),
DDFCC_ATI2 = PF_FOURCC("ATI2"),
DDFCC_BC5U = PF_FOURCC("BC5U"),
DDFCC_A2XY = PF_FOURCC("A2XY")
DDFCC_A2XY = PF_FOURCC("A2XY"),
DDFCC_DX10 = PF_FOURCC("DX10"),
DDFCC_R16F = 111,
DDFCC_RG16F = 112,
DDFCC_RGBA16F = 113,
DDFCC_R32F = 114,
DDFCC_RG32F = 115,
DDFCC_RGBA32F = 116
};

// Reference: https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format
enum DXGIFormat {
DXGI_R32G32B32A32_FLOAT = 2,
DXGI_R16G16B16A16_FLOAT = 10,
DXGI_R32G32_FLOAT = 16,
DXGI_R10G10B10A2_UNORM = 24,
DXGI_R8G8B8A8_UNORM = 28,
DXGI_R16G16_FLOAT = 34,
DXGI_R32_FLOAT = 41,
DXGI_R16_FLOAT = 54,
DXGI_R9G9B9E5 = 67,
DXGI_BC1_UNORM = 71,
DXGI_BC2_UNORM = 74,
DXGI_BC3_UNORM = 77,
DXGI_BC4_UNORM = 80,
DXGI_BC5_UNORM = 83,
DXGI_B5G6R5_UNORM = 85,
DXGI_B5G5R5A1_UNORM = 86,
DXGI_B8G8R8A8_UNORM = 87,
DXGI_BC6H_UF16 = 95,
DXGI_BC6H_SF16 = 96,
DXGI_BC7_UNORM = 98,
DXGI_B4G4R4A4_UNORM = 115
};

// The legacy bitmasked format names here represent the actual data layout in the files,
Expand All @@ -66,13 +98,25 @@ enum DDSFormat {
DDS_DXT5,
DDS_ATI1,
DDS_ATI2,
DDS_BC6U,
DDS_BC6S,
DDS_BC7U,
DDS_R16F,
DDS_RG16F,
DDS_RGBA16F,
DDS_R32F,
DDS_RG32F,
DDS_RGBA32F,
DDS_RGB9E5,
DDS_BGRA8,
DDS_BGR8,
DDS_RGBA8,
DDS_RGB8,
DDS_BGR5A1,
DDS_BGR565,
DDS_BGR10A2,
DDS_RGB10A2,
DDS_BGRA4,
DDS_LUMINANCE,
DDS_LUMINANCE_ALPHA,
DDS_MAX
Expand All @@ -92,17 +136,101 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = {
{ "DXT5/BC3", true, 4, 16, Image::FORMAT_DXT5 },
{ "ATI1/BC4", true, 4, 8, Image::FORMAT_RGTC_R },
{ "ATI2/A2XY/BC5", true, 4, 16, Image::FORMAT_RGTC_RG },
{ "BC6U", true, 4, 16, Image::FORMAT_BPTC_RGBFU },
{ "BC6S", true, 4, 16, Image::FORMAT_BPTC_RGBF },
{ "BC7U", true, 4, 16, Image::FORMAT_BPTC_RGBA },
{ "R16F", false, 1, 2, Image::FORMAT_RH },
{ "RG16F", false, 1, 4, Image::FORMAT_RGH },
{ "RGBA16F", false, 1, 8, Image::FORMAT_RGBAH },
{ "R32F", false, 1, 4, Image::FORMAT_RF },
{ "RG32F", false, 1, 8, Image::FORMAT_RGF },
{ "RGBA32F", false, 1, 16, Image::FORMAT_RGBAF },
{ "RGB9E5", false, 1, 4, Image::FORMAT_RGBE9995 },
{ "BGRA8", false, 1, 4, Image::FORMAT_RGBA8 },
{ "BGR8", false, 1, 3, Image::FORMAT_RGB8 },
{ "RGBA8", false, 1, 4, Image::FORMAT_RGBA8 },
{ "RGB8", false, 1, 3, Image::FORMAT_RGB8 },
{ "BGR5A1", false, 1, 2, Image::FORMAT_RGBA8 },
{ "BGR565", false, 1, 2, Image::FORMAT_RGB8 },
{ "BGR10A2", false, 1, 4, Image::FORMAT_RGBA8 },
{ "RGB10A2", false, 1, 4, Image::FORMAT_RGBA8 },
{ "BGRA4", false, 1, 2, Image::FORMAT_RGBA8 },
{ "GRAYSCALE", false, 1, 1, Image::FORMAT_L8 },
{ "GRAYSCALE_ALPHA", false, 1, 2, Image::FORMAT_LA8 }
};

static DDSFormat dxgi_to_dds_format(uint32_t p_dxgi_format) {
switch (p_dxgi_format) {
case DXGI_R32G32B32A32_FLOAT: {
return DDS_RGBA32F;
}
case DXGI_R16G16B16A16_FLOAT: {
return DDS_RGBA16F;
}
case DXGI_R32G32_FLOAT: {
return DDS_RG32F;
}
case DXGI_R10G10B10A2_UNORM: {
return DDS_RGB10A2;
}
case DXGI_R8G8B8A8_UNORM: {
return DDS_RGBA8;
}
case DXGI_R16G16_FLOAT: {
return DDS_RG16F;
}
case DXGI_R32_FLOAT: {
return DDS_R32F;
}
case DXGI_R16_FLOAT: {
return DDS_R16F;
}
case DXGI_R9G9B9E5: {
return DDS_RGB9E5;
}
case DXGI_BC1_UNORM: {
return DDS_DXT1;
}
case DXGI_BC2_UNORM: {
return DDS_DXT3;
}
case DXGI_BC3_UNORM: {
return DDS_DXT5;
}
case DXGI_BC4_UNORM: {
return DDS_ATI1;
}
case DXGI_BC5_UNORM: {
return DDS_ATI2;
}
case DXGI_B5G6R5_UNORM: {
return DDS_BGR565;
}
case DXGI_B5G5R5A1_UNORM: {
return DDS_BGR5A1;
}
case DXGI_B8G8R8A8_UNORM: {
return DDS_BGRA8;
}
case DXGI_BC6H_UF16: {
return DDS_BC6U;
}
case DXGI_BC6H_SF16: {
return DDS_BC6S;
}
case DXGI_BC7_UNORM: {
return DDS_BC7U;
}
case DXGI_B4G4R4A4_UNORM: {
return DDS_BGRA4;
}

default: {
return DDS_MAX;
}
}
}

Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
Expand Down Expand Up @@ -186,6 +314,33 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
case DDFCC_A2XY: {
dds_format = DDS_ATI2;
} break;
case DDFCC_R16F: {
dds_format = DDS_R16F;
} break;
case DDFCC_RG16F: {
dds_format = DDS_RG16F;
} break;
case DDFCC_RGBA16F: {
dds_format = DDS_RGBA16F;
} break;
case DDFCC_R32F: {
dds_format = DDS_R32F;
} break;
case DDFCC_RG32F: {
dds_format = DDS_RG32F;
} break;
case DDFCC_RGBA32F: {
dds_format = DDS_RGBA32F;
} break;
case DDFCC_DX10: {
uint32_t dxgi_format = f->get_32();
/* uint32_t dimension = */ f->get_32();
/* uint32_t misc_flags_1 = */ f->get_32();
/* uint32_t array_size = */ f->get_32();
/* uint32_t misc_flags_2 = */ f->get_32();

dds_format = dxgi_to_dds_format(dxgi_format);
} break;

default: {
ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported FourCC in DDS '" + p_path + "'.");
Expand All @@ -204,6 +359,10 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
dds_format = DDS_BGR5A1;
} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff00000 && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff && format_alpha_mask == 0xc0000000) {
dds_format = DDS_BGR10A2;
} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff00000 && format_alpha_mask == 0xc0000000) {
dds_format = DDS_RGB10A2;
} else if (format_rgb_bits == 16 && format_red_mask == 0xf00 && format_green_mask == 0xf0 && format_blue_mask == 0xf && format_alpha_mask == 0xf000) {
dds_format = DDS_BGRA4;
}

} else {
Expand Down Expand Up @@ -273,7 +432,7 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
// Calculate the space these formats will take up after decoding.
if (dds_format == DDS_BGR565) {
size = size * 3 / 2;
} else if (dds_format == DDS_BGR5A1) {
} else if (dds_format == DDS_BGR5A1 || dds_format == DDS_BGRA4) {
size = size * 2;
}

Expand Down Expand Up @@ -320,6 +479,49 @@ Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_orig
wb[dst_ofs + 2] = b << 3;
}

} break;
case DDS_BGRA4: {
// To RGBA8.
int colcount = size / 4;

for (int i = colcount - 1; i >= 0; i--) {
int src_ofs = i * 2;
int dst_ofs = i * 4;

uint8_t b = wb[src_ofs] & 0x0F;
uint8_t g = wb[src_ofs] & 0xF0;
uint8_t r = wb[src_ofs + 1] & 0x0F;
uint8_t a = wb[src_ofs + 1] & 0xF0;

wb[dst_ofs] = (r << 4) | r;
wb[dst_ofs + 1] = g | (g >> 4);
wb[dst_ofs + 2] = (b << 4) | b;
wb[dst_ofs + 3] = a | (a >> 4);
}

} break;
case DDS_RGB10A2: {
// To RGBA8.
int colcount = size / 4;

for (int i = 0; i < colcount; i++) {
int ofs = i * 4;

uint32_t w32 = uint32_t(wb[ofs + 0]) | (uint32_t(wb[ofs + 1]) << 8) | (uint32_t(wb[ofs + 2]) << 16) | (uint32_t(wb[ofs + 3]) << 24);

// This method follows the 'standard' way of decoding 10-bit dds files,
// which means the ones created with DirectXTex will be loaded incorrectly.
uint8_t a = (w32 & 0xc0000000) >> 24;
uint8_t r = (w32 & 0x3ff) >> 2;
uint8_t g = (w32 & 0xffc00) >> 12;
uint8_t b = (w32 & 0x3ff00000) >> 22;

wb[ofs + 0] = r;
wb[ofs + 1] = g;
wb[ofs + 2] = b;
wb[ofs + 3] = a == 0xc0 ? 255 : a; // 0xc0 should be opaque.
}

} break;
case DDS_BGR10A2: {
// To RGBA8.
Expand Down
Loading