DDSLoader.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. /*
  2. * Copyright (c) 2021, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Debug.h>
  7. #include <AK/Endian.h>
  8. #include <AK/Error.h>
  9. #include <AK/MemoryStream.h>
  10. #include <AK/StringBuilder.h>
  11. #include <AK/Try.h>
  12. #include <AK/Vector.h>
  13. #include <LibGfx/ImageFormats/DDSLoader.h>
  14. #include <fcntl.h>
  15. #include <math.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <sys/mman.h>
  19. #include <sys/stat.h>
  20. #include <unistd.h>
  21. namespace Gfx {
  22. struct DDSLoadingContext {
  23. enum State {
  24. NotDecoded = 0,
  25. Error,
  26. BitmapDecoded,
  27. };
  28. State state { State::NotDecoded };
  29. u8 const* data { nullptr };
  30. size_t data_size { 0 };
  31. DDSHeader header;
  32. DDSHeaderDXT10 header10;
  33. RefPtr<Gfx::Bitmap> bitmap;
  34. void dump_debug();
  35. };
  36. static constexpr u32 create_four_cc(char c0, char c1, char c2, char c3)
  37. {
  38. return c0 | c1 << 8 | c2 << 16 | c3 << 24;
  39. }
  40. static u64 get_width(DDSHeader header, size_t mipmap_level)
  41. {
  42. if (mipmap_level >= header.mip_map_count) {
  43. return header.width;
  44. }
  45. return header.width >> mipmap_level;
  46. }
  47. static u64 get_height(DDSHeader header, size_t mipmap_level)
  48. {
  49. if (mipmap_level >= header.mip_map_count) {
  50. return header.height;
  51. }
  52. return header.height >> mipmap_level;
  53. }
  54. static constexpr bool has_bitmask(DDSPixelFormat format, u32 r, u32 g, u32 b, u32 a)
  55. {
  56. return format.r_bit_mask == r && format.g_bit_mask == g && format.b_bit_mask == b && format.a_bit_mask == a;
  57. }
  58. static DXGIFormat get_format(DDSPixelFormat format)
  59. {
  60. if ((format.flags & PixelFormatFlags::DDPF_RGB) == PixelFormatFlags::DDPF_RGB) {
  61. switch (format.rgb_bit_count) {
  62. case 32: {
  63. if (has_bitmask(format, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000))
  64. return DXGI_FORMAT_R8G8B8A8_UNORM;
  65. if (has_bitmask(format, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000))
  66. return DXGI_FORMAT_B8G8R8A8_UNORM;
  67. if (has_bitmask(format, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000))
  68. return DXGI_FORMAT_B8G8R8X8_UNORM;
  69. if (has_bitmask(format, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000))
  70. return DXGI_FORMAT_R10G10B10A2_UNORM;
  71. if (has_bitmask(format, 0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000))
  72. return DXGI_FORMAT_R16G16_UNORM;
  73. if (has_bitmask(format, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000))
  74. return DXGI_FORMAT_R32_FLOAT;
  75. break;
  76. }
  77. case 24:
  78. break;
  79. case 16: {
  80. if (has_bitmask(format, 0x7C00, 0x03E0, 0x001F, 0x8000))
  81. return DXGI_FORMAT_B5G5R5A1_UNORM;
  82. if (has_bitmask(format, 0xF800, 0x07E0, 0x001F, 0x0000))
  83. return DXGI_FORMAT_B5G6R5_UNORM;
  84. if (has_bitmask(format, 0xF800, 0x07E0, 0x001F, 0x0000))
  85. return DXGI_FORMAT_B5G6R5_UNORM;
  86. if (has_bitmask(format, 0x0F00, 0x00F0, 0x000F, 0xF000))
  87. return DXGI_FORMAT_B4G4R4A4_UNORM;
  88. if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00))
  89. return DXGI_FORMAT_R8G8_UNORM;
  90. if (has_bitmask(format, 0xFFFF, 0x0000, 0x0000, 0x0000))
  91. return DXGI_FORMAT_R16_UNORM;
  92. break;
  93. }
  94. case 8: {
  95. if (has_bitmask(format, 0xFF, 0x00, 0x00, 0x00))
  96. return DXGI_FORMAT_R8_UNORM;
  97. break;
  98. }
  99. }
  100. } else if ((format.flags & PixelFormatFlags::DDPF_LUMINANCE) == PixelFormatFlags::DDPF_LUMINANCE) {
  101. switch (format.rgb_bit_count) {
  102. case 16: {
  103. if (has_bitmask(format, 0xFFFF, 0x0000, 0x0000, 0x0000))
  104. return DXGI_FORMAT_R16_UNORM;
  105. if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00))
  106. return DXGI_FORMAT_R8G8_UNORM;
  107. break;
  108. }
  109. case 8: {
  110. if (has_bitmask(format, 0xFF, 0x00, 0x00, 0x00))
  111. return DXGI_FORMAT_R8_UNORM;
  112. // Some writers mistakenly write this as 8 bpp.
  113. if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00))
  114. return DXGI_FORMAT_R8G8_UNORM;
  115. break;
  116. }
  117. }
  118. } else if ((format.flags & PixelFormatFlags::DDPF_ALPHA) == PixelFormatFlags::DDPF_ALPHA) {
  119. if (format.rgb_bit_count == 8)
  120. return DXGI_FORMAT_A8_UNORM;
  121. } else if ((format.flags & PixelFormatFlags::DDPF_BUMPDUDV) == PixelFormatFlags::DDPF_BUMPDUDV) {
  122. switch (format.rgb_bit_count) {
  123. case 32: {
  124. if (has_bitmask(format, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000))
  125. return DXGI_FORMAT_R8G8B8A8_SNORM;
  126. if (has_bitmask(format, 0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000))
  127. return DXGI_FORMAT_R16G16_SNORM;
  128. break;
  129. }
  130. case 16: {
  131. if (has_bitmask(format, 0x00FF, 0xFF00, 0x0000, 0x0000))
  132. return DXGI_FORMAT_R8G8_SNORM;
  133. break;
  134. }
  135. }
  136. } else if ((format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC) {
  137. if (format.four_cc == create_four_cc('D', 'X', 'T', '1'))
  138. return DXGI_FORMAT_BC1_UNORM;
  139. if (format.four_cc == create_four_cc('D', 'X', 'T', '2'))
  140. return DXGI_FORMAT_BC2_UNORM;
  141. if (format.four_cc == create_four_cc('D', 'X', 'T', '3'))
  142. return DXGI_FORMAT_BC2_UNORM;
  143. if (format.four_cc == create_four_cc('D', 'X', 'T', '4'))
  144. return DXGI_FORMAT_BC3_UNORM;
  145. if (format.four_cc == create_four_cc('D', 'X', 'T', '5'))
  146. return DXGI_FORMAT_BC3_UNORM;
  147. if (format.four_cc == create_four_cc('A', 'T', 'I', '1'))
  148. return DXGI_FORMAT_BC4_UNORM;
  149. if (format.four_cc == create_four_cc('B', 'C', '4', 'U'))
  150. return DXGI_FORMAT_BC4_UNORM;
  151. if (format.four_cc == create_four_cc('B', 'C', '4', 'S'))
  152. return DXGI_FORMAT_BC4_SNORM;
  153. if (format.four_cc == create_four_cc('A', 'T', 'I', '2'))
  154. return DXGI_FORMAT_BC5_UNORM;
  155. if (format.four_cc == create_four_cc('B', 'C', '5', 'U'))
  156. return DXGI_FORMAT_BC5_UNORM;
  157. if (format.four_cc == create_four_cc('B', 'C', '5', 'S'))
  158. return DXGI_FORMAT_BC5_SNORM;
  159. if (format.four_cc == create_four_cc('R', 'G', 'B', 'G'))
  160. return DXGI_FORMAT_R8G8_B8G8_UNORM;
  161. if (format.four_cc == create_four_cc('G', 'R', 'G', 'B'))
  162. return DXGI_FORMAT_G8R8_G8B8_UNORM;
  163. if (format.four_cc == create_four_cc('Y', 'U', 'Y', '2'))
  164. return DXGI_FORMAT_YUY2;
  165. switch (format.four_cc) {
  166. case 36:
  167. return DXGI_FORMAT_R16G16B16A16_UNORM;
  168. case 110:
  169. return DXGI_FORMAT_R16G16B16A16_SNORM;
  170. case 111:
  171. return DXGI_FORMAT_R16_FLOAT;
  172. case 112:
  173. return DXGI_FORMAT_R16G16_FLOAT;
  174. case 113:
  175. return DXGI_FORMAT_R16G16B16A16_FLOAT;
  176. case 114:
  177. return DXGI_FORMAT_R32_FLOAT;
  178. case 115:
  179. return DXGI_FORMAT_R32G32_FLOAT;
  180. case 116:
  181. return DXGI_FORMAT_R32G32B32A32_FLOAT;
  182. }
  183. }
  184. return DXGI_FORMAT_UNKNOWN;
  185. }
  186. static ErrorOr<void> decode_dx5_alpha_block(Stream& stream, DDSLoadingContext& context, u64 bitmap_x, u64 bitmap_y)
  187. {
  188. auto color0 = TRY(stream.read_value<LittleEndian<u8>>());
  189. auto color1 = TRY(stream.read_value<LittleEndian<u8>>());
  190. auto code0 = TRY(stream.read_value<LittleEndian<u8>>());
  191. auto code1 = TRY(stream.read_value<LittleEndian<u8>>());
  192. auto code2 = TRY(stream.read_value<LittleEndian<u8>>());
  193. auto code3 = TRY(stream.read_value<LittleEndian<u8>>());
  194. auto code4 = TRY(stream.read_value<LittleEndian<u8>>());
  195. auto code5 = TRY(stream.read_value<LittleEndian<u8>>());
  196. u32 codes[6] = { 0 };
  197. codes[0] = code0 + 256 * (code1 + 256);
  198. codes[1] = code1 + 256 * (code2 + 256);
  199. codes[2] = code2 + 256 * (code3 + 256);
  200. codes[3] = code3 + 256 * (code4 + 256);
  201. codes[4] = code4 + 256 * code5;
  202. codes[5] = code5;
  203. u32 color[8] = { 0 };
  204. if (color0 > 128) {
  205. color[0] = color0;
  206. }
  207. if (color1 > 128) {
  208. color[1] = color1;
  209. }
  210. if (color0 > color1) {
  211. color[2] = (6 * color[0] + 1 * color[1]) / 7;
  212. color[3] = (5 * color[0] + 2 * color[1]) / 7;
  213. color[4] = (4 * color[0] + 3 * color[1]) / 7;
  214. color[5] = (3 * color[0] + 4 * color[1]) / 7;
  215. color[6] = (2 * color[0] + 5 * color[1]) / 7;
  216. color[7] = (1 * color[0] + 6 * color[1]) / 7;
  217. } else {
  218. color[2] = (4 * color[0] + 1 * color[1]) / 5;
  219. color[3] = (3 * color[0] + 2 * color[1]) / 5;
  220. color[4] = (2 * color[0] + 3 * color[1]) / 5;
  221. color[5] = (1 * color[0] + 4 * color[1]) / 5;
  222. color[6] = 0;
  223. color[7] = 255;
  224. }
  225. for (size_t y = 0; y < 4; y++) {
  226. for (size_t x = 0; x < 4; x++) {
  227. u8 index = 3 * (4 * y + x);
  228. u8 bit_location = floor(index / 8.0);
  229. u8 adjusted_index = index - (bit_location * 8);
  230. u8 code = (codes[bit_location] >> adjusted_index) & 7;
  231. u8 alpha = color[code];
  232. Color color = Color(0, 0, 0, alpha);
  233. context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color);
  234. }
  235. }
  236. return {};
  237. }
  238. static ErrorOr<void> decode_dx3_alpha_block(Stream& stream, DDSLoadingContext& context, u64 bitmap_x, u64 bitmap_y)
  239. {
  240. auto a0 = TRY(stream.read_value<LittleEndian<u8>>());
  241. auto a1 = TRY(stream.read_value<LittleEndian<u8>>());
  242. auto a2 = TRY(stream.read_value<LittleEndian<u8>>());
  243. auto a3 = TRY(stream.read_value<LittleEndian<u8>>());
  244. auto a4 = TRY(stream.read_value<LittleEndian<u8>>());
  245. auto a5 = TRY(stream.read_value<LittleEndian<u8>>());
  246. auto a6 = TRY(stream.read_value<LittleEndian<u8>>());
  247. auto a7 = TRY(stream.read_value<LittleEndian<u8>>());
  248. u64 alpha_0 = a0 + 256u * (a1 + 256u * (a2 + 256u * (a3 + 256u)));
  249. u64 alpha_1 = a4 + 256u * (a5 + 256u * (a6 + 256u * a7));
  250. for (size_t y = 0; y < 4; y++) {
  251. for (size_t x = 0; x < 4; x++) {
  252. u8 code = 4 * (4 * y + x);
  253. if (code >= 32) {
  254. code = code - 32;
  255. u8 alpha = ((alpha_1 >> code) & 0x0F) * 17;
  256. Color color = Color(0, 0, 0, alpha);
  257. context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color);
  258. } else {
  259. u8 alpha = ((alpha_0 >> code) & 0x0F) * 17;
  260. Color color = Color(0, 0, 0, alpha);
  261. context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color);
  262. }
  263. }
  264. }
  265. return {};
  266. }
  267. static void unpack_rbg_565(u32 rgb, u8* output)
  268. {
  269. u8 r = (rgb >> 11) & 0x1F;
  270. u8 g = (rgb >> 5) & 0x3F;
  271. u8 b = rgb & 0x1F;
  272. output[0] = (r << 3) | (r >> 2);
  273. output[1] = (g << 2) | (g >> 4);
  274. output[2] = (b << 3) | (b >> 2);
  275. output[3] = 255;
  276. }
  277. static ErrorOr<void> decode_color_block(Stream& stream, DDSLoadingContext& context, bool dxt1, u64 bitmap_x, u64 bitmap_y)
  278. {
  279. auto c0_low = TRY(stream.read_value<LittleEndian<u8>>());
  280. auto c0_high = TRY(stream.read_value<LittleEndian<u8>>());
  281. auto c1_low = TRY(stream.read_value<LittleEndian<u8>>());
  282. auto c1_high = TRY(stream.read_value<LittleEndian<u8>>());
  283. auto codes_0 = TRY(stream.read_value<LittleEndian<u8>>());
  284. auto codes_1 = TRY(stream.read_value<LittleEndian<u8>>());
  285. auto codes_2 = TRY(stream.read_value<LittleEndian<u8>>());
  286. auto codes_3 = TRY(stream.read_value<LittleEndian<u8>>());
  287. u64 code = codes_0 + 256 * (codes_1 + 256 * (codes_2 + 256 * codes_3));
  288. u32 color_0 = c0_low + (c0_high * 256);
  289. u32 color_1 = c1_low + (c1_high * 256);
  290. u8 rgba[4][4];
  291. unpack_rbg_565(color_0, rgba[0]);
  292. unpack_rbg_565(color_1, rgba[1]);
  293. if (color_0 > color_1) {
  294. for (size_t i = 0; i < 3; i++) {
  295. rgba[2][i] = (2 * rgba[0][i] + rgba[1][i]) / 3;
  296. rgba[3][i] = (rgba[0][i] + 2 * rgba[1][i]) / 3;
  297. }
  298. rgba[2][3] = 255;
  299. rgba[3][3] = 255;
  300. } else {
  301. for (size_t i = 0; i < 3; i++) {
  302. rgba[2][i] = (rgba[0][i] + rgba[1][i]) / 2;
  303. rgba[3][i] = 0;
  304. }
  305. rgba[2][3] = 255;
  306. rgba[3][3] = dxt1 ? 0 : 255;
  307. }
  308. size_t i = 0;
  309. for (size_t y = 0; y < 4; y++) {
  310. for (size_t x = 0; x < 4; x++) {
  311. u8 code_byte = (code >> (i * 2)) & 3;
  312. u8 r = rgba[code_byte][0];
  313. u8 g = rgba[code_byte][1];
  314. u8 b = rgba[code_byte][2];
  315. u8 a = dxt1 ? rgba[code_byte][3] : context.bitmap->get_pixel(bitmap_x + x, bitmap_y + y).alpha();
  316. Color color = Color(r, g, b, a);
  317. context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color);
  318. i++;
  319. }
  320. }
  321. return {};
  322. }
  323. static ErrorOr<void> decode_dxt(Stream& stream, DDSLoadingContext& context, DXGIFormat format, u64 width, u64 y)
  324. {
  325. if (format == DXGI_FORMAT_BC1_UNORM) {
  326. for (size_t x = 0; x < width; x += 4) {
  327. TRY(decode_color_block(stream, context, true, x, y));
  328. }
  329. }
  330. if (format == DXGI_FORMAT_BC2_UNORM) {
  331. for (size_t x = 0; x < width; x += 4) {
  332. TRY(decode_dx3_alpha_block(stream, context, x, y));
  333. TRY(decode_color_block(stream, context, false, x, y));
  334. }
  335. }
  336. if (format == DXGI_FORMAT_BC3_UNORM) {
  337. for (size_t x = 0; x < width; x += 4) {
  338. TRY(decode_dx5_alpha_block(stream, context, x, y));
  339. TRY(decode_color_block(stream, context, false, x, y));
  340. }
  341. }
  342. return {};
  343. }
  344. static ErrorOr<void> decode_bitmap(Stream& stream, DDSLoadingContext& context, DXGIFormat format, u64 width, u64 height)
  345. {
  346. Vector<u32> dxt_formats = { DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC3_UNORM };
  347. if (dxt_formats.contains_slow(format)) {
  348. for (u64 y = 0; y < height; y += 4) {
  349. TRY(decode_dxt(stream, context, format, width, y));
  350. }
  351. }
  352. // FIXME: Support more encodings (ATI, YUV, RAW, etc...).
  353. return {};
  354. }
  355. static ErrorOr<void> decode_dds(DDSLoadingContext& context)
  356. {
  357. // All valid DDS files are at least 128 bytes long.
  358. if (context.data_size < 128) {
  359. dbgln_if(DDS_DEBUG, "File is too short for DDS");
  360. context.state = DDSLoadingContext::State::Error;
  361. return Error::from_string_literal("File is too short for DDS");
  362. }
  363. FixedMemoryStream stream { ReadonlyBytes { context.data, context.data_size } };
  364. auto magic = TRY(stream.read_value<u32>());
  365. if (magic != create_four_cc('D', 'D', 'S', ' ')) {
  366. dbgln_if(DDS_DEBUG, "Missing magic number");
  367. context.state = DDSLoadingContext::State::Error;
  368. return Error::from_string_literal("Missing magic number");
  369. }
  370. context.header = TRY(stream.read_value<DDSHeader>());
  371. if (context.header.size != 124) {
  372. dbgln_if(DDS_DEBUG, "Header size is malformed");
  373. context.state = DDSLoadingContext::State::Error;
  374. return Error::from_string_literal("Header size is malformed");
  375. }
  376. if (context.header.pixel_format.size != 32) {
  377. dbgln_if(DDS_DEBUG, "Pixel format size is malformed");
  378. context.state = DDSLoadingContext::State::Error;
  379. return Error::from_string_literal("Pixel format size is malformed");
  380. }
  381. if ((context.header.pixel_format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC) {
  382. if (context.header.pixel_format.four_cc == create_four_cc('D', 'X', '1', '0')) {
  383. if (context.data_size < 148) {
  384. dbgln_if(DDS_DEBUG, "DX10 header is too short");
  385. context.state = DDSLoadingContext::State::Error;
  386. return Error::from_string_literal("DX10 header is too short");
  387. }
  388. context.header10 = TRY(stream.read_value<DDSHeaderDXT10>());
  389. }
  390. }
  391. if constexpr (DDS_DEBUG) {
  392. context.dump_debug();
  393. }
  394. DXGIFormat format = get_format(context.header.pixel_format);
  395. Vector<u32> supported_formats = { DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC3_UNORM };
  396. if (!supported_formats.contains_slow(format)) {
  397. dbgln_if(DDS_DEBUG, "Format of type {} is not supported at the moment", static_cast<u32>(format));
  398. context.state = DDSLoadingContext::State::Error;
  399. return Error::from_string_literal("Format type is not supported at the moment");
  400. }
  401. // We support parsing mipmaps, but we only care about the largest one :^) (At least for now)
  402. if (size_t mipmap_level = 0; mipmap_level < max(context.header.mip_map_count, 1u)) {
  403. u64 width = get_width(context.header, mipmap_level);
  404. u64 height = get_height(context.header, mipmap_level);
  405. context.bitmap = TRY(Bitmap::create(BitmapFormat::BGRA8888, { width, height }));
  406. TRY(decode_bitmap(stream, context, format, width, height));
  407. }
  408. context.state = DDSLoadingContext::State::BitmapDecoded;
  409. return {};
  410. }
  411. void DDSLoadingContext::dump_debug()
  412. {
  413. StringBuilder builder;
  414. builder.append("\nDDS:\n"sv);
  415. builder.appendff("\tHeader Size: {}\n", header.size);
  416. builder.append("\tFlags:"sv);
  417. if ((header.flags & DDSFlags::DDSD_CAPS) == DDSFlags::DDSD_CAPS)
  418. builder.append(" DDSD_CAPS"sv);
  419. if ((header.flags & DDSFlags::DDSD_HEIGHT) == DDSFlags::DDSD_HEIGHT)
  420. builder.append(" DDSD_HEIGHT"sv);
  421. if ((header.flags & DDSFlags::DDSD_WIDTH) == DDSFlags::DDSD_WIDTH)
  422. builder.append(" DDSD_WIDTH"sv);
  423. if ((header.flags & DDSFlags::DDSD_PITCH) == DDSFlags::DDSD_PITCH)
  424. builder.append(" DDSD_PITCH"sv);
  425. if ((header.flags & DDSFlags::DDSD_PIXELFORMAT) == DDSFlags::DDSD_PIXELFORMAT)
  426. builder.append(" DDSD_PIXELFORMAT"sv);
  427. if ((header.flags & DDSFlags::DDSD_MIPMAPCOUNT) == DDSFlags::DDSD_MIPMAPCOUNT)
  428. builder.append(" DDSD_MIPMAPCOUNT"sv);
  429. if ((header.flags & DDSFlags::DDSD_LINEARSIZE) == DDSFlags::DDSD_LINEARSIZE)
  430. builder.append(" DDSD_LINEARSIZE"sv);
  431. if ((header.flags & DDSFlags::DDSD_DEPTH) == DDSFlags::DDSD_DEPTH)
  432. builder.append(" DDSD_DEPTH"sv);
  433. builder.append("\n"sv);
  434. builder.appendff("\tHeight: {}\n", header.height);
  435. builder.appendff("\tWidth: {}\n", header.width);
  436. builder.appendff("\tPitch: {}\n", header.pitch);
  437. builder.appendff("\tDepth: {}\n", header.depth);
  438. builder.appendff("\tMipmap Count: {}\n", header.mip_map_count);
  439. builder.append("\tCaps:"sv);
  440. if ((header.caps1 & Caps1Flags::DDSCAPS_COMPLEX) == Caps1Flags::DDSCAPS_COMPLEX)
  441. builder.append(" DDSCAPS_COMPLEX"sv);
  442. if ((header.caps1 & Caps1Flags::DDSCAPS_MIPMAP) == Caps1Flags::DDSCAPS_MIPMAP)
  443. builder.append(" DDSCAPS_MIPMAP"sv);
  444. if ((header.caps1 & Caps1Flags::DDSCAPS_TEXTURE) == Caps1Flags::DDSCAPS_TEXTURE)
  445. builder.append(" DDSCAPS_TEXTURE"sv);
  446. builder.append("\n"sv);
  447. builder.append("\tCaps2:"sv);
  448. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP) == Caps2Flags::DDSCAPS2_CUBEMAP)
  449. builder.append(" DDSCAPS2_CUBEMAP"sv);
  450. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEX) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEX)
  451. builder.append(" DDSCAPS2_CUBEMAP_POSITIVEX"sv);
  452. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEX) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEX)
  453. builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEX"sv);
  454. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEY) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEY)
  455. builder.append(" DDSCAPS2_CUBEMAP_POSITIVEY"sv);
  456. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEY) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEY)
  457. builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEY"sv);
  458. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEZ) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEZ)
  459. builder.append(" DDSCAPS2_CUBEMAP_POSITIVEZ"sv);
  460. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEZ) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEZ)
  461. builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEZ"sv);
  462. if ((header.caps2 & Caps2Flags::DDSCAPS2_VOLUME) == Caps2Flags::DDSCAPS2_VOLUME)
  463. builder.append(" DDSCAPS2_VOLUME"sv);
  464. builder.append("\n"sv);
  465. builder.append("Pixel Format:\n"sv);
  466. builder.appendff("\tStruct Size: {}\n", header.pixel_format.size);
  467. builder.append("\tFlags:"sv);
  468. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_ALPHAPIXELS) == PixelFormatFlags::DDPF_ALPHAPIXELS)
  469. builder.append(" DDPF_ALPHAPIXELS"sv);
  470. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_ALPHA) == PixelFormatFlags::DDPF_ALPHA)
  471. builder.append(" DDPF_ALPHA"sv);
  472. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC)
  473. builder.append(" DDPF_FOURCC"sv);
  474. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_PALETTEINDEXED8) == PixelFormatFlags::DDPF_PALETTEINDEXED8)
  475. builder.append(" DDPF_PALETTEINDEXED8"sv);
  476. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_RGB) == PixelFormatFlags::DDPF_RGB)
  477. builder.append(" DDPF_RGB"sv);
  478. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_YUV) == PixelFormatFlags::DDPF_YUV)
  479. builder.append(" DDPF_YUV"sv);
  480. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_LUMINANCE) == PixelFormatFlags::DDPF_LUMINANCE)
  481. builder.append(" DDPF_LUMINANCE"sv);
  482. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_BUMPDUDV) == PixelFormatFlags::DDPF_BUMPDUDV)
  483. builder.append(" DDPF_BUMPDUDV"sv);
  484. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_NORMAL) == PixelFormatFlags::DDPF_NORMAL)
  485. builder.append(" DDPF_NORMAL"sv);
  486. builder.append("\n"sv);
  487. builder.append("\tFour CC: "sv);
  488. builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 0)) & 0xFF);
  489. builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 1)) & 0xFF);
  490. builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 2)) & 0xFF);
  491. builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 3)) & 0xFF);
  492. builder.append("\n"sv);
  493. builder.appendff("\tRGB Bit Count: {}\n", header.pixel_format.rgb_bit_count);
  494. builder.appendff("\tR Bit Mask: {}\n", header.pixel_format.r_bit_mask);
  495. builder.appendff("\tG Bit Mask: {}\n", header.pixel_format.g_bit_mask);
  496. builder.appendff("\tB Bit Mask: {}\n", header.pixel_format.b_bit_mask);
  497. builder.appendff("\tA Bit Mask: {}\n", header.pixel_format.a_bit_mask);
  498. builder.append("DDS10:\n"sv);
  499. builder.appendff("\tFormat: {}\n", static_cast<u32>(header10.format));
  500. builder.append("\tResource Dimension:"sv);
  501. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_UNKNOWN) == ResourceDimensions::DDS_DIMENSION_UNKNOWN)
  502. builder.append(" DDS_DIMENSION_UNKNOWN"sv);
  503. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_BUFFER) == ResourceDimensions::DDS_DIMENSION_BUFFER)
  504. builder.append(" DDS_DIMENSION_BUFFER"sv);
  505. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE1D) == ResourceDimensions::DDS_DIMENSION_TEXTURE1D)
  506. builder.append(" DDS_DIMENSION_TEXTURE1D"sv);
  507. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE2D) == ResourceDimensions::DDS_DIMENSION_TEXTURE2D)
  508. builder.append(" DDS_DIMENSION_TEXTURE2D"sv);
  509. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE3D) == ResourceDimensions::DDS_DIMENSION_TEXTURE3D)
  510. builder.append(" DDS_DIMENSION_TEXTURE3D"sv);
  511. builder.append("\n"sv);
  512. builder.appendff("\tArray Size: {}\n", header10.array_size);
  513. builder.append("\tMisc Flags:"sv);
  514. if ((header10.misc_flag & MiscFlags::DDS_RESOURCE_MISC_TEXTURECUBE) == MiscFlags::DDS_RESOURCE_MISC_TEXTURECUBE)
  515. builder.append(" DDS_RESOURCE_MISC_TEXTURECUBE"sv);
  516. builder.append("\n"sv);
  517. builder.append("\tMisc Flags 2:"sv);
  518. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_UNKNOWN) == Misc2Flags::DDS_ALPHA_MODE_UNKNOWN)
  519. builder.append(" DDS_ALPHA_MODE_UNKNOWN"sv);
  520. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_STRAIGHT) == Misc2Flags::DDS_ALPHA_MODE_STRAIGHT)
  521. builder.append(" DDS_ALPHA_MODE_STRAIGHT"sv);
  522. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_PREMULTIPLIED) == Misc2Flags::DDS_ALPHA_MODE_PREMULTIPLIED)
  523. builder.append(" DDS_ALPHA_MODE_PREMULTIPLIED"sv);
  524. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_OPAQUE) == Misc2Flags::DDS_ALPHA_MODE_OPAQUE)
  525. builder.append(" DDS_ALPHA_MODE_OPAQUE"sv);
  526. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_CUSTOM) == Misc2Flags::DDS_ALPHA_MODE_CUSTOM)
  527. builder.append(" DDS_ALPHA_MODE_CUSTOM"sv);
  528. builder.append("\n"sv);
  529. dbgln("{}", builder.to_deprecated_string());
  530. }
  531. DDSImageDecoderPlugin::DDSImageDecoderPlugin(u8 const* data, size_t size)
  532. {
  533. m_context = make<DDSLoadingContext>();
  534. m_context->data = data;
  535. m_context->data_size = size;
  536. }
  537. DDSImageDecoderPlugin::~DDSImageDecoderPlugin() = default;
  538. IntSize DDSImageDecoderPlugin::size()
  539. {
  540. if (m_context->state == DDSLoadingContext::State::Error)
  541. return {};
  542. if (m_context->state == DDSLoadingContext::State::BitmapDecoded)
  543. return { m_context->header.width, m_context->header.height };
  544. return {};
  545. }
  546. void DDSImageDecoderPlugin::set_volatile()
  547. {
  548. if (m_context->bitmap)
  549. m_context->bitmap->set_volatile();
  550. }
  551. bool DDSImageDecoderPlugin::set_nonvolatile(bool& was_purged)
  552. {
  553. if (!m_context->bitmap)
  554. return false;
  555. return m_context->bitmap->set_nonvolatile(was_purged);
  556. }
  557. bool DDSImageDecoderPlugin::initialize()
  558. {
  559. // The header is always at least 128 bytes, so if the file is smaller, it can't be a DDS.
  560. return m_context->data_size > 128
  561. && m_context->data[0] == 0x44
  562. && m_context->data[1] == 0x44
  563. && m_context->data[2] == 0x53
  564. && m_context->data[3] == 0x20;
  565. }
  566. bool DDSImageDecoderPlugin::sniff(ReadonlyBytes data)
  567. {
  568. // The header is always at least 128 bytes, so if the file is smaller, it can't be a DDS.
  569. return data.size() > 128
  570. && data.data()[0] == 0x44
  571. && data.data()[1] == 0x44
  572. && data.data()[2] == 0x53
  573. && data.data()[3] == 0x20;
  574. }
  575. ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> DDSImageDecoderPlugin::create(ReadonlyBytes data)
  576. {
  577. return adopt_nonnull_own_or_enomem(new (nothrow) DDSImageDecoderPlugin(data.data(), data.size()));
  578. }
  579. bool DDSImageDecoderPlugin::is_animated()
  580. {
  581. return false;
  582. }
  583. size_t DDSImageDecoderPlugin::loop_count()
  584. {
  585. return 0;
  586. }
  587. size_t DDSImageDecoderPlugin::frame_count()
  588. {
  589. return 1;
  590. }
  591. size_t DDSImageDecoderPlugin::first_animated_frame_index()
  592. {
  593. return 0;
  594. }
  595. ErrorOr<ImageFrameDescriptor> DDSImageDecoderPlugin::frame(size_t index)
  596. {
  597. if (index > 0)
  598. return Error::from_string_literal("DDSImageDecoderPlugin: Invalid frame index");
  599. if (m_context->state == DDSLoadingContext::State::Error)
  600. return Error::from_string_literal("DDSImageDecoderPlugin: Decoding failed");
  601. if (m_context->state < DDSLoadingContext::State::BitmapDecoded) {
  602. TRY(decode_dds(*m_context));
  603. }
  604. VERIFY(m_context->bitmap);
  605. return ImageFrameDescriptor { m_context->bitmap, 0 };
  606. }
  607. ErrorOr<Optional<ReadonlyBytes>> DDSImageDecoderPlugin::icc_data()
  608. {
  609. return OptionalNone {};
  610. }
  611. }