DDSLoader.cpp 35 KB

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