| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2021, the SerenityOS developers. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <AK/Debug.h>
 | 
					
						
							|  |  |  | #include <AK/Endian.h>
 | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  | #include <AK/Error.h>
 | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  | #include <AK/MemoryStream.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | #include <AK/StringBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  | #include <AK/Try.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | #include <AK/Vector.h>
 | 
					
						
							| 
									
										
										
										
											2023-03-21 14:58:06 -04:00
										 |  |  | #include <LibGfx/ImageFormats/DDSLoader.h>
 | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <math.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <sys/mman.h>
 | 
					
						
							|  |  |  | #include <sys/stat.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Gfx { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct DDSLoadingContext { | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |     DDSLoadingContext(FixedMemoryStream stream) | 
					
						
							|  |  |  |         : stream(move(stream)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     enum State { | 
					
						
							|  |  |  |         NotDecoded = 0, | 
					
						
							|  |  |  |         Error, | 
					
						
							| 
									
										
										
										
											2023-07-11 11:53:02 -04:00
										 |  |  |         HeaderDecoded, | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         BitmapDecoded, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     State state { State::NotDecoded }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |     FixedMemoryStream stream; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     DDSHeader header; | 
					
						
							|  |  |  |     DDSHeaderDXT10 header10; | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |     DXGIFormat format; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     RefPtr<Gfx::Bitmap> bitmap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void dump_debug(); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static constexpr u32 create_four_cc(char c0, char c1, char c2, char c3) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return c0 | c1 << 8 | c2 << 16 | c3 << 24; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u64 get_width(DDSHeader header, size_t mipmap_level) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (mipmap_level >= header.mip_map_count) { | 
					
						
							|  |  |  |         return header.width; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return header.width >> mipmap_level; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u64 get_height(DDSHeader header, size_t mipmap_level) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (mipmap_level >= header.mip_map_count) { | 
					
						
							|  |  |  |         return header.height; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return header.height >> mipmap_level; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static constexpr bool has_bitmask(DDSPixelFormat format, u32 r, u32 g, u32 b, u32 a) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return format.r_bit_mask == r && format.g_bit_mask == g && format.b_bit_mask == b && format.a_bit_mask == a; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static DXGIFormat get_format(DDSPixelFormat format) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if ((format.flags & PixelFormatFlags::DDPF_RGB) == PixelFormatFlags::DDPF_RGB) { | 
					
						
							|  |  |  |         switch (format.rgb_bit_count) { | 
					
						
							|  |  |  |         case 32: { | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R8G8B8A8_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_B8G8R8A8_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_B8G8R8X8_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R10G10B10A2_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R16G16_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R32_FLOAT; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         case 24: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 16: { | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x7C00, 0x03E0, 0x001F, 0x8000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_B5G5R5A1_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0xF800, 0x07E0, 0x001F, 0x0000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_B5G6R5_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0xF800, 0x07E0, 0x001F, 0x0000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_B5G6R5_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x0F00, 0x00F0, 0x000F, 0xF000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_B4G4R4A4_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R8G8_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0xFFFF, 0x0000, 0x0000, 0x0000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R16_UNORM; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         case 8: { | 
					
						
							|  |  |  |             if (has_bitmask(format, 0xFF, 0x00, 0x00, 0x00)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R8_UNORM; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if ((format.flags & PixelFormatFlags::DDPF_LUMINANCE) == PixelFormatFlags::DDPF_LUMINANCE) { | 
					
						
							|  |  |  |         switch (format.rgb_bit_count) { | 
					
						
							|  |  |  |         case 16: { | 
					
						
							|  |  |  |             if (has_bitmask(format, 0xFFFF, 0x0000, 0x0000, 0x0000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R16_UNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R8G8_UNORM; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         case 8: { | 
					
						
							|  |  |  |             if (has_bitmask(format, 0xFF, 0x00, 0x00, 0x00)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R8_UNORM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Some writers mistakenly write this as 8 bpp.
 | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R8G8_UNORM; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if ((format.flags & PixelFormatFlags::DDPF_ALPHA) == PixelFormatFlags::DDPF_ALPHA) { | 
					
						
							|  |  |  |         if (format.rgb_bit_count == 8) | 
					
						
							|  |  |  |             return DXGI_FORMAT_A8_UNORM; | 
					
						
							|  |  |  |     } else if ((format.flags & PixelFormatFlags::DDPF_BUMPDUDV) == PixelFormatFlags::DDPF_BUMPDUDV) { | 
					
						
							|  |  |  |         switch (format.rgb_bit_count) { | 
					
						
							|  |  |  |         case 32: { | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R8G8B8A8_SNORM; | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R16G16_SNORM; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         case 16: { | 
					
						
							|  |  |  |             if (has_bitmask(format, 0x00FF, 0xFF00, 0x0000, 0x0000)) | 
					
						
							|  |  |  |                 return DXGI_FORMAT_R8G8_SNORM; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if ((format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC) { | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('D', 'X', 'T', '1')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC1_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('D', 'X', 'T', '2')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC2_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('D', 'X', 'T', '3')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC2_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('D', 'X', 'T', '4')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC3_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('D', 'X', 'T', '5')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC3_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('A', 'T', 'I', '1')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC4_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('B', 'C', '4', 'U')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC4_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('B', 'C', '4', 'S')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC4_SNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('A', 'T', 'I', '2')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC5_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('B', 'C', '5', 'U')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC5_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('B', 'C', '5', 'S')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_BC5_SNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('R', 'G', 'B', 'G')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_R8G8_B8G8_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('G', 'R', 'G', 'B')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_G8R8_G8B8_UNORM; | 
					
						
							|  |  |  |         if (format.four_cc == create_four_cc('Y', 'U', 'Y', '2')) | 
					
						
							|  |  |  |             return DXGI_FORMAT_YUY2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (format.four_cc) { | 
					
						
							|  |  |  |         case 36: | 
					
						
							|  |  |  |             return DXGI_FORMAT_R16G16B16A16_UNORM; | 
					
						
							|  |  |  |         case 110: | 
					
						
							|  |  |  |             return DXGI_FORMAT_R16G16B16A16_SNORM; | 
					
						
							|  |  |  |         case 111: | 
					
						
							|  |  |  |             return DXGI_FORMAT_R16_FLOAT; | 
					
						
							|  |  |  |         case 112: | 
					
						
							|  |  |  |             return DXGI_FORMAT_R16G16_FLOAT; | 
					
						
							|  |  |  |         case 113: | 
					
						
							|  |  |  |             return DXGI_FORMAT_R16G16B16A16_FLOAT; | 
					
						
							|  |  |  |         case 114: | 
					
						
							|  |  |  |             return DXGI_FORMAT_R32_FLOAT; | 
					
						
							|  |  |  |         case 115: | 
					
						
							|  |  |  |             return DXGI_FORMAT_R32G32_FLOAT; | 
					
						
							|  |  |  |         case 116: | 
					
						
							|  |  |  |             return DXGI_FORMAT_R32G32B32A32_FLOAT; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return DXGI_FORMAT_UNKNOWN; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-10 01:00:18 +01:00
										 |  |  | static ErrorOr<void> decode_dx5_alpha_block(Stream& stream, DDSLoadingContext& context, u64 bitmap_x, u64 bitmap_y) | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  |     auto color0 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto color1 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  |     auto code0 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto code1 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto code2 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto code3 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto code4 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto code5 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     u32 codes[6] = { 0 }; | 
					
						
							|  |  |  |     codes[0] = code0 + 256 * (code1 + 256); | 
					
						
							|  |  |  |     codes[1] = code1 + 256 * (code2 + 256); | 
					
						
							|  |  |  |     codes[2] = code2 + 256 * (code3 + 256); | 
					
						
							|  |  |  |     codes[3] = code3 + 256 * (code4 + 256); | 
					
						
							|  |  |  |     codes[4] = code4 + 256 * code5; | 
					
						
							|  |  |  |     codes[5] = code5; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     u32 color[8] = { 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (color0 > 128) { | 
					
						
							|  |  |  |         color[0] = color0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (color1 > 128) { | 
					
						
							|  |  |  |         color[1] = color1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (color0 > color1) { | 
					
						
							|  |  |  |         color[2] = (6 * color[0] + 1 * color[1]) / 7; | 
					
						
							|  |  |  |         color[3] = (5 * color[0] + 2 * color[1]) / 7; | 
					
						
							|  |  |  |         color[4] = (4 * color[0] + 3 * color[1]) / 7; | 
					
						
							|  |  |  |         color[5] = (3 * color[0] + 4 * color[1]) / 7; | 
					
						
							|  |  |  |         color[6] = (2 * color[0] + 5 * color[1]) / 7; | 
					
						
							|  |  |  |         color[7] = (1 * color[0] + 6 * color[1]) / 7; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         color[2] = (4 * color[0] + 1 * color[1]) / 5; | 
					
						
							|  |  |  |         color[3] = (3 * color[0] + 2 * color[1]) / 5; | 
					
						
							|  |  |  |         color[4] = (2 * color[0] + 3 * color[1]) / 5; | 
					
						
							|  |  |  |         color[5] = (1 * color[0] + 4 * color[1]) / 5; | 
					
						
							|  |  |  |         color[6] = 0; | 
					
						
							|  |  |  |         color[7] = 255; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-06 18:51:57 +01:00
										 |  |  |     for (size_t y = 0; y < 4 && bitmap_y + y < static_cast<u64>(context.bitmap->height()); y++) { | 
					
						
							|  |  |  |         for (size_t x = 0; x < 4 && bitmap_x + x < static_cast<u64>(context.bitmap->width()); x++) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |             u8 index = 3 * (4 * y + x); | 
					
						
							|  |  |  |             u8 bit_location = floor(index / 8.0); | 
					
						
							|  |  |  |             u8 adjusted_index = index - (bit_location * 8); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             u8 code = (codes[bit_location] >> adjusted_index) & 7; | 
					
						
							|  |  |  |             u8 alpha = color[code]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Color color = Color(0, 0, 0, alpha); | 
					
						
							|  |  |  |             context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-10 01:00:18 +01:00
										 |  |  | static ErrorOr<void> decode_dx3_alpha_block(Stream& stream, DDSLoadingContext& context, u64 bitmap_x, u64 bitmap_y) | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  |     auto a0 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto a1 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto a2 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto a3 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto a4 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto a5 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto a6 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto a7 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     u64 alpha_0 = a0 + 256u * (a1 + 256u * (a2 + 256u * (a3 + 256u))); | 
					
						
							|  |  |  |     u64 alpha_1 = a4 + 256u * (a5 + 256u * (a6 + 256u * a7)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-06 18:51:57 +01:00
										 |  |  |     for (size_t y = 0; y < 4 && bitmap_y + y < static_cast<u64>(context.bitmap->height()); y++) { | 
					
						
							|  |  |  |         for (size_t x = 0; x < 4 && bitmap_x + x < static_cast<u64>(context.bitmap->width()); x++) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |             u8 code = 4 * (4 * y + x); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (code >= 32) { | 
					
						
							|  |  |  |                 code = code - 32; | 
					
						
							|  |  |  |                 u8 alpha = ((alpha_1 >> code) & 0x0F) * 17; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 Color color = Color(0, 0, 0, alpha); | 
					
						
							|  |  |  |                 context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 u8 alpha = ((alpha_0 >> code) & 0x0F) * 17; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 Color color = Color(0, 0, 0, alpha); | 
					
						
							|  |  |  |                 context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void unpack_rbg_565(u32 rgb, u8* output) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     u8 r = (rgb >> 11) & 0x1F; | 
					
						
							|  |  |  |     u8 g = (rgb >> 5) & 0x3F; | 
					
						
							|  |  |  |     u8 b = rgb & 0x1F; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     output[0] = (r << 3) | (r >> 2); | 
					
						
							|  |  |  |     output[1] = (g << 2) | (g >> 4); | 
					
						
							|  |  |  |     output[2] = (b << 3) | (b >> 2); | 
					
						
							|  |  |  |     output[3] = 255; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-10 01:00:18 +01:00
										 |  |  | static ErrorOr<void> decode_color_block(Stream& stream, DDSLoadingContext& context, bool dxt1, u64 bitmap_x, u64 bitmap_y) | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  |     auto c0_low = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto c0_high = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto c1_low = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto c1_high = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto codes_0 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto codes_1 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto codes_2 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							|  |  |  |     auto codes_3 = TRY(stream.read_value<LittleEndian<u8>>()); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     u64 code = codes_0 + 256 * (codes_1 + 256 * (codes_2 + 256 * codes_3)); | 
					
						
							|  |  |  |     u32 color_0 = c0_low + (c0_high * 256); | 
					
						
							|  |  |  |     u32 color_1 = c1_low + (c1_high * 256); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     u8 rgba[4][4]; | 
					
						
							|  |  |  |     unpack_rbg_565(color_0, rgba[0]); | 
					
						
							|  |  |  |     unpack_rbg_565(color_1, rgba[1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (color_0 > color_1) { | 
					
						
							|  |  |  |         for (size_t i = 0; i < 3; i++) { | 
					
						
							|  |  |  |             rgba[2][i] = (2 * rgba[0][i] + rgba[1][i]) / 3; | 
					
						
							|  |  |  |             rgba[3][i] = (rgba[0][i] + 2 * rgba[1][i]) / 3; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rgba[2][3] = 255; | 
					
						
							|  |  |  |         rgba[3][3] = 255; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         for (size_t i = 0; i < 3; i++) { | 
					
						
							|  |  |  |             rgba[2][i] = (rgba[0][i] + rgba[1][i]) / 2; | 
					
						
							|  |  |  |             rgba[3][i] = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rgba[2][3] = 255; | 
					
						
							|  |  |  |         rgba[3][3] = dxt1 ? 0 : 255; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size_t i = 0; | 
					
						
							| 
									
										
										
										
											2023-10-06 18:51:57 +01:00
										 |  |  |     for (size_t y = 0; y < 4 && bitmap_y + y < static_cast<u64>(context.bitmap->height()); y++) { | 
					
						
							|  |  |  |         for (size_t x = 0; x < 4 && bitmap_x + x < static_cast<u64>(context.bitmap->width()); x++) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |             u8 code_byte = (code >> (i * 2)) & 3; | 
					
						
							|  |  |  |             u8 r = rgba[code_byte][0]; | 
					
						
							|  |  |  |             u8 g = rgba[code_byte][1]; | 
					
						
							|  |  |  |             u8 b = rgba[code_byte][2]; | 
					
						
							|  |  |  |             u8 a = dxt1 ? rgba[code_byte][3] : context.bitmap->get_pixel(bitmap_x + x, bitmap_y + y).alpha(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Color color = Color(r, g, b, a); | 
					
						
							|  |  |  |             context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color); | 
					
						
							|  |  |  |             i++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  | static ErrorOr<void> decode_dxt(Stream& stream, DDSLoadingContext& context, u64 width, u64 y) | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |     if (context.format == DXGI_FORMAT_BC1_UNORM) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         for (size_t x = 0; x < width; x += 4) { | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  |             TRY(decode_color_block(stream, context, true, x, y)); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |     if (context.format == DXGI_FORMAT_BC2_UNORM) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         for (size_t x = 0; x < width; x += 4) { | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  |             TRY(decode_dx3_alpha_block(stream, context, x, y)); | 
					
						
							|  |  |  |             TRY(decode_color_block(stream, context, false, x, y)); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |     if (context.format == DXGI_FORMAT_BC3_UNORM) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         for (size_t x = 0; x < width; x += 4) { | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  |             TRY(decode_dx5_alpha_block(stream, context, x, y)); | 
					
						
							|  |  |  |             TRY(decode_color_block(stream, context, false, x, y)); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  | static ErrorOr<void> decode_bitmap(Stream& stream, DDSLoadingContext& context, u64 width, u64 height) | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:56:00 -04:00
										 |  |  |     static constexpr Array dxt_formats = { DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC3_UNORM }; | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |     if (dxt_formats.contains_slow(context.format)) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         for (u64 y = 0; y < height; y += 4) { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |             TRY(decode_dxt(stream, context, width, y)); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // FIXME: Support more encodings (ATI, YUV, RAW, etc...).
 | 
					
						
							| 
									
										
										
										
											2023-01-30 13:22:50 +01:00
										 |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:44:58 -04:00
										 |  |  | static ErrorOr<void> decode_header(DDSLoadingContext& context) | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     // All valid DDS files are at least 128 bytes long.
 | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |     if (TRY(context.stream.size()) < 128) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         dbgln_if(DDS_DEBUG, "File is too short for DDS"); | 
					
						
							|  |  |  |         context.state = DDSLoadingContext::State::Error; | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  |         return Error::from_string_literal("File is too short for DDS"); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |     auto magic = TRY(context.stream.read_value<u32>()); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (magic != create_four_cc('D', 'D', 'S', ' ')) { | 
					
						
							|  |  |  |         dbgln_if(DDS_DEBUG, "Missing magic number"); | 
					
						
							|  |  |  |         context.state = DDSLoadingContext::State::Error; | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  |         return Error::from_string_literal("Missing magic number"); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |     context.header = TRY(context.stream.read_value<DDSHeader>()); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (context.header.size != 124) { | 
					
						
							|  |  |  |         dbgln_if(DDS_DEBUG, "Header size is malformed"); | 
					
						
							|  |  |  |         context.state = DDSLoadingContext::State::Error; | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  |         return Error::from_string_literal("Header size is malformed"); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (context.header.pixel_format.size != 32) { | 
					
						
							|  |  |  |         dbgln_if(DDS_DEBUG, "Pixel format size is malformed"); | 
					
						
							|  |  |  |         context.state = DDSLoadingContext::State::Error; | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  |         return Error::from_string_literal("Pixel format size is malformed"); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((context.header.pixel_format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC) { | 
					
						
							|  |  |  |         if (context.header.pixel_format.four_cc == create_four_cc('D', 'X', '1', '0')) { | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |             if (TRY(context.stream.size()) < 148) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |                 dbgln_if(DDS_DEBUG, "DX10 header is too short"); | 
					
						
							|  |  |  |                 context.state = DDSLoadingContext::State::Error; | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  |                 return Error::from_string_literal("DX10 header is too short"); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |             context.header10 = TRY(context.stream.read_value<DDSHeaderDXT10>()); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if constexpr (DDS_DEBUG) { | 
					
						
							|  |  |  |         context.dump_debug(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |     context.format = get_format(context.header.pixel_format); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:56:00 -04:00
										 |  |  |     static constexpr Array supported_formats = { DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC3_UNORM }; | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |     if (!supported_formats.contains_slow(context.format)) { | 
					
						
							|  |  |  |         dbgln_if(DDS_DEBUG, "Format of type {} is not supported at the moment", to_underlying(context.format)); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         context.state = DDSLoadingContext::State::Error; | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  |         return Error::from_string_literal("Format type is not supported at the moment"); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:53:02 -04:00
										 |  |  |     context.state = DDSLoadingContext::HeaderDecoded; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:44:58 -04:00
										 |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ErrorOr<void> decode_dds(DDSLoadingContext& context) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:53:02 -04:00
										 |  |  |     VERIFY(context.state == DDSLoadingContext::HeaderDecoded); | 
					
						
							| 
									
										
										
										
											2023-07-11 11:44:58 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-08 08:34:12 -04:00
										 |  |  |     // We support parsing mipmaps, but we only care about the largest one :^) (At least for now)
 | 
					
						
							|  |  |  |     if (size_t mipmap_level = 0; mipmap_level < max(context.header.mip_map_count, 1u)) { | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |         u64 width = get_width(context.header, mipmap_level); | 
					
						
							|  |  |  |         u64 height = get_height(context.header, mipmap_level); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 20:06:05 +01:00
										 |  |  |         context.bitmap = TRY(Bitmap::create(BitmapFormat::BGRA8888, { width, height })); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-11 11:39:23 -04:00
										 |  |  |         TRY(decode_bitmap(context.stream, context, width, height)); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     context.state = DDSLoadingContext::State::BitmapDecoded; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  |     return {}; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void DDSLoadingContext::dump_debug() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     StringBuilder builder; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\nDDS:\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     builder.appendff("\tHeader Size: {}\n", header.size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\tFlags:"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.flags & DDSFlags::DDSD_CAPS) == DDSFlags::DDSD_CAPS) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSD_CAPS"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.flags & DDSFlags::DDSD_HEIGHT) == DDSFlags::DDSD_HEIGHT) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSD_HEIGHT"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.flags & DDSFlags::DDSD_WIDTH) == DDSFlags::DDSD_WIDTH) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSD_WIDTH"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.flags & DDSFlags::DDSD_PITCH) == DDSFlags::DDSD_PITCH) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSD_PITCH"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.flags & DDSFlags::DDSD_PIXELFORMAT) == DDSFlags::DDSD_PIXELFORMAT) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSD_PIXELFORMAT"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.flags & DDSFlags::DDSD_MIPMAPCOUNT) == DDSFlags::DDSD_MIPMAPCOUNT) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSD_MIPMAPCOUNT"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.flags & DDSFlags::DDSD_LINEARSIZE) == DDSFlags::DDSD_LINEARSIZE) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSD_LINEARSIZE"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.flags & DDSFlags::DDSD_DEPTH) == DDSFlags::DDSD_DEPTH) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSD_DEPTH"sv); | 
					
						
							|  |  |  |     builder.append("\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     builder.appendff("\tHeight: {}\n", header.height); | 
					
						
							|  |  |  |     builder.appendff("\tWidth: {}\n", header.width); | 
					
						
							|  |  |  |     builder.appendff("\tPitch: {}\n", header.pitch); | 
					
						
							|  |  |  |     builder.appendff("\tDepth: {}\n", header.depth); | 
					
						
							|  |  |  |     builder.appendff("\tMipmap Count: {}\n", header.mip_map_count); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\tCaps:"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps1 & Caps1Flags::DDSCAPS_COMPLEX) == Caps1Flags::DDSCAPS_COMPLEX) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS_COMPLEX"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps1 & Caps1Flags::DDSCAPS_MIPMAP) == Caps1Flags::DDSCAPS_MIPMAP) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS_MIPMAP"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps1 & Caps1Flags::DDSCAPS_TEXTURE) == Caps1Flags::DDSCAPS_TEXTURE) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS_TEXTURE"sv); | 
					
						
							|  |  |  |     builder.append("\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\tCaps2:"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP) == Caps2Flags::DDSCAPS2_CUBEMAP) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS2_CUBEMAP"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEX) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEX) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS2_CUBEMAP_POSITIVEX"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEX) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEX) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEX"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEY) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEY) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS2_CUBEMAP_POSITIVEY"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEY) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEY) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEY"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEZ) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEZ) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS2_CUBEMAP_POSITIVEZ"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEZ) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEZ) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEZ"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.caps2 & Caps2Flags::DDSCAPS2_VOLUME) == Caps2Flags::DDSCAPS2_VOLUME) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDSCAPS2_VOLUME"sv); | 
					
						
							|  |  |  |     builder.append("\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("Pixel Format:\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     builder.appendff("\tStruct Size: {}\n", header.pixel_format.size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\tFlags:"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_ALPHAPIXELS) == PixelFormatFlags::DDPF_ALPHAPIXELS) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_ALPHAPIXELS"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_ALPHA) == PixelFormatFlags::DDPF_ALPHA) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_ALPHA"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_FOURCC"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_PALETTEINDEXED8) == PixelFormatFlags::DDPF_PALETTEINDEXED8) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_PALETTEINDEXED8"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_RGB) == PixelFormatFlags::DDPF_RGB) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_RGB"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_YUV) == PixelFormatFlags::DDPF_YUV) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_YUV"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_LUMINANCE) == PixelFormatFlags::DDPF_LUMINANCE) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_LUMINANCE"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_BUMPDUDV) == PixelFormatFlags::DDPF_BUMPDUDV) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_BUMPDUDV"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header.pixel_format.flags & PixelFormatFlags::DDPF_NORMAL) == PixelFormatFlags::DDPF_NORMAL) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDPF_NORMAL"sv); | 
					
						
							|  |  |  |     builder.append("\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\tFour CC: "sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 0)) & 0xFF); | 
					
						
							|  |  |  |     builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 1)) & 0xFF); | 
					
						
							|  |  |  |     builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 2)) & 0xFF); | 
					
						
							|  |  |  |     builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 3)) & 0xFF); | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     builder.appendff("\tRGB Bit Count: {}\n", header.pixel_format.rgb_bit_count); | 
					
						
							|  |  |  |     builder.appendff("\tR Bit Mask: {}\n", header.pixel_format.r_bit_mask); | 
					
						
							|  |  |  |     builder.appendff("\tG Bit Mask: {}\n", header.pixel_format.g_bit_mask); | 
					
						
							|  |  |  |     builder.appendff("\tB Bit Mask: {}\n", header.pixel_format.b_bit_mask); | 
					
						
							|  |  |  |     builder.appendff("\tA Bit Mask: {}\n", header.pixel_format.a_bit_mask); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("DDS10:\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     builder.appendff("\tFormat: {}\n", static_cast<u32>(header10.format)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\tResource Dimension:"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_UNKNOWN) == ResourceDimensions::DDS_DIMENSION_UNKNOWN) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_DIMENSION_UNKNOWN"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_BUFFER) == ResourceDimensions::DDS_DIMENSION_BUFFER) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_DIMENSION_BUFFER"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE1D) == ResourceDimensions::DDS_DIMENSION_TEXTURE1D) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_DIMENSION_TEXTURE1D"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE2D) == ResourceDimensions::DDS_DIMENSION_TEXTURE2D) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_DIMENSION_TEXTURE2D"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE3D) == ResourceDimensions::DDS_DIMENSION_TEXTURE3D) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_DIMENSION_TEXTURE3D"sv); | 
					
						
							|  |  |  |     builder.append("\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     builder.appendff("\tArray Size: {}\n", header10.array_size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\tMisc Flags:"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.misc_flag & MiscFlags::DDS_RESOURCE_MISC_TEXTURECUBE) == MiscFlags::DDS_RESOURCE_MISC_TEXTURECUBE) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_RESOURCE_MISC_TEXTURECUBE"sv); | 
					
						
							|  |  |  |     builder.append("\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |     builder.append("\tMisc Flags 2:"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_UNKNOWN) == Misc2Flags::DDS_ALPHA_MODE_UNKNOWN) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_ALPHA_MODE_UNKNOWN"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_STRAIGHT) == Misc2Flags::DDS_ALPHA_MODE_STRAIGHT) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_ALPHA_MODE_STRAIGHT"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_PREMULTIPLIED) == Misc2Flags::DDS_ALPHA_MODE_PREMULTIPLIED) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_ALPHA_MODE_PREMULTIPLIED"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_OPAQUE) == Misc2Flags::DDS_ALPHA_MODE_OPAQUE) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_ALPHA_MODE_OPAQUE"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  |     if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_CUSTOM) == Misc2Flags::DDS_ALPHA_MODE_CUSTOM) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:32:29 +00:00
										 |  |  |         builder.append(" DDS_ALPHA_MODE_CUSTOM"sv); | 
					
						
							|  |  |  |     builder.append("\n"sv); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-06 01:12:49 +00:00
										 |  |  |     dbgln("{}", builder.to_deprecated_string()); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  | DDSImageDecoderPlugin::DDSImageDecoderPlugin(FixedMemoryStream stream) | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |     m_context = make<DDSLoadingContext>(move(stream)); | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 13:26:37 -06:00
										 |  |  | DDSImageDecoderPlugin::~DDSImageDecoderPlugin() = default; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | IntSize DDSImageDecoderPlugin::size() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-11 11:53:02 -04:00
										 |  |  |     return { m_context->header.width, m_context->header.height }; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-26 18:02:50 +00:00
										 |  |  | bool DDSImageDecoderPlugin::sniff(ReadonlyBytes data) | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     // The header is always at least 128 bytes, so if the file is smaller, it can't be a DDS.
 | 
					
						
							|  |  |  |     return data.size() > 128 | 
					
						
							|  |  |  |         && data.data()[0] == 0x44 | 
					
						
							|  |  |  |         && data.data()[1] == 0x44 | 
					
						
							|  |  |  |         && data.data()[2] == 0x53 | 
					
						
							|  |  |  |         && data.data()[3] == 0x20; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> DDSImageDecoderPlugin::create(ReadonlyBytes data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-06 23:06:39 -04:00
										 |  |  |     FixedMemoryStream stream { data }; | 
					
						
							| 
									
										
										
										
											2023-07-11 11:53:02 -04:00
										 |  |  |     auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) DDSImageDecoderPlugin(move(stream)))); | 
					
						
							|  |  |  |     TRY(decode_header(*plugin->m_context)); | 
					
						
							|  |  |  |     return plugin; | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-02 22:20:06 +01:00
										 |  |  | ErrorOr<ImageFrameDescriptor> DDSImageDecoderPlugin::frame(size_t index, Optional<IntSize>) | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-11-20 14:29:33 +01:00
										 |  |  |     if (index > 0) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:57:32 +00:00
										 |  |  |         return Error::from_string_literal("DDSImageDecoderPlugin: Invalid frame index"); | 
					
						
							| 
									
										
										
										
											2021-11-18 13:47:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_context->state == DDSLoadingContext::State::Error) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:57:32 +00:00
										 |  |  |         return Error::from_string_literal("DDSImageDecoderPlugin: Decoding failed"); | 
					
						
							| 
									
										
										
										
											2021-11-18 13:47:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_context->state < DDSLoadingContext::State::BitmapDecoded) { | 
					
						
							| 
									
										
										
										
											2022-12-22 08:00:25 +01:00
										 |  |  |         TRY(decode_dds(*m_context)); | 
					
						
							| 
									
										
										
										
											2021-11-18 13:47:29 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VERIFY(m_context->bitmap); | 
					
						
							| 
									
										
										
										
											2021-11-20 14:29:33 +01:00
										 |  |  |     return ImageFrameDescriptor { m_context->bitmap, 0 }; | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-07-27 01:29:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-26 07:23:59 -05:00
										 |  |  | ErrorOr<Optional<ReadonlyBytes>> DDSImageDecoderPlugin::icc_data() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return OptionalNone {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-15 17:02:40 +02:00
										 |  |  | } |