ddsparse.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. /**
  2. * Simple DDS data parser for compressed 2D textures.
  3. *
  4. * Copyright (c) 2013-2023 Sasha Szpakowski
  5. *
  6. * This software is provided 'as-is', without any express or implied
  7. * warranty. In no event will the authors be held liable for any damages
  8. * arising from the use of this software.
  9. *
  10. * Permission is granted to anyone to use this software for any purpose,
  11. * including commercial applications, and to alter it and redistribute it
  12. * freely, subject to the following restrictions:
  13. *
  14. * 1. The origin of this software must not be misrepresented; you must not
  15. * claim that you wrote the original software. If you use this software
  16. * in a product, an acknowledgment in the product documentation would be
  17. * appreciated but is not required.
  18. * 2. Altered source versions must be plainly marked as such, and must not be
  19. * misrepresented as being the original software.
  20. * 3. This notice may not be removed or altered from any source distribution.
  21. **/
  22. #include "ddsparse.h"
  23. #include "ddsinfo.h"
  24. #include <algorithm>
  25. namespace dds
  26. {
  27. using namespace dds::dxinfo;
  28. // Creates a packed uint representation of a FourCC code.
  29. #define MakeFourCC(a, b, c, d) ((uint32_t) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a)))
  30. #define ISBITMASK(r,g,b,a) (ddpf.rBitMask == r && ddpf.gBitMask == g && ddpf.bBitMask == b && ddpf.aBitMask == a)
  31. // Function adapted from DirectXTex:
  32. // https://github.com/microsoft/DirectXTex/blob/master/DDSTextureLoader/DDSTextureLoader.cpp#L623
  33. static DXGIFormat getDXGIFormat(const DDSPixelFormat& ddpf)
  34. {
  35. if (ddpf.flags & DDPF_RGB)
  36. {
  37. // Note that sRGB formats are written using the "DX10" extended header
  38. switch (ddpf.rgbBitCount)
  39. {
  40. case 32:
  41. if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))
  42. return DXGI_FORMAT_R8G8B8A8_UNORM;
  43. if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000))
  44. return DXGI_FORMAT_B8G8R8A8_UNORM;
  45. if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000))
  46. return DXGI_FORMAT_B8G8R8X8_UNORM;
  47. // No DXGI format maps to ISBITMASK(0x000000ff,0x0000ff00,0x00ff0000,0x00000000) aka D3DFMT_X8B8G8R8
  48. // Note that many common DDS reader/writers (including D3DX) swap the
  49. // the RED/BLUE masks for 10:10:10:2 formats. We assume
  50. // below that the 'backwards' header mask is being used since it is most
  51. // likely written by D3DX. The more robust solution is to use the 'DX10'
  52. // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly
  53. // For 'correct' writers, this should be 0x000003ff,0x000ffc00,0x3ff00000 for RGB data
  54. if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000))
  55. return DXGI_FORMAT_R10G10B10A2_UNORM;
  56. // No DXGI format maps to ISBITMASK(0x000003ff,0x000ffc00,0x3ff00000,0xc0000000) aka D3DFMT_A2R10G10B10
  57. if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))
  58. return DXGI_FORMAT_R16G16_UNORM;
  59. if (ISBITMASK(0xffffffff, 0x00000000, 0x00000000, 0x00000000))
  60. // Only 32-bit color channel format in D3D9 was R32F
  61. return DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114
  62. break;
  63. case 24:
  64. // No 24bpp DXGI formats aka D3DFMT_R8G8B8
  65. break;
  66. case 16:
  67. if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x8000))
  68. return DXGI_FORMAT_B5G5R5A1_UNORM;
  69. if (ISBITMASK(0xf800, 0x07e0, 0x001f, 0x0000))
  70. return DXGI_FORMAT_B5G6R5_UNORM;
  71. // No DXGI format maps to ISBITMASK(0x7c00,0x03e0,0x001f,0x0000) aka D3DFMT_X1R5G5B5
  72. // No DXGI format maps to ISBITMASK(0x0f00,0x00f0,0x000f,0x0000) aka D3DFMT_X4R4G4B4
  73. // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc.
  74. break;
  75. }
  76. }
  77. else if (ddpf.flags & DDPF_LUMINANCE)
  78. {
  79. if (ddpf.rgbBitCount == 8)
  80. {
  81. if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x00000000))
  82. return DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension
  83. // No DXGI format maps to ISBITMASK(0x0f,0x00,0x00,0xf0) aka D3DFMT_A4L4
  84. if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))
  85. return DXGI_FORMAT_R8G8_UNORM; // Some DDS writers assume the bitcount should be 8 instead of 16
  86. }
  87. if (ddpf.rgbBitCount == 16)
  88. {
  89. if (ISBITMASK(0x0000ffff, 0x00000000, 0x00000000, 0x00000000))
  90. return DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension
  91. if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))
  92. return DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension
  93. }
  94. }
  95. else if (ddpf.flags & DDPF_ALPHA)
  96. {
  97. if (ddpf.rgbBitCount == 8)
  98. return DXGI_FORMAT_A8_UNORM;
  99. }
  100. else if (ddpf.flags & DDPF_BUMPDUDV)
  101. {
  102. if (ddpf.rgbBitCount == 16)
  103. {
  104. if (ISBITMASK(0x00ff, 0xff00, 0x0000, 0x0000))
  105. return DXGI_FORMAT_R8G8_SNORM; // D3DX10/11 writes this out as DX10 extension
  106. }
  107. if (ddpf.rgbBitCount == 32)
  108. {
  109. if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))
  110. return DXGI_FORMAT_R8G8B8A8_SNORM; // D3DX10/11 writes this out as DX10 extension
  111. if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))
  112. return DXGI_FORMAT_R16G16_SNORM; // D3DX10/11 writes this out as DX10 extension
  113. // No DXGI format maps to ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000) aka D3DFMT_A2W10V10U10
  114. }
  115. }
  116. else if (ddpf.flags & DDPF_FOURCC)
  117. {
  118. switch (ddpf.fourCC)
  119. {
  120. case MakeFourCC('D','X','T','1'):
  121. return DXGI_FORMAT_BC1_UNORM;
  122. case MakeFourCC('D','X','T','3'):
  123. return DXGI_FORMAT_BC2_UNORM;
  124. case MakeFourCC('D','X','T','5'):
  125. return DXGI_FORMAT_BC3_UNORM;
  126. // While pre-multiplied alpha isn't directly supported by the DXGI formats,
  127. // they are basically the same as these BC formats so they can be mapped
  128. case MakeFourCC('D','X','T','2'):
  129. return DXGI_FORMAT_BC2_UNORM;
  130. case MakeFourCC('D','X','T','4'):
  131. return DXGI_FORMAT_BC3_UNORM;
  132. case MakeFourCC('A','T','I','1'):
  133. return DXGI_FORMAT_BC4_UNORM;
  134. case MakeFourCC('B','C','4','U'):
  135. return DXGI_FORMAT_BC4_UNORM;
  136. case MakeFourCC('B','C','4','S'):
  137. return DXGI_FORMAT_BC4_SNORM;
  138. case MakeFourCC('A','T','I','2'):
  139. return DXGI_FORMAT_BC5_UNORM;
  140. case MakeFourCC('B','C','5','U'):
  141. return DXGI_FORMAT_BC5_UNORM;
  142. case MakeFourCC('B','C','5','S'):
  143. return DXGI_FORMAT_BC5_SNORM;
  144. // BC6H and BC7 are written using the "DX10" extended header
  145. case MakeFourCC('R','G','B','G'):
  146. return DXGI_FORMAT_R8G8_B8G8_UNORM;
  147. case MakeFourCC('G','R','G','B'):
  148. return DXGI_FORMAT_G8R8_G8B8_UNORM;
  149. // Check for D3DFORMAT enums being set here
  150. case 36: // D3DFMT_A16B16G16R16
  151. return DXGI_FORMAT_R16G16B16A16_UNORM;
  152. case 110: // D3DFMT_Q16W16V16U16
  153. return DXGI_FORMAT_R16G16B16A16_SNORM;
  154. case 111: // D3DFMT_R16F
  155. return DXGI_FORMAT_R16_FLOAT;
  156. case 112: // D3DFMT_G16R16F
  157. return DXGI_FORMAT_R16G16_FLOAT;
  158. case 113: // D3DFMT_A16B16G16R16F
  159. return DXGI_FORMAT_R16G16B16A16_FLOAT;
  160. case 114: // D3DFMT_R32F
  161. return DXGI_FORMAT_R32_FLOAT;
  162. case 115: // D3DFMT_G32R32F
  163. return DXGI_FORMAT_R32G32_FLOAT;
  164. case 116: // D3DFMT_A32B32G32R32F
  165. return DXGI_FORMAT_R32G32B32A32_FLOAT;
  166. }
  167. }
  168. return DXGI_FORMAT_UNKNOWN;
  169. }
  170. static size_t getBitsPerPixel(DXGIFormat fmt)
  171. {
  172. switch (fmt)
  173. {
  174. case DXGI_FORMAT_R32G32B32A32_TYPELESS:
  175. case DXGI_FORMAT_R32G32B32A32_FLOAT:
  176. case DXGI_FORMAT_R32G32B32A32_UINT:
  177. case DXGI_FORMAT_R32G32B32A32_SINT:
  178. return 128;
  179. case DXGI_FORMAT_R32G32B32_TYPELESS:
  180. case DXGI_FORMAT_R32G32B32_FLOAT:
  181. case DXGI_FORMAT_R32G32B32_UINT:
  182. case DXGI_FORMAT_R32G32B32_SINT:
  183. return 96;
  184. case DXGI_FORMAT_R16G16B16A16_TYPELESS:
  185. case DXGI_FORMAT_R16G16B16A16_FLOAT:
  186. case DXGI_FORMAT_R16G16B16A16_UNORM:
  187. case DXGI_FORMAT_R16G16B16A16_UINT:
  188. case DXGI_FORMAT_R16G16B16A16_SNORM:
  189. case DXGI_FORMAT_R16G16B16A16_SINT:
  190. case DXGI_FORMAT_R32G32_TYPELESS:
  191. case DXGI_FORMAT_R32G32_FLOAT:
  192. case DXGI_FORMAT_R32G32_UINT:
  193. case DXGI_FORMAT_R32G32_SINT:
  194. case DXGI_FORMAT_R32G8X24_TYPELESS:
  195. case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
  196. case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
  197. case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
  198. return 64;
  199. case DXGI_FORMAT_R10G10B10A2_TYPELESS:
  200. case DXGI_FORMAT_R10G10B10A2_UNORM:
  201. case DXGI_FORMAT_R10G10B10A2_UINT:
  202. case DXGI_FORMAT_R11G11B10_FLOAT:
  203. case DXGI_FORMAT_R8G8B8A8_TYPELESS:
  204. case DXGI_FORMAT_R8G8B8A8_UNORM:
  205. case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
  206. case DXGI_FORMAT_R8G8B8A8_UINT:
  207. case DXGI_FORMAT_R8G8B8A8_SNORM:
  208. case DXGI_FORMAT_R8G8B8A8_SINT:
  209. case DXGI_FORMAT_R16G16_TYPELESS:
  210. case DXGI_FORMAT_R16G16_FLOAT:
  211. case DXGI_FORMAT_R16G16_UNORM:
  212. case DXGI_FORMAT_R16G16_UINT:
  213. case DXGI_FORMAT_R16G16_SNORM:
  214. case DXGI_FORMAT_R16G16_SINT:
  215. case DXGI_FORMAT_R32_TYPELESS:
  216. case DXGI_FORMAT_D32_FLOAT:
  217. case DXGI_FORMAT_R32_FLOAT:
  218. case DXGI_FORMAT_R32_UINT:
  219. case DXGI_FORMAT_R32_SINT:
  220. case DXGI_FORMAT_R24G8_TYPELESS:
  221. case DXGI_FORMAT_D24_UNORM_S8_UINT:
  222. case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
  223. case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
  224. case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
  225. case DXGI_FORMAT_R8G8_B8G8_UNORM:
  226. case DXGI_FORMAT_G8R8_G8B8_UNORM:
  227. case DXGI_FORMAT_B8G8R8A8_UNORM:
  228. case DXGI_FORMAT_B8G8R8X8_UNORM:
  229. case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
  230. case DXGI_FORMAT_B8G8R8A8_TYPELESS:
  231. case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
  232. case DXGI_FORMAT_B8G8R8X8_TYPELESS:
  233. case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
  234. return 32;
  235. case DXGI_FORMAT_R8G8_TYPELESS:
  236. case DXGI_FORMAT_R8G8_UNORM:
  237. case DXGI_FORMAT_R8G8_UINT:
  238. case DXGI_FORMAT_R8G8_SNORM:
  239. case DXGI_FORMAT_R8G8_SINT:
  240. case DXGI_FORMAT_R16_TYPELESS:
  241. case DXGI_FORMAT_R16_FLOAT:
  242. case DXGI_FORMAT_D16_UNORM:
  243. case DXGI_FORMAT_R16_UNORM:
  244. case DXGI_FORMAT_R16_UINT:
  245. case DXGI_FORMAT_R16_SNORM:
  246. case DXGI_FORMAT_R16_SINT:
  247. case DXGI_FORMAT_B5G6R5_UNORM:
  248. case DXGI_FORMAT_B5G5R5A1_UNORM:
  249. return 16;
  250. case DXGI_FORMAT_R8_TYPELESS:
  251. case DXGI_FORMAT_R8_UNORM:
  252. case DXGI_FORMAT_R8_UINT:
  253. case DXGI_FORMAT_R8_SNORM:
  254. case DXGI_FORMAT_R8_SINT:
  255. case DXGI_FORMAT_A8_UNORM:
  256. return 8;
  257. case DXGI_FORMAT_R1_UNORM:
  258. return 1;
  259. case DXGI_FORMAT_BC1_TYPELESS:
  260. case DXGI_FORMAT_BC1_UNORM:
  261. case DXGI_FORMAT_BC1_UNORM_SRGB:
  262. case DXGI_FORMAT_BC4_TYPELESS:
  263. case DXGI_FORMAT_BC4_UNORM:
  264. case DXGI_FORMAT_BC4_SNORM:
  265. return 4;
  266. case DXGI_FORMAT_BC2_TYPELESS:
  267. case DXGI_FORMAT_BC2_UNORM:
  268. case DXGI_FORMAT_BC2_UNORM_SRGB:
  269. case DXGI_FORMAT_BC3_TYPELESS:
  270. case DXGI_FORMAT_BC3_UNORM:
  271. case DXGI_FORMAT_BC3_UNORM_SRGB:
  272. case DXGI_FORMAT_BC5_TYPELESS:
  273. case DXGI_FORMAT_BC5_UNORM:
  274. case DXGI_FORMAT_BC5_SNORM:
  275. case DXGI_FORMAT_BC6H_TYPELESS:
  276. case DXGI_FORMAT_BC6H_UF16:
  277. case DXGI_FORMAT_BC6H_SF16:
  278. case DXGI_FORMAT_BC7_TYPELESS:
  279. case DXGI_FORMAT_BC7_UNORM:
  280. case DXGI_FORMAT_BC7_UNORM_SRGB:
  281. return 8;
  282. default:
  283. return 0;
  284. }
  285. }
  286. static bool isBlockCompressed(DXGIFormat fmt)
  287. {
  288. switch (fmt)
  289. {
  290. case DXGI_FORMAT_BC1_TYPELESS:
  291. case DXGI_FORMAT_BC1_UNORM:
  292. case DXGI_FORMAT_BC1_UNORM_SRGB:
  293. case DXGI_FORMAT_BC4_TYPELESS:
  294. case DXGI_FORMAT_BC4_UNORM:
  295. case DXGI_FORMAT_BC4_SNORM:
  296. case DXGI_FORMAT_BC2_TYPELESS:
  297. case DXGI_FORMAT_BC2_UNORM:
  298. case DXGI_FORMAT_BC2_UNORM_SRGB:
  299. case DXGI_FORMAT_BC3_TYPELESS:
  300. case DXGI_FORMAT_BC3_UNORM:
  301. case DXGI_FORMAT_BC3_UNORM_SRGB:
  302. case DXGI_FORMAT_BC5_TYPELESS:
  303. case DXGI_FORMAT_BC5_UNORM:
  304. case DXGI_FORMAT_BC5_SNORM:
  305. case DXGI_FORMAT_BC6H_TYPELESS:
  306. case DXGI_FORMAT_BC6H_UF16:
  307. case DXGI_FORMAT_BC6H_SF16:
  308. case DXGI_FORMAT_BC7_TYPELESS:
  309. case DXGI_FORMAT_BC7_UNORM:
  310. case DXGI_FORMAT_BC7_UNORM_SRGB:
  311. return true;
  312. default:
  313. return false;
  314. }
  315. }
  316. bool isDDS(const void *data, size_t dataSize)
  317. {
  318. const uint8_t *readData = (const uint8_t *) data;
  319. ptrdiff_t offset = 0;
  320. // Is the data large enough to hold the DDS header?
  321. if(dataSize < sizeof(uint32_t) + sizeof(DDSHeader))
  322. return false;
  323. // All DDS files start with "DDS ".
  324. if((*(uint32_t *) readData) != MakeFourCC('D','D','S',' '))
  325. return false;
  326. offset += sizeof(uint32_t);
  327. DDSHeader *header = (DDSHeader *) &readData[offset];
  328. // Verify header to validate DDS data.
  329. if (header->size != sizeof(DDSHeader) || header->format.size != sizeof(DDSPixelFormat))
  330. return false;
  331. offset += sizeof(DDSHeader);
  332. // Check for DX10 extension.
  333. if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == MakeFourCC('D','X','1','0')))
  334. {
  335. // Data must be big enough for both headers plus the magic value.
  336. if (dataSize < (sizeof(uint32_t) + sizeof(DDSHeader) + sizeof(DDSHeader10)))
  337. return false;
  338. }
  339. return true;
  340. }
  341. DXGIFormat getDDSPixelFormat(const void *data, size_t dataSize)
  342. {
  343. if (!isDDS(data, dataSize))
  344. return DXGI_FORMAT_UNKNOWN;
  345. const uint8_t *readData = (const uint8_t *) data;
  346. ptrdiff_t offset = sizeof(uint32_t);
  347. DDSHeader *header = (DDSHeader *) &readData[offset];
  348. offset += sizeof(DDSHeader);
  349. // Check for DX10 extension.
  350. if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == MakeFourCC('D','X','1','0')))
  351. {
  352. DDSHeader10 *header10 = (DDSHeader10 *) &readData[offset];
  353. return header10->dxgiFormat;
  354. }
  355. return getDXGIFormat(header->format);
  356. }
  357. bool isCompressedDDS(const void *data, size_t dataSize)
  358. {
  359. DXGIFormat format = getDDSPixelFormat(data, dataSize);
  360. return format != DXGI_FORMAT_UNKNOWN && isBlockCompressed(format);
  361. }
  362. Parser::Parser(const void *data, size_t dataSize)
  363. : format(DXGI_FORMAT_UNKNOWN)
  364. {
  365. parseData(data, dataSize);
  366. }
  367. Parser::Parser(const Parser &other)
  368. : texData(other.texData)
  369. , format(other.format)
  370. {
  371. }
  372. Parser::Parser()
  373. : format(DXGI_FORMAT_UNKNOWN)
  374. {
  375. }
  376. Parser &Parser::operator = (const Parser &other)
  377. {
  378. texData = other.texData;
  379. format = other.format;
  380. return *this;
  381. }
  382. Parser::~Parser()
  383. {
  384. }
  385. DXGIFormat Parser::getFormat() const
  386. {
  387. return format;
  388. }
  389. const Image *Parser::getImageData(size_t miplevel) const
  390. {
  391. if (miplevel >= texData.size())
  392. return 0;
  393. return &texData[miplevel];
  394. }
  395. size_t Parser::getMipmapCount() const
  396. {
  397. return texData.size();
  398. }
  399. size_t Parser::parseImageSize(DXGIFormat fmt, int width, int height) const
  400. {
  401. size_t bytes = 0;
  402. size_t bytesPerBlock = 0;
  403. bool packed = false;
  404. bool blockCompressed = false;
  405. switch (fmt)
  406. {
  407. case DXGI_FORMAT_BC1_TYPELESS:
  408. case DXGI_FORMAT_BC1_UNORM:
  409. case DXGI_FORMAT_BC1_UNORM_SRGB:
  410. case DXGI_FORMAT_BC4_TYPELESS:
  411. case DXGI_FORMAT_BC4_UNORM:
  412. case DXGI_FORMAT_BC4_SNORM:
  413. blockCompressed = true;
  414. bytesPerBlock = 8;
  415. break;
  416. case DXGI_FORMAT_BC2_TYPELESS:
  417. case DXGI_FORMAT_BC2_UNORM:
  418. case DXGI_FORMAT_BC2_UNORM_SRGB:
  419. case DXGI_FORMAT_BC3_TYPELESS:
  420. case DXGI_FORMAT_BC3_UNORM:
  421. case DXGI_FORMAT_BC3_UNORM_SRGB:
  422. case DXGI_FORMAT_BC5_TYPELESS:
  423. case DXGI_FORMAT_BC5_UNORM:
  424. case DXGI_FORMAT_BC5_SNORM:
  425. case DXGI_FORMAT_BC6H_TYPELESS:
  426. case DXGI_FORMAT_BC6H_UF16:
  427. case DXGI_FORMAT_BC6H_SF16:
  428. case DXGI_FORMAT_BC7_TYPELESS:
  429. case DXGI_FORMAT_BC7_UNORM:
  430. case DXGI_FORMAT_BC7_UNORM_SRGB:
  431. blockCompressed = true;
  432. bytesPerBlock = 16;
  433. break;
  434. case DXGI_FORMAT_R8G8_B8G8_UNORM:
  435. case DXGI_FORMAT_G8R8_G8B8_UNORM:
  436. packed = true;
  437. bytesPerBlock = 4;
  438. break;
  439. default:
  440. break;
  441. }
  442. if (packed)
  443. {
  444. size_t rowBytes = (((size_t) width + 1u) >> 1) * bytesPerBlock;
  445. bytes = rowBytes * height;
  446. }
  447. else if (blockCompressed)
  448. {
  449. size_t numBlocksWide = width > 0 ? std::max(1, (width + 3) / 4) : 0;
  450. size_t numBlocksHigh = height > 0 ? std::max(1, (height + 3) / 4) : 0;
  451. bytes = numBlocksWide * bytesPerBlock * numBlocksHigh;
  452. }
  453. else
  454. {
  455. size_t bpp = getBitsPerPixel(fmt);
  456. if (bpp == 0)
  457. return 0;
  458. // Round up to the nearest byte.
  459. size_t rowBytes = ((size_t) width * bpp + 7u) / 8u;
  460. bytes = rowBytes * height;
  461. }
  462. return bytes;
  463. }
  464. bool Parser::parseTexData(const uint8_t *data, size_t dataSize, DXGIFormat fmt, int w, int h, int nb_mips)
  465. {
  466. size_t offset = 0;
  467. std::vector<Image> newTexData;
  468. for (int i = 0; i < nb_mips; i++)
  469. {
  470. Image img;
  471. img.width = w;
  472. img.height = h;
  473. img.dataSize = parseImageSize(fmt, img.width, img.height);
  474. // Make sure the data size is valid.
  475. if (img.dataSize == 0 || (offset + img.dataSize) > dataSize)
  476. return false;
  477. // Store the memory address of the data representing this mip level.
  478. img.data = &data[offset];
  479. newTexData.push_back(img);
  480. // Move to the next mip level.
  481. offset += img.dataSize;
  482. w = std::max(w / 2, 1);
  483. h = std::max(h / 2, 1);
  484. }
  485. texData = newTexData;
  486. return true;
  487. }
  488. bool Parser::parseData(const void *data, size_t dataSize)
  489. {
  490. if (!isDDS(data, dataSize))
  491. return false;
  492. const uint8_t *readData = (const uint8_t *) data;
  493. ptrdiff_t offset = sizeof(uint32_t);
  494. DDSHeader *header = (DDSHeader *) &readData[offset];
  495. offset += sizeof(DDSHeader);
  496. // Check for DX10 extension.
  497. if ((header->format.flags & DDPF_FOURCC) && (header->format.fourCC == MakeFourCC('D','X','1','0')))
  498. {
  499. DDSHeader10 *header10 = (DDSHeader10 *) &readData[offset];
  500. offset += sizeof(DDSHeader10);
  501. // We can't deal with 1D/3D textures.
  502. switch (header10->resourceDimension)
  503. {
  504. case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
  505. case D3D10_RESOURCE_DIMENSION_UNKNOWN:
  506. break;
  507. default:
  508. return false;
  509. }
  510. // We also can't deal with texture arrays and cubemaps.
  511. if (header10->arraySize > 1)
  512. return false;
  513. format = header10->dxgiFormat;
  514. }
  515. else
  516. format = getDXGIFormat(header->format);
  517. if (format == DXGI_FORMAT_UNKNOWN)
  518. return false;
  519. int w = header->width;
  520. int h = header->height;
  521. int nb_mips = std::max((int) header->mipMapCount, 1);
  522. return parseTexData(&readData[offset], dataSize - offset, format, w, h, nb_mips);
  523. }
  524. } // dds