DDSLoader.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  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/LexicalPath.h>
  9. #include <AK/MappedFile.h>
  10. #include <AK/MemoryStream.h>
  11. #include <AK/StringBuilder.h>
  12. #include <AK/Vector.h>
  13. #include <LibGfx/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. #ifdef __serenity__
  22. # include <serenity.h>
  23. #endif
  24. namespace Gfx {
  25. struct DDSLoadingContext {
  26. enum State {
  27. NotDecoded = 0,
  28. Error,
  29. BitmapDecoded,
  30. };
  31. State state { State::NotDecoded };
  32. const u8* data { nullptr };
  33. size_t data_size { 0 };
  34. DDSHeader header;
  35. DDSHeaderDXT10 header10;
  36. RefPtr<Gfx::Bitmap> bitmap;
  37. void dump_debug();
  38. };
  39. static constexpr u32 create_four_cc(char c0, char c1, char c2, char c3)
  40. {
  41. return c0 | c1 << 8 | c2 << 16 | c3 << 24;
  42. }
  43. static bool is_planar(DXGIFormat format)
  44. {
  45. switch (format) {
  46. case DXGI_FORMAT_NV12:
  47. case DXGI_FORMAT_420_OPAQUE:
  48. case DXGI_FORMAT_P208:
  49. case DXGI_FORMAT_P010:
  50. case DXGI_FORMAT_P016:
  51. return true;
  52. default:
  53. return false;
  54. }
  55. }
  56. static bool is_packed(DXGIFormat format)
  57. {
  58. switch (format) {
  59. case DXGI_FORMAT_R8G8_B8G8_UNORM:
  60. case DXGI_FORMAT_G8R8_G8B8_UNORM:
  61. case DXGI_FORMAT_YUY2:
  62. case DXGI_FORMAT_Y210:
  63. case DXGI_FORMAT_Y216:
  64. return true;
  65. default:
  66. return false;
  67. }
  68. }
  69. static u64 get_width(DDSHeader header, size_t mipmap_level)
  70. {
  71. if (mipmap_level >= header.mip_map_count) {
  72. return header.width;
  73. }
  74. return header.width >> mipmap_level;
  75. }
  76. static u64 get_height(DDSHeader header, size_t mipmap_level)
  77. {
  78. if (mipmap_level >= header.mip_map_count) {
  79. return header.height;
  80. }
  81. return header.height >> mipmap_level;
  82. }
  83. static constexpr bool has_bitmask(DDSPixelFormat format, u32 r, u32 g, u32 b, u32 a)
  84. {
  85. return format.r_bit_mask == r && format.g_bit_mask == g && format.b_bit_mask == b && format.a_bit_mask == a;
  86. }
  87. static DXGIFormat get_format(DDSPixelFormat format)
  88. {
  89. if ((format.flags & PixelFormatFlags::DDPF_RGB) == PixelFormatFlags::DDPF_RGB) {
  90. switch (format.rgb_bit_count) {
  91. case 32: {
  92. if (has_bitmask(format, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000))
  93. return DXGI_FORMAT_R8G8B8A8_UNORM;
  94. if (has_bitmask(format, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000))
  95. return DXGI_FORMAT_B8G8R8A8_UNORM;
  96. if (has_bitmask(format, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000))
  97. return DXGI_FORMAT_B8G8R8X8_UNORM;
  98. if (has_bitmask(format, 0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000))
  99. return DXGI_FORMAT_R10G10B10A2_UNORM;
  100. if (has_bitmask(format, 0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000))
  101. return DXGI_FORMAT_R16G16_UNORM;
  102. if (has_bitmask(format, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000))
  103. return DXGI_FORMAT_R32_FLOAT;
  104. break;
  105. }
  106. case 24:
  107. break;
  108. case 16: {
  109. if (has_bitmask(format, 0x7C00, 0x03E0, 0x001F, 0x8000))
  110. return DXGI_FORMAT_B5G5R5A1_UNORM;
  111. if (has_bitmask(format, 0xF800, 0x07E0, 0x001F, 0x0000))
  112. return DXGI_FORMAT_B5G6R5_UNORM;
  113. if (has_bitmask(format, 0xF800, 0x07E0, 0x001F, 0x0000))
  114. return DXGI_FORMAT_B5G6R5_UNORM;
  115. if (has_bitmask(format, 0x0F00, 0x00F0, 0x000F, 0xF000))
  116. return DXGI_FORMAT_B4G4R4A4_UNORM;
  117. if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00))
  118. return DXGI_FORMAT_R8G8_UNORM;
  119. if (has_bitmask(format, 0xFFFF, 0x0000, 0x0000, 0x0000))
  120. return DXGI_FORMAT_R16_UNORM;
  121. break;
  122. }
  123. case 8: {
  124. if (has_bitmask(format, 0xFF, 0x00, 0x00, 0x00))
  125. return DXGI_FORMAT_R8_UNORM;
  126. break;
  127. }
  128. }
  129. } else if ((format.flags & PixelFormatFlags::DDPF_LUMINANCE) == PixelFormatFlags::DDPF_LUMINANCE) {
  130. switch (format.rgb_bit_count) {
  131. case 16: {
  132. if (has_bitmask(format, 0xFFFF, 0x0000, 0x0000, 0x0000))
  133. return DXGI_FORMAT_R16_UNORM;
  134. if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00))
  135. return DXGI_FORMAT_R8G8_UNORM;
  136. break;
  137. }
  138. case 8: {
  139. if (has_bitmask(format, 0xFF, 0x00, 0x00, 0x00))
  140. return DXGI_FORMAT_R8_UNORM;
  141. // Some writers mistakenly write this as 8 bpp.
  142. if (has_bitmask(format, 0x00FF, 0x0000, 0x0000, 0xFF00))
  143. return DXGI_FORMAT_R8G8_UNORM;
  144. break;
  145. }
  146. }
  147. } else if ((format.flags & PixelFormatFlags::DDPF_ALPHA) == PixelFormatFlags::DDPF_ALPHA) {
  148. if (format.rgb_bit_count == 8)
  149. return DXGI_FORMAT_A8_UNORM;
  150. } else if ((format.flags & PixelFormatFlags::DDPF_BUMPDUDV) == PixelFormatFlags::DDPF_BUMPDUDV) {
  151. switch (format.rgb_bit_count) {
  152. case 32: {
  153. if (has_bitmask(format, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000))
  154. return DXGI_FORMAT_R8G8B8A8_SNORM;
  155. if (has_bitmask(format, 0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000))
  156. return DXGI_FORMAT_R16G16_SNORM;
  157. break;
  158. }
  159. case 16: {
  160. if (has_bitmask(format, 0x00FF, 0xFF00, 0x0000, 0x0000))
  161. return DXGI_FORMAT_R8G8_SNORM;
  162. break;
  163. }
  164. }
  165. } else if ((format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC) {
  166. if (format.four_cc == create_four_cc('D', 'X', 'T', '1'))
  167. return DXGI_FORMAT_BC1_UNORM;
  168. if (format.four_cc == create_four_cc('D', 'X', 'T', '2'))
  169. return DXGI_FORMAT_BC2_UNORM;
  170. if (format.four_cc == create_four_cc('D', 'X', 'T', '3'))
  171. return DXGI_FORMAT_BC2_UNORM;
  172. if (format.four_cc == create_four_cc('D', 'X', 'T', '4'))
  173. return DXGI_FORMAT_BC3_UNORM;
  174. if (format.four_cc == create_four_cc('D', 'X', 'T', '5'))
  175. return DXGI_FORMAT_BC3_UNORM;
  176. if (format.four_cc == create_four_cc('A', 'T', 'I', '1'))
  177. return DXGI_FORMAT_BC4_UNORM;
  178. if (format.four_cc == create_four_cc('B', 'C', '4', 'U'))
  179. return DXGI_FORMAT_BC4_UNORM;
  180. if (format.four_cc == create_four_cc('B', 'C', '4', 'S'))
  181. return DXGI_FORMAT_BC4_SNORM;
  182. if (format.four_cc == create_four_cc('A', 'T', 'I', '2'))
  183. return DXGI_FORMAT_BC5_UNORM;
  184. if (format.four_cc == create_four_cc('B', 'C', '5', 'U'))
  185. return DXGI_FORMAT_BC5_UNORM;
  186. if (format.four_cc == create_four_cc('B', 'C', '5', 'S'))
  187. return DXGI_FORMAT_BC5_SNORM;
  188. if (format.four_cc == create_four_cc('R', 'G', 'B', 'G'))
  189. return DXGI_FORMAT_R8G8_B8G8_UNORM;
  190. if (format.four_cc == create_four_cc('G', 'R', 'G', 'B'))
  191. return DXGI_FORMAT_G8R8_G8B8_UNORM;
  192. if (format.four_cc == create_four_cc('Y', 'U', 'Y', '2'))
  193. return DXGI_FORMAT_YUY2;
  194. switch (format.four_cc) {
  195. case 36:
  196. return DXGI_FORMAT_R16G16B16A16_UNORM;
  197. case 110:
  198. return DXGI_FORMAT_R16G16B16A16_SNORM;
  199. case 111:
  200. return DXGI_FORMAT_R16_FLOAT;
  201. case 112:
  202. return DXGI_FORMAT_R16G16_FLOAT;
  203. case 113:
  204. return DXGI_FORMAT_R16G16B16A16_FLOAT;
  205. case 114:
  206. return DXGI_FORMAT_R32_FLOAT;
  207. case 115:
  208. return DXGI_FORMAT_R32G32_FLOAT;
  209. case 116:
  210. return DXGI_FORMAT_R32G32B32A32_FLOAT;
  211. }
  212. }
  213. return DXGI_FORMAT_UNKNOWN;
  214. }
  215. static bool is_block_compressed(DXGIFormat format)
  216. {
  217. switch (format) {
  218. case DXGI_FORMAT_BC1_TYPELESS:
  219. case DXGI_FORMAT_BC1_UNORM:
  220. case DXGI_FORMAT_BC1_UNORM_SRGB:
  221. case DXGI_FORMAT_BC4_TYPELESS:
  222. case DXGI_FORMAT_BC4_UNORM:
  223. case DXGI_FORMAT_BC4_SNORM:
  224. case DXGI_FORMAT_BC2_TYPELESS:
  225. case DXGI_FORMAT_BC2_UNORM:
  226. case DXGI_FORMAT_BC2_UNORM_SRGB:
  227. case DXGI_FORMAT_BC3_TYPELESS:
  228. case DXGI_FORMAT_BC3_UNORM:
  229. case DXGI_FORMAT_BC3_UNORM_SRGB:
  230. case DXGI_FORMAT_BC5_TYPELESS:
  231. case DXGI_FORMAT_BC5_UNORM:
  232. case DXGI_FORMAT_BC5_SNORM:
  233. case DXGI_FORMAT_BC6H_TYPELESS:
  234. case DXGI_FORMAT_BC6H_UF16:
  235. case DXGI_FORMAT_BC6H_SF16:
  236. case DXGI_FORMAT_BC7_TYPELESS:
  237. case DXGI_FORMAT_BC7_UNORM:
  238. case DXGI_FORMAT_BC7_UNORM_SRGB:
  239. return true;
  240. default:
  241. return false;
  242. }
  243. }
  244. static size_t block_size(DXGIFormat format)
  245. {
  246. switch (format) {
  247. case DXGI_FORMAT_BC2_TYPELESS:
  248. case DXGI_FORMAT_BC2_UNORM:
  249. case DXGI_FORMAT_BC2_UNORM_SRGB:
  250. case DXGI_FORMAT_BC3_TYPELESS:
  251. case DXGI_FORMAT_BC3_UNORM:
  252. case DXGI_FORMAT_BC3_UNORM_SRGB:
  253. case DXGI_FORMAT_BC5_TYPELESS:
  254. case DXGI_FORMAT_BC5_UNORM:
  255. case DXGI_FORMAT_BC5_SNORM:
  256. case DXGI_FORMAT_BC6H_TYPELESS:
  257. case DXGI_FORMAT_BC6H_UF16:
  258. case DXGI_FORMAT_BC6H_SF16:
  259. case DXGI_FORMAT_BC7_TYPELESS:
  260. case DXGI_FORMAT_BC7_UNORM:
  261. case DXGI_FORMAT_BC7_UNORM_SRGB:
  262. return 16;
  263. case DXGI_FORMAT_BC1_TYPELESS:
  264. case DXGI_FORMAT_BC1_UNORM:
  265. case DXGI_FORMAT_BC1_UNORM_SRGB:
  266. case DXGI_FORMAT_BC4_TYPELESS:
  267. case DXGI_FORMAT_BC4_UNORM:
  268. case DXGI_FORMAT_BC4_SNORM:
  269. case DXGI_FORMAT_Y210:
  270. case DXGI_FORMAT_Y216:
  271. return 8;
  272. case DXGI_FORMAT_R8G8_B8G8_UNORM:
  273. case DXGI_FORMAT_G8R8_G8B8_UNORM:
  274. case DXGI_FORMAT_YUY2:
  275. case DXGI_FORMAT_P010:
  276. case DXGI_FORMAT_P016:
  277. return 4;
  278. case DXGI_FORMAT_NV12:
  279. case DXGI_FORMAT_420_OPAQUE:
  280. case DXGI_FORMAT_P208:
  281. return 2;
  282. default:
  283. return 0;
  284. }
  285. }
  286. static size_t bits_per_pixel(DXGIFormat format)
  287. {
  288. switch (format) {
  289. case DXGI_FORMAT_R32G32B32A32_TYPELESS:
  290. case DXGI_FORMAT_R32G32B32A32_FLOAT:
  291. case DXGI_FORMAT_R32G32B32A32_UINT:
  292. case DXGI_FORMAT_R32G32B32A32_SINT:
  293. return 128;
  294. case DXGI_FORMAT_R32G32B32_TYPELESS:
  295. case DXGI_FORMAT_R32G32B32_FLOAT:
  296. case DXGI_FORMAT_R32G32B32_UINT:
  297. case DXGI_FORMAT_R32G32B32_SINT:
  298. return 96;
  299. case DXGI_FORMAT_R16G16B16A16_TYPELESS:
  300. case DXGI_FORMAT_R16G16B16A16_FLOAT:
  301. case DXGI_FORMAT_R16G16B16A16_UNORM:
  302. case DXGI_FORMAT_R16G16B16A16_UINT:
  303. case DXGI_FORMAT_R16G16B16A16_SNORM:
  304. case DXGI_FORMAT_R16G16B16A16_SINT:
  305. case DXGI_FORMAT_R32G32_TYPELESS:
  306. case DXGI_FORMAT_R32G32_FLOAT:
  307. case DXGI_FORMAT_R32G32_UINT:
  308. case DXGI_FORMAT_R32G32_SINT:
  309. case DXGI_FORMAT_R32G8X24_TYPELESS:
  310. case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
  311. case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
  312. case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
  313. case DXGI_FORMAT_Y416:
  314. case DXGI_FORMAT_Y210:
  315. case DXGI_FORMAT_Y216:
  316. return 64;
  317. case DXGI_FORMAT_R10G10B10A2_TYPELESS:
  318. case DXGI_FORMAT_R10G10B10A2_UNORM:
  319. case DXGI_FORMAT_R10G10B10A2_UINT:
  320. case DXGI_FORMAT_R11G11B10_FLOAT:
  321. case DXGI_FORMAT_R8G8B8A8_TYPELESS:
  322. case DXGI_FORMAT_R8G8B8A8_UNORM:
  323. case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
  324. case DXGI_FORMAT_R8G8B8A8_UINT:
  325. case DXGI_FORMAT_R8G8B8A8_SNORM:
  326. case DXGI_FORMAT_R8G8B8A8_SINT:
  327. case DXGI_FORMAT_R16G16_TYPELESS:
  328. case DXGI_FORMAT_R16G16_FLOAT:
  329. case DXGI_FORMAT_R16G16_UNORM:
  330. case DXGI_FORMAT_R16G16_UINT:
  331. case DXGI_FORMAT_R16G16_SNORM:
  332. case DXGI_FORMAT_R16G16_SINT:
  333. case DXGI_FORMAT_R32_TYPELESS:
  334. case DXGI_FORMAT_D32_FLOAT:
  335. case DXGI_FORMAT_R32_FLOAT:
  336. case DXGI_FORMAT_R32_UINT:
  337. case DXGI_FORMAT_R32_SINT:
  338. case DXGI_FORMAT_R24G8_TYPELESS:
  339. case DXGI_FORMAT_D24_UNORM_S8_UINT:
  340. case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
  341. case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
  342. case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
  343. case DXGI_FORMAT_R8G8_B8G8_UNORM:
  344. case DXGI_FORMAT_G8R8_G8B8_UNORM:
  345. case DXGI_FORMAT_B8G8R8A8_UNORM:
  346. case DXGI_FORMAT_B8G8R8X8_UNORM:
  347. case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
  348. case DXGI_FORMAT_B8G8R8A8_TYPELESS:
  349. case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
  350. case DXGI_FORMAT_B8G8R8X8_TYPELESS:
  351. case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
  352. case DXGI_FORMAT_AYUV:
  353. case DXGI_FORMAT_Y410:
  354. case DXGI_FORMAT_YUY2:
  355. return 32;
  356. case DXGI_FORMAT_P010:
  357. case DXGI_FORMAT_P016:
  358. case DXGI_FORMAT_V408:
  359. return 24;
  360. case DXGI_FORMAT_R8G8_TYPELESS:
  361. case DXGI_FORMAT_R8G8_UNORM:
  362. case DXGI_FORMAT_R8G8_UINT:
  363. case DXGI_FORMAT_R8G8_SNORM:
  364. case DXGI_FORMAT_R8G8_SINT:
  365. case DXGI_FORMAT_R16_TYPELESS:
  366. case DXGI_FORMAT_R16_FLOAT:
  367. case DXGI_FORMAT_D16_UNORM:
  368. case DXGI_FORMAT_R16_UNORM:
  369. case DXGI_FORMAT_R16_UINT:
  370. case DXGI_FORMAT_R16_SNORM:
  371. case DXGI_FORMAT_R16_SINT:
  372. case DXGI_FORMAT_B5G6R5_UNORM:
  373. case DXGI_FORMAT_B5G5R5A1_UNORM:
  374. case DXGI_FORMAT_A8P8:
  375. case DXGI_FORMAT_B4G4R4A4_UNORM:
  376. case DXGI_FORMAT_P208:
  377. case DXGI_FORMAT_V208:
  378. return 16;
  379. case DXGI_FORMAT_NV12:
  380. case DXGI_FORMAT_420_OPAQUE:
  381. case DXGI_FORMAT_NV11:
  382. return 12;
  383. case DXGI_FORMAT_R8_TYPELESS:
  384. case DXGI_FORMAT_R8_UNORM:
  385. case DXGI_FORMAT_R8_UINT:
  386. case DXGI_FORMAT_R8_SNORM:
  387. case DXGI_FORMAT_R8_SINT:
  388. case DXGI_FORMAT_A8_UNORM:
  389. case DXGI_FORMAT_BC2_TYPELESS:
  390. case DXGI_FORMAT_BC2_UNORM:
  391. case DXGI_FORMAT_BC2_UNORM_SRGB:
  392. case DXGI_FORMAT_BC3_TYPELESS:
  393. case DXGI_FORMAT_BC3_UNORM:
  394. case DXGI_FORMAT_BC3_UNORM_SRGB:
  395. case DXGI_FORMAT_BC5_TYPELESS:
  396. case DXGI_FORMAT_BC5_UNORM:
  397. case DXGI_FORMAT_BC5_SNORM:
  398. case DXGI_FORMAT_BC6H_TYPELESS:
  399. case DXGI_FORMAT_BC6H_UF16:
  400. case DXGI_FORMAT_BC6H_SF16:
  401. case DXGI_FORMAT_BC7_TYPELESS:
  402. case DXGI_FORMAT_BC7_UNORM:
  403. case DXGI_FORMAT_BC7_UNORM_SRGB:
  404. case DXGI_FORMAT_AI44:
  405. case DXGI_FORMAT_IA44:
  406. case DXGI_FORMAT_P8:
  407. return 8;
  408. case DXGI_FORMAT_R1_UNORM:
  409. return 1;
  410. case DXGI_FORMAT_BC1_TYPELESS:
  411. case DXGI_FORMAT_BC1_UNORM:
  412. case DXGI_FORMAT_BC1_UNORM_SRGB:
  413. case DXGI_FORMAT_BC4_TYPELESS:
  414. case DXGI_FORMAT_BC4_UNORM:
  415. case DXGI_FORMAT_BC4_SNORM:
  416. return 4;
  417. default:
  418. return 0;
  419. }
  420. }
  421. static void decode_dx5_alpha_block(InputMemoryStream& stream, DDSLoadingContext& context, u64 bitmap_x, u64 bitmap_y)
  422. {
  423. LittleEndian<u8> color0 {}, color1 {};
  424. LittleEndian<u8> code0 {}, code1 {}, code2 {}, code3 {}, code4 {}, code5 {};
  425. stream >> color0;
  426. stream >> color1;
  427. stream >> code0;
  428. stream >> code1;
  429. stream >> code2;
  430. stream >> code3;
  431. stream >> code4;
  432. stream >> code5;
  433. u32 codes[6] = { 0 };
  434. codes[0] = code0 + 256 * (code1 + 256);
  435. codes[1] = code1 + 256 * (code2 + 256);
  436. codes[2] = code2 + 256 * (code3 + 256);
  437. codes[3] = code3 + 256 * (code4 + 256);
  438. codes[4] = code4 + 256 * code5;
  439. codes[5] = code5;
  440. u32 color[8] = { 0 };
  441. if (color0 > 128) {
  442. color[0] = color0;
  443. }
  444. if (color1 > 128) {
  445. color[1] = color1;
  446. }
  447. if (color0 > color1) {
  448. color[2] = (6 * color[0] + 1 * color[1]) / 7;
  449. color[3] = (5 * color[0] + 2 * color[1]) / 7;
  450. color[4] = (4 * color[0] + 3 * color[1]) / 7;
  451. color[5] = (3 * color[0] + 4 * color[1]) / 7;
  452. color[6] = (2 * color[0] + 5 * color[1]) / 7;
  453. color[7] = (1 * color[0] + 6 * color[1]) / 7;
  454. } else {
  455. color[2] = (4 * color[0] + 1 * color[1]) / 5;
  456. color[3] = (3 * color[0] + 2 * color[1]) / 5;
  457. color[4] = (2 * color[0] + 3 * color[1]) / 5;
  458. color[5] = (1 * color[0] + 4 * color[1]) / 5;
  459. color[6] = 0;
  460. color[7] = 255;
  461. }
  462. for (size_t y = 0; y < 4; y++) {
  463. for (size_t x = 0; x < 4; x++) {
  464. u8 index = 3 * (4 * y + x);
  465. u8 bit_location = floor(index / 8.0);
  466. u8 adjusted_index = index - (bit_location * 8);
  467. u8 code = (codes[bit_location] >> adjusted_index) & 7;
  468. u8 alpha = color[code];
  469. Color color = Color(0, 0, 0, alpha);
  470. context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color);
  471. }
  472. }
  473. }
  474. static void decode_dx3_alpha_block(InputMemoryStream& stream, DDSLoadingContext& context, u64 bitmap_x, u64 bitmap_y)
  475. {
  476. LittleEndian<u8> a0 {}, a1 {}, a2 {}, a3 {}, a4 {}, a5 {}, a6 {}, a7 {};
  477. stream >> a0;
  478. stream >> a1;
  479. stream >> a2;
  480. stream >> a3;
  481. stream >> a4;
  482. stream >> a5;
  483. stream >> a6;
  484. stream >> a7;
  485. u64 alpha_0 = a0 + 256u * (a1 + 256u * (a2 + 256u * (a3 + 256u)));
  486. u64 alpha_1 = a4 + 256u * (a5 + 256u * (a6 + 256u * a7));
  487. for (size_t y = 0; y < 4; y++) {
  488. for (size_t x = 0; x < 4; x++) {
  489. u8 code = 4 * (4 * y + x);
  490. if (code >= 32) {
  491. code = code - 32;
  492. u8 alpha = ((alpha_1 >> code) & 0x0F) * 17;
  493. Color color = Color(0, 0, 0, alpha);
  494. context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color);
  495. } else {
  496. u8 alpha = ((alpha_0 >> code) & 0x0F) * 17;
  497. Color color = Color(0, 0, 0, alpha);
  498. context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color);
  499. }
  500. }
  501. }
  502. }
  503. static void unpack_rbg_565(u32 rgb, u8* output)
  504. {
  505. u8 r = (rgb >> 11) & 0x1F;
  506. u8 g = (rgb >> 5) & 0x3F;
  507. u8 b = rgb & 0x1F;
  508. output[0] = (r << 3) | (r >> 2);
  509. output[1] = (g << 2) | (g >> 4);
  510. output[2] = (b << 3) | (b >> 2);
  511. output[3] = 255;
  512. }
  513. static void decode_color_block(InputMemoryStream& stream, DDSLoadingContext& context, bool dxt1, u64 bitmap_x, u64 bitmap_y)
  514. {
  515. LittleEndian<u8> c0_low {}, c0_high {}, c1_low {}, c1_high {};
  516. LittleEndian<u8> codes_0 {}, codes_1 {}, codes_2 {}, codes_3 {};
  517. stream >> c0_low;
  518. stream >> c0_high;
  519. stream >> c1_low;
  520. stream >> c1_high;
  521. stream >> codes_0;
  522. stream >> codes_1;
  523. stream >> codes_2;
  524. stream >> codes_3;
  525. u64 code = codes_0 + 256 * (codes_1 + 256 * (codes_2 + 256 * codes_3));
  526. u32 color_0 = c0_low + (c0_high * 256);
  527. u32 color_1 = c1_low + (c1_high * 256);
  528. u8 rgba[4][4];
  529. unpack_rbg_565(color_0, rgba[0]);
  530. unpack_rbg_565(color_1, rgba[1]);
  531. if (color_0 > color_1) {
  532. for (size_t i = 0; i < 3; i++) {
  533. rgba[2][i] = (2 * rgba[0][i] + rgba[1][i]) / 3;
  534. rgba[3][i] = (rgba[0][i] + 2 * rgba[1][i]) / 3;
  535. }
  536. rgba[2][3] = 255;
  537. rgba[3][3] = 255;
  538. } else {
  539. for (size_t i = 0; i < 3; i++) {
  540. rgba[2][i] = (rgba[0][i] + rgba[1][i]) / 2;
  541. rgba[3][i] = 0;
  542. }
  543. rgba[2][3] = 255;
  544. rgba[3][3] = dxt1 ? 0 : 255;
  545. }
  546. size_t i = 0;
  547. for (size_t y = 0; y < 4; y++) {
  548. for (size_t x = 0; x < 4; x++) {
  549. u8 code_byte = (code >> (i * 2)) & 3;
  550. u8 r = rgba[code_byte][0];
  551. u8 g = rgba[code_byte][1];
  552. u8 b = rgba[code_byte][2];
  553. u8 a = dxt1 ? rgba[code_byte][3] : context.bitmap->get_pixel(bitmap_x + x, bitmap_y + y).alpha();
  554. Color color = Color(r, g, b, a);
  555. context.bitmap->set_pixel(bitmap_x + x, bitmap_y + y, color);
  556. i++;
  557. }
  558. }
  559. }
  560. static void decode_dxt(InputMemoryStream& stream, DDSLoadingContext& context, DXGIFormat format, u64 width, u64 y)
  561. {
  562. if (format == DXGI_FORMAT_BC1_UNORM) {
  563. for (size_t x = 0; x < width; x += 4) {
  564. decode_color_block(stream, context, true, x, y);
  565. }
  566. }
  567. if (format == DXGI_FORMAT_BC2_UNORM) {
  568. for (size_t x = 0; x < width; x += 4) {
  569. decode_dx3_alpha_block(stream, context, x, y);
  570. decode_color_block(stream, context, false, x, y);
  571. }
  572. }
  573. if (format == DXGI_FORMAT_BC3_UNORM) {
  574. for (size_t x = 0; x < width; x += 4) {
  575. decode_dx5_alpha_block(stream, context, x, y);
  576. decode_color_block(stream, context, false, x, y);
  577. }
  578. }
  579. }
  580. static void decode_bitmap(InputMemoryStream& stream, DDSLoadingContext& context, DXGIFormat format, u64 width, u64 height)
  581. {
  582. Vector<u32> dxt_formats = { DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC3_UNORM };
  583. if (dxt_formats.contains_slow(format)) {
  584. for (u64 y = 0; y < height; y += 4) {
  585. decode_dxt(stream, context, format, width, y);
  586. }
  587. }
  588. // FIXME: Support more encodings (ATI, YUV, RAW, etc...).
  589. }
  590. static size_t get_minimum_bytes_for_mipmap(DXGIFormat format, u64 width, u64 height)
  591. {
  592. u64 row_bytes {};
  593. u64 row_count {};
  594. if (is_block_compressed(format)) {
  595. u64 width_in_blocks {};
  596. u64 height_in_blocks {};
  597. if (width > 0) {
  598. width_in_blocks = max(static_cast<u64>(1), (width + 3u) / 4u);
  599. }
  600. if (height > 0) {
  601. height_in_blocks = max(static_cast<u64>(1), (height + 3u) / 4u);
  602. }
  603. row_bytes = width_in_blocks * block_size(format);
  604. row_count = height_in_blocks;
  605. return row_bytes * row_count;
  606. } else if (is_packed(format)) {
  607. row_bytes = ((width + 1u) >> 1) * block_size(format);
  608. row_count = height;
  609. return row_bytes * row_count;
  610. } else if (format == DXGI_FORMAT_NV11) {
  611. row_bytes = ((width + 3u) >> 2) * 4u;
  612. row_count = height * 2u;
  613. return row_bytes * row_count;
  614. } else if (is_planar(format)) {
  615. row_bytes = ((width + 1u) >> 1) * block_size(format);
  616. row_count = height + ((height + 1u) >> 1);
  617. return (row_bytes * row_count) + (((row_bytes * row_count) + 1) >> 1);
  618. } else {
  619. u32 bpp = bits_per_pixel(format);
  620. row_bytes = (width * bpp + 7u) / 8u;
  621. row_count = height;
  622. return row_bytes * row_count;
  623. }
  624. }
  625. static bool decode_dds(DDSLoadingContext& context)
  626. {
  627. InputMemoryStream stream({ context.data, context.data_size });
  628. // All valid DDS files are at least 128 bytes long.
  629. if (stream.remaining() < 128) {
  630. dbgln_if(DDS_DEBUG, "File is too short for DDS");
  631. context.state = DDSLoadingContext::State::Error;
  632. return false;
  633. }
  634. u32 magic;
  635. stream >> magic;
  636. if (magic != create_four_cc('D', 'D', 'S', ' ')) {
  637. dbgln_if(DDS_DEBUG, "Missing magic number");
  638. context.state = DDSLoadingContext::State::Error;
  639. return false;
  640. }
  641. stream >> context.header.size;
  642. stream >> context.header.flags;
  643. stream >> context.header.height;
  644. stream >> context.header.width;
  645. stream >> context.header.pitch;
  646. stream >> context.header.depth;
  647. stream >> context.header.mip_map_count;
  648. // The bytes in context.header.reserved are unused, so we just skip over them (11 * 4 bytes).
  649. stream.discard_or_error(44);
  650. stream >> context.header.pixel_format.size;
  651. stream >> context.header.pixel_format.flags;
  652. stream >> context.header.pixel_format.four_cc;
  653. stream >> context.header.pixel_format.rgb_bit_count;
  654. stream >> context.header.pixel_format.r_bit_mask;
  655. stream >> context.header.pixel_format.g_bit_mask;
  656. stream >> context.header.pixel_format.b_bit_mask;
  657. stream >> context.header.pixel_format.a_bit_mask;
  658. stream >> context.header.caps1;
  659. stream >> context.header.caps2;
  660. stream >> context.header.caps3;
  661. stream >> context.header.caps4;
  662. stream >> context.header.reserved2;
  663. if (context.header.size != 124) {
  664. dbgln_if(DDS_DEBUG, "Header size is malformed");
  665. context.state = DDSLoadingContext::State::Error;
  666. return false;
  667. }
  668. if (context.header.pixel_format.size != 32) {
  669. dbgln_if(DDS_DEBUG, "Pixel format size is malformed");
  670. context.state = DDSLoadingContext::State::Error;
  671. return false;
  672. }
  673. if ((context.header.pixel_format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC) {
  674. if (context.header.pixel_format.four_cc == create_four_cc('D', 'X', '1', '0')) {
  675. if (stream.bytes().size() < 148) {
  676. dbgln_if(DDS_DEBUG, "DX10 header is too short");
  677. context.state = DDSLoadingContext::State::Error;
  678. return false;
  679. }
  680. u32 format {};
  681. stream >> format;
  682. context.header10.format = static_cast<DXGIFormat>(format);
  683. stream >> context.header10.resource_dimension;
  684. stream >> context.header10.misc_flag;
  685. stream >> context.header10.array_size;
  686. stream >> context.header10.misc_flag2;
  687. }
  688. }
  689. if constexpr (DDS_DEBUG) {
  690. context.dump_debug();
  691. }
  692. DXGIFormat format = get_format(context.header.pixel_format);
  693. Vector<u32> supported_formats = { DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC3_UNORM };
  694. if (!supported_formats.contains_slow(format)) {
  695. dbgln_if(DDS_DEBUG, "Format of type {} is not supported at the moment", static_cast<u32>(format));
  696. context.state = DDSLoadingContext::State::Error;
  697. return false;
  698. }
  699. for (size_t mipmap_level = 0; mipmap_level < max(context.header.mip_map_count, 1u); mipmap_level++) {
  700. u64 width = get_width(context.header, mipmap_level);
  701. u64 height = get_height(context.header, mipmap_level);
  702. u64 needed_bytes = get_minimum_bytes_for_mipmap(format, width, height);
  703. dbgln_if(DDS_DEBUG, "There are {} bytes remaining, we need {} for mipmap level {} of the image", stream.remaining(), needed_bytes, mipmap_level);
  704. VERIFY(stream.remaining() >= needed_bytes);
  705. context.bitmap = Bitmap::create_purgeable(BitmapFormat::BGRA8888, { width, height });
  706. decode_bitmap(stream, context, format, width, height);
  707. // We support parsing mipmaps, but we only care about the largest one :^) (Atleast for now)
  708. break;
  709. }
  710. context.state = DDSLoadingContext::State::BitmapDecoded;
  711. return true;
  712. }
  713. void DDSLoadingContext::dump_debug()
  714. {
  715. StringBuilder builder;
  716. builder.append("\nDDS:\n");
  717. builder.appendff("\tHeader Size: {}\n", header.size);
  718. builder.append("\tFlags:");
  719. if ((header.flags & DDSFlags::DDSD_CAPS) == DDSFlags::DDSD_CAPS)
  720. builder.append(" DDSD_CAPS");
  721. if ((header.flags & DDSFlags::DDSD_HEIGHT) == DDSFlags::DDSD_HEIGHT)
  722. builder.append(" DDSD_HEIGHT");
  723. if ((header.flags & DDSFlags::DDSD_WIDTH) == DDSFlags::DDSD_WIDTH)
  724. builder.append(" DDSD_WIDTH");
  725. if ((header.flags & DDSFlags::DDSD_PITCH) == DDSFlags::DDSD_PITCH)
  726. builder.append(" DDSD_PITCH");
  727. if ((header.flags & DDSFlags::DDSD_PIXELFORMAT) == DDSFlags::DDSD_PIXELFORMAT)
  728. builder.append(" DDSD_PIXELFORMAT");
  729. if ((header.flags & DDSFlags::DDSD_MIPMAPCOUNT) == DDSFlags::DDSD_MIPMAPCOUNT)
  730. builder.append(" DDSD_MIPMAPCOUNT");
  731. if ((header.flags & DDSFlags::DDSD_LINEARSIZE) == DDSFlags::DDSD_LINEARSIZE)
  732. builder.append(" DDSD_LINEARSIZE");
  733. if ((header.flags & DDSFlags::DDSD_DEPTH) == DDSFlags::DDSD_DEPTH)
  734. builder.append(" DDSD_DEPTH");
  735. builder.append("\n");
  736. builder.appendff("\tHeight: {}\n", header.height);
  737. builder.appendff("\tWidth: {}\n", header.width);
  738. builder.appendff("\tPitch: {}\n", header.pitch);
  739. builder.appendff("\tDepth: {}\n", header.depth);
  740. builder.appendff("\tMipmap Count: {}\n", header.mip_map_count);
  741. builder.append("\tCaps:");
  742. if ((header.caps1 & Caps1Flags::DDSCAPS_COMPLEX) == Caps1Flags::DDSCAPS_COMPLEX)
  743. builder.append(" DDSCAPS_COMPLEX");
  744. if ((header.caps1 & Caps1Flags::DDSCAPS_MIPMAP) == Caps1Flags::DDSCAPS_MIPMAP)
  745. builder.append(" DDSCAPS_MIPMAP");
  746. if ((header.caps1 & Caps1Flags::DDSCAPS_TEXTURE) == Caps1Flags::DDSCAPS_TEXTURE)
  747. builder.append(" DDSCAPS_TEXTURE");
  748. builder.append("\n");
  749. builder.append("\tCaps2:");
  750. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP) == Caps2Flags::DDSCAPS2_CUBEMAP)
  751. builder.append(" DDSCAPS2_CUBEMAP");
  752. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEX) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEX)
  753. builder.append(" DDSCAPS2_CUBEMAP_POSITIVEX");
  754. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEX) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEX)
  755. builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEX");
  756. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEY) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEY)
  757. builder.append(" DDSCAPS2_CUBEMAP_POSITIVEY");
  758. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEY) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEY)
  759. builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEY");
  760. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEZ) == Caps2Flags::DDSCAPS2_CUBEMAP_POSITIVEZ)
  761. builder.append(" DDSCAPS2_CUBEMAP_POSITIVEZ");
  762. if ((header.caps2 & Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEZ) == Caps2Flags::DDSCAPS2_CUBEMAP_NEGATIVEZ)
  763. builder.append(" DDSCAPS2_CUBEMAP_NEGATIVEZ");
  764. if ((header.caps2 & Caps2Flags::DDSCAPS2_VOLUME) == Caps2Flags::DDSCAPS2_VOLUME)
  765. builder.append(" DDSCAPS2_VOLUME");
  766. builder.append("\n");
  767. builder.append("Pixel Format:\n");
  768. builder.appendff("\tStruct Size: {}\n", header.pixel_format.size);
  769. builder.append("\tFlags:");
  770. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_ALPHAPIXELS) == PixelFormatFlags::DDPF_ALPHAPIXELS)
  771. builder.append(" DDPF_ALPHAPIXELS");
  772. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_ALPHA) == PixelFormatFlags::DDPF_ALPHA)
  773. builder.append(" DDPF_ALPHA");
  774. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_FOURCC) == PixelFormatFlags::DDPF_FOURCC)
  775. builder.append(" DDPF_FOURCC");
  776. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_PALETTEINDEXED8) == PixelFormatFlags::DDPF_PALETTEINDEXED8)
  777. builder.append(" DDPF_PALETTEINDEXED8");
  778. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_RGB) == PixelFormatFlags::DDPF_RGB)
  779. builder.append(" DDPF_RGB");
  780. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_YUV) == PixelFormatFlags::DDPF_YUV)
  781. builder.append(" DDPF_YUV");
  782. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_LUMINANCE) == PixelFormatFlags::DDPF_LUMINANCE)
  783. builder.append(" DDPF_LUMINANCE");
  784. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_BUMPDUDV) == PixelFormatFlags::DDPF_BUMPDUDV)
  785. builder.append(" DDPF_BUMPDUDV");
  786. if ((header.pixel_format.flags & PixelFormatFlags::DDPF_NORMAL) == PixelFormatFlags::DDPF_NORMAL)
  787. builder.append(" DDPF_NORMAL");
  788. builder.append("\n");
  789. builder.append("\tFour CC: ");
  790. builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 0)) & 0xFF);
  791. builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 1)) & 0xFF);
  792. builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 2)) & 0xFF);
  793. builder.appendff("{:c}", (header.pixel_format.four_cc >> (8 * 3)) & 0xFF);
  794. builder.append("\n");
  795. builder.appendff("\tRGB Bit Count: {}\n", header.pixel_format.rgb_bit_count);
  796. builder.appendff("\tR Bit Mask: {}\n", header.pixel_format.r_bit_mask);
  797. builder.appendff("\tG Bit Mask: {}\n", header.pixel_format.g_bit_mask);
  798. builder.appendff("\tB Bit Mask: {}\n", header.pixel_format.b_bit_mask);
  799. builder.appendff("\tA Bit Mask: {}\n", header.pixel_format.a_bit_mask);
  800. builder.append("DDS10:\n");
  801. builder.appendff("\tFormat: {}\n", static_cast<u32>(header10.format));
  802. builder.append("\tResource Dimension:");
  803. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_UNKNOWN) == ResourceDimensions::DDS_DIMENSION_UNKNOWN)
  804. builder.append(" DDS_DIMENSION_UNKNOWN");
  805. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_BUFFER) == ResourceDimensions::DDS_DIMENSION_BUFFER)
  806. builder.append(" DDS_DIMENSION_BUFFER");
  807. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE1D) == ResourceDimensions::DDS_DIMENSION_TEXTURE1D)
  808. builder.append(" DDS_DIMENSION_TEXTURE1D");
  809. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE2D) == ResourceDimensions::DDS_DIMENSION_TEXTURE2D)
  810. builder.append(" DDS_DIMENSION_TEXTURE2D");
  811. if ((header10.resource_dimension & ResourceDimensions::DDS_DIMENSION_TEXTURE3D) == ResourceDimensions::DDS_DIMENSION_TEXTURE3D)
  812. builder.append(" DDS_DIMENSION_TEXTURE3D");
  813. builder.append("\n");
  814. builder.appendff("\tArray Size: {}\n", header10.array_size);
  815. builder.append("\tMisc Flags:");
  816. if ((header10.misc_flag & MiscFlags::DDS_RESOURCE_MISC_TEXTURECUBE) == MiscFlags::DDS_RESOURCE_MISC_TEXTURECUBE)
  817. builder.append(" DDS_RESOURCE_MISC_TEXTURECUBE");
  818. builder.append("\n");
  819. builder.append("\tMisc Flags 2:");
  820. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_UNKNOWN) == Misc2Flags::DDS_ALPHA_MODE_UNKNOWN)
  821. builder.append(" DDS_ALPHA_MODE_UNKNOWN");
  822. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_STRAIGHT) == Misc2Flags::DDS_ALPHA_MODE_STRAIGHT)
  823. builder.append(" DDS_ALPHA_MODE_STRAIGHT");
  824. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_PREMULTIPLIED) == Misc2Flags::DDS_ALPHA_MODE_PREMULTIPLIED)
  825. builder.append(" DDS_ALPHA_MODE_PREMULTIPLIED");
  826. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_OPAQUE) == Misc2Flags::DDS_ALPHA_MODE_OPAQUE)
  827. builder.append(" DDS_ALPHA_MODE_OPAQUE");
  828. if ((header10.misc_flag2 & Misc2Flags::DDS_ALPHA_MODE_CUSTOM) == Misc2Flags::DDS_ALPHA_MODE_CUSTOM)
  829. builder.append(" DDS_ALPHA_MODE_CUSTOM");
  830. builder.append("\n");
  831. dbgln("{}", builder.to_string());
  832. }
  833. static RefPtr<Gfx::Bitmap> load_dds_impl(const u8* data, size_t length)
  834. {
  835. DDSLoadingContext context;
  836. context.data = data;
  837. context.data_size = length;
  838. if (!decode_dds(context))
  839. return nullptr;
  840. return context.bitmap;
  841. }
  842. RefPtr<Gfx::Bitmap> load_dds(String const& path)
  843. {
  844. auto file_or_error = MappedFile::map(path);
  845. if (file_or_error.is_error())
  846. return nullptr;
  847. auto bitmap = load_dds_impl((const u8*)file_or_error.value()->data(), file_or_error.value()->size());
  848. if (bitmap)
  849. bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded DDS: {}", bitmap->size(), LexicalPath::canonicalized_path(path)));
  850. return bitmap;
  851. }
  852. RefPtr<Gfx::Bitmap> load_dds_from_memory(const u8* data, size_t length)
  853. {
  854. auto bitmap = load_dds_impl(data, length);
  855. if (bitmap)
  856. bitmap->set_mmap_name(String::formatted("Gfx::Bitmap [{}] - Decoded DDS: <memory>", bitmap->size()));
  857. return bitmap;
  858. }
  859. DDSImageDecoderPlugin::DDSImageDecoderPlugin(const u8* data, size_t size)
  860. {
  861. m_context = make<DDSLoadingContext>();
  862. m_context->data = data;
  863. m_context->data_size = size;
  864. }
  865. DDSImageDecoderPlugin::~DDSImageDecoderPlugin()
  866. {
  867. }
  868. IntSize DDSImageDecoderPlugin::size()
  869. {
  870. if (m_context->state == DDSLoadingContext::State::Error)
  871. return {};
  872. if (m_context->state == DDSLoadingContext::State::BitmapDecoded)
  873. return { m_context->header.width, m_context->header.height };
  874. return {};
  875. }
  876. RefPtr<Gfx::Bitmap> DDSImageDecoderPlugin::bitmap()
  877. {
  878. if (m_context->state == DDSLoadingContext::State::Error)
  879. return nullptr;
  880. if (m_context->state < DDSLoadingContext::State::BitmapDecoded) {
  881. bool success = decode_dds(*m_context);
  882. if (!success)
  883. return nullptr;
  884. }
  885. VERIFY(m_context->bitmap);
  886. return m_context->bitmap;
  887. }
  888. void DDSImageDecoderPlugin::set_volatile()
  889. {
  890. if (m_context->bitmap)
  891. m_context->bitmap->set_volatile();
  892. }
  893. bool DDSImageDecoderPlugin::set_nonvolatile()
  894. {
  895. if (!m_context->bitmap)
  896. return false;
  897. return m_context->bitmap->set_nonvolatile();
  898. }
  899. bool DDSImageDecoderPlugin::sniff()
  900. {
  901. // The header is always atleast 128 bytes, so if the file is smaller, it cant be a DDS.
  902. return m_context->data_size > 128
  903. && m_context->data[0] == 0x44
  904. && m_context->data[1] == 0x44
  905. && m_context->data[2] == 0x53
  906. && m_context->data[3] == 0x20;
  907. }
  908. bool DDSImageDecoderPlugin::is_animated()
  909. {
  910. return false;
  911. }
  912. size_t DDSImageDecoderPlugin::loop_count()
  913. {
  914. return 0;
  915. }
  916. size_t DDSImageDecoderPlugin::frame_count()
  917. {
  918. return 1;
  919. }
  920. ImageFrameDescriptor DDSImageDecoderPlugin::frame([[maybe_unused]] size_t i)
  921. {
  922. // We have "frames", but they are all the same image, so lets just use the largest version.
  923. return { bitmap(), 0 };
  924. }
  925. }