浏览代码

Add support for loading more DDS formats

BlueCube3310 2 年之前
父节点
当前提交
c278cc3946
共有 1 个文件被更改,包括 204 次插入2 次删除
  1. 204 2
      modules/dds/texture_loader_dds.cpp

+ 204 - 2
modules/dds/texture_loader_dds.cpp

@@ -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,
@@ -66,6 +98,16 @@ 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,
@@ -73,6 +115,8 @@ enum DDSFormat {
 	DDS_BGR5A1,
 	DDS_BGR565,
 	DDS_BGR10A2,
+	DDS_RGB10A2,
+	DDS_BGRA4,
 	DDS_LUMINANCE,
 	DDS_LUMINANCE_ALPHA,
 	DDS_MAX
@@ -92,6 +136,16 @@ 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 },
@@ -99,10 +153,84 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = {
 	{ "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;
@@ -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 + "'.");
@@ -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 {
@@ -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;
 		}
 
@@ -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.