crn_ktx_texture.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. // File: crn_ktx_texture.cpp
  2. #include "crn_core.h"
  3. #include "crn_ktx_texture.h"
  4. #include "crn_console.h"
  5. // Set #if CRNLIB_KTX_PVRTEX_WORKAROUNDS to 1 to enable various workarounds for oddball KTX files written by PVRTexTool.
  6. #define CRNLIB_KTX_PVRTEX_WORKAROUNDS 1
  7. namespace crnlib
  8. {
  9. const uint8 s_ktx_file_id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
  10. bool is_packed_pixel_ogl_type(uint32 ogl_type)
  11. {
  12. switch (ogl_type)
  13. {
  14. case KTX_UNSIGNED_BYTE_3_3_2:
  15. case KTX_UNSIGNED_BYTE_2_3_3_REV:
  16. case KTX_UNSIGNED_SHORT_5_6_5:
  17. case KTX_UNSIGNED_SHORT_5_6_5_REV:
  18. case KTX_UNSIGNED_SHORT_4_4_4_4:
  19. case KTX_UNSIGNED_SHORT_4_4_4_4_REV:
  20. case KTX_UNSIGNED_SHORT_5_5_5_1:
  21. case KTX_UNSIGNED_SHORT_1_5_5_5_REV:
  22. case KTX_UNSIGNED_INT_8_8_8_8:
  23. case KTX_UNSIGNED_INT_8_8_8_8_REV:
  24. case KTX_UNSIGNED_INT_10_10_10_2:
  25. case KTX_UNSIGNED_INT_2_10_10_10_REV:
  26. case KTX_UNSIGNED_INT_24_8:
  27. case KTX_UNSIGNED_INT_10F_11F_11F_REV:
  28. case KTX_UNSIGNED_INT_5_9_9_9_REV:
  29. return true;
  30. }
  31. return false;
  32. }
  33. uint get_ogl_type_size(uint32 ogl_type)
  34. {
  35. switch (ogl_type)
  36. {
  37. case KTX_UNSIGNED_BYTE:
  38. case KTX_BYTE:
  39. return 1;
  40. case KTX_HALF_FLOAT:
  41. case KTX_UNSIGNED_SHORT:
  42. case KTX_SHORT:
  43. return 2;
  44. case KTX_FLOAT:
  45. case KTX_UNSIGNED_INT:
  46. case KTX_INT:
  47. return 4;
  48. case KTX_UNSIGNED_BYTE_3_3_2:
  49. case KTX_UNSIGNED_BYTE_2_3_3_REV:
  50. return 1;
  51. case KTX_UNSIGNED_SHORT_5_6_5:
  52. case KTX_UNSIGNED_SHORT_5_6_5_REV:
  53. case KTX_UNSIGNED_SHORT_4_4_4_4:
  54. case KTX_UNSIGNED_SHORT_4_4_4_4_REV:
  55. case KTX_UNSIGNED_SHORT_5_5_5_1:
  56. case KTX_UNSIGNED_SHORT_1_5_5_5_REV:
  57. return 2;
  58. case KTX_UNSIGNED_INT_8_8_8_8:
  59. case KTX_UNSIGNED_INT_8_8_8_8_REV:
  60. case KTX_UNSIGNED_INT_10_10_10_2:
  61. case KTX_UNSIGNED_INT_2_10_10_10_REV:
  62. case KTX_UNSIGNED_INT_24_8:
  63. case KTX_UNSIGNED_INT_10F_11F_11F_REV:
  64. case KTX_UNSIGNED_INT_5_9_9_9_REV:
  65. return 4;
  66. }
  67. return 0;
  68. }
  69. uint32 get_ogl_base_internal_fmt(uint32 ogl_fmt)
  70. {
  71. switch (ogl_fmt)
  72. {
  73. case KTX_ETC1_RGB8_OES:
  74. case KTX_RGB_S3TC:
  75. case KTX_RGB4_S3TC:
  76. case KTX_COMPRESSED_RGB_S3TC_DXT1_EXT:
  77. case KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT:
  78. return KTX_RGB;
  79. case KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  80. case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
  81. case KTX_RGBA_S3TC:
  82. case KTX_RGBA4_S3TC:
  83. case KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  84. case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
  85. case KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  86. case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
  87. case KTX_RGBA_DXT5_S3TC:
  88. case KTX_RGBA4_DXT5_S3TC:
  89. return KTX_RGBA;
  90. case 1:
  91. case KTX_RED:
  92. case KTX_RED_INTEGER:
  93. case KTX_GREEN:
  94. case KTX_GREEN_INTEGER:
  95. case KTX_BLUE:
  96. case KTX_BLUE_INTEGER:
  97. case KTX_R8:
  98. case KTX_R8UI:
  99. case KTX_LUMINANCE8:
  100. case KTX_ALPHA:
  101. case KTX_LUMINANCE:
  102. case KTX_COMPRESSED_RED_RGTC1_EXT:
  103. case KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT:
  104. case KTX_COMPRESSED_LUMINANCE_LATC1_EXT:
  105. case KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
  106. return KTX_RED;
  107. case 2:
  108. case KTX_RG:
  109. case KTX_RG8:
  110. case KTX_RG_INTEGER:
  111. case KTX_LUMINANCE_ALPHA:
  112. case KTX_COMPRESSED_RED_GREEN_RGTC2_EXT:
  113. case KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
  114. case KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
  115. case KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
  116. return KTX_RG;
  117. case 3:
  118. case KTX_SRGB:
  119. case KTX_RGB:
  120. case KTX_RGB_INTEGER:
  121. case KTX_BGR:
  122. case KTX_BGR_INTEGER:
  123. case KTX_RGB8:
  124. case KTX_SRGB8:
  125. return KTX_RGB;
  126. case 4:
  127. case KTX_RGBA:
  128. case KTX_BGRA:
  129. case KTX_RGBA_INTEGER:
  130. case KTX_BGRA_INTEGER:
  131. case KTX_SRGB_ALPHA:
  132. case KTX_SRGB8_ALPHA8:
  133. case KTX_RGBA8:
  134. return KTX_RGBA;
  135. }
  136. return 0;
  137. }
  138. bool get_ogl_fmt_desc(uint32 ogl_fmt, uint32 ogl_type, uint& block_dim, uint& bytes_per_block)
  139. {
  140. uint ogl_type_size = get_ogl_type_size(ogl_type);
  141. block_dim = 1;
  142. bytes_per_block = 0;
  143. switch (ogl_fmt)
  144. {
  145. case KTX_COMPRESSED_RED_RGTC1_EXT:
  146. case KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT:
  147. case KTX_COMPRESSED_LUMINANCE_LATC1_EXT:
  148. case KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
  149. case KTX_ETC1_RGB8_OES:
  150. case KTX_RGB_S3TC:
  151. case KTX_RGB4_S3TC:
  152. case KTX_COMPRESSED_RGB_S3TC_DXT1_EXT:
  153. case KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  154. case KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT:
  155. case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
  156. {
  157. block_dim = 4;
  158. bytes_per_block = 8;
  159. break;
  160. }
  161. case KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
  162. case KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
  163. case KTX_COMPRESSED_RED_GREEN_RGTC2_EXT:
  164. case KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
  165. case KTX_RGBA_S3TC:
  166. case KTX_RGBA4_S3TC:
  167. case KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  168. case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
  169. case KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  170. case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
  171. case KTX_RGBA_DXT5_S3TC:
  172. case KTX_RGBA4_DXT5_S3TC:
  173. {
  174. block_dim = 4;
  175. bytes_per_block = 16;
  176. break;
  177. }
  178. case 1:
  179. case KTX_ALPHA:
  180. case KTX_RED:
  181. case KTX_GREEN:
  182. case KTX_BLUE:
  183. case KTX_RED_INTEGER:
  184. case KTX_GREEN_INTEGER:
  185. case KTX_BLUE_INTEGER:
  186. case KTX_LUMINANCE:
  187. {
  188. bytes_per_block = ogl_type_size;
  189. break;
  190. }
  191. case KTX_R8:
  192. case KTX_R8UI:
  193. case KTX_ALPHA8:
  194. case KTX_LUMINANCE8:
  195. {
  196. bytes_per_block = 1;
  197. break;
  198. }
  199. case 2:
  200. case KTX_RG:
  201. case KTX_RG_INTEGER:
  202. case KTX_LUMINANCE_ALPHA:
  203. {
  204. bytes_per_block = 2 * ogl_type_size;
  205. break;
  206. }
  207. case KTX_RG8:
  208. case KTX_LUMINANCE8_ALPHA8:
  209. {
  210. bytes_per_block = 2;
  211. break;
  212. }
  213. case 3:
  214. case KTX_SRGB:
  215. case KTX_RGB:
  216. case KTX_BGR:
  217. case KTX_RGB_INTEGER:
  218. case KTX_BGR_INTEGER:
  219. {
  220. bytes_per_block = is_packed_pixel_ogl_type(ogl_type) ? ogl_type_size : (3 * ogl_type_size);
  221. break;
  222. }
  223. case KTX_RGB8:
  224. case KTX_SRGB8:
  225. {
  226. bytes_per_block = 3;
  227. break;
  228. }
  229. case 4:
  230. case KTX_RGBA:
  231. case KTX_BGRA:
  232. case KTX_RGBA_INTEGER:
  233. case KTX_BGRA_INTEGER:
  234. case KTX_SRGB_ALPHA:
  235. {
  236. bytes_per_block = is_packed_pixel_ogl_type(ogl_type) ? ogl_type_size : (4 * ogl_type_size);
  237. break;
  238. }
  239. case KTX_SRGB8_ALPHA8:
  240. case KTX_RGBA8:
  241. {
  242. bytes_per_block = 4;
  243. break;
  244. }
  245. default:
  246. return false;
  247. }
  248. return true;
  249. }
  250. bool ktx_texture::compute_pixel_info()
  251. {
  252. if ((!m_header.m_glType) || (!m_header.m_glFormat))
  253. {
  254. if ((m_header.m_glType) || (m_header.m_glFormat))
  255. return false;
  256. // Must be a compressed format.
  257. if (!get_ogl_fmt_desc(m_header.m_glInternalFormat, m_header.m_glType, m_block_dim, m_bytes_per_block))
  258. {
  259. #if CRNLIB_KTX_PVRTEX_WORKAROUNDS
  260. if ((!m_header.m_glInternalFormat) && (!m_header.m_glType) && (!m_header.m_glTypeSize) && (!m_header.m_glBaseInternalFormat))
  261. {
  262. // PVRTexTool writes bogus headers when outputting ETC1.
  263. console::warning("ktx_texture::compute_pixel_info: Header doesn't specify any format, assuming ETC1 and hoping for the best");
  264. m_header.m_glBaseInternalFormat = KTX_RGB;
  265. m_header.m_glInternalFormat = KTX_ETC1_RGB8_OES;
  266. m_header.m_glTypeSize = 1;
  267. m_block_dim = 4;
  268. m_bytes_per_block = 8;
  269. return true;
  270. }
  271. #endif
  272. return false;
  273. }
  274. if (m_block_dim == 1)
  275. return false;
  276. }
  277. else
  278. {
  279. // Must be an uncompressed format.
  280. if (!get_ogl_fmt_desc(m_header.m_glFormat, m_header.m_glType, m_block_dim, m_bytes_per_block))
  281. return false;
  282. if (m_block_dim > 1)
  283. return false;
  284. }
  285. return true;
  286. }
  287. bool ktx_texture::read_from_stream(data_stream_serializer& serializer)
  288. {
  289. clear();
  290. // Read header
  291. if (serializer.read(&m_header, 1, sizeof(m_header)) != sizeof(ktx_header))
  292. return false;
  293. // Check header
  294. if (memcmp(s_ktx_file_id, m_header.m_identifier, sizeof(m_header.m_identifier)))
  295. return false;
  296. if ((m_header.m_endianness != KTX_OPPOSITE_ENDIAN) && (m_header.m_endianness != KTX_ENDIAN))
  297. return false;
  298. m_opposite_endianness = (m_header.m_endianness == KTX_OPPOSITE_ENDIAN);
  299. if (m_opposite_endianness)
  300. {
  301. m_header.endian_swap();
  302. if ((m_header.m_glTypeSize != sizeof(uint8)) && (m_header.m_glTypeSize != sizeof(uint16)) && (m_header.m_glTypeSize != sizeof(uint32)))
  303. return false;
  304. }
  305. if (!check_header())
  306. return false;
  307. if (!compute_pixel_info())
  308. return false;
  309. uint8 pad_bytes[3];
  310. // Read the key value entries
  311. uint num_key_value_bytes_remaining = m_header.m_bytesOfKeyValueData;
  312. while (num_key_value_bytes_remaining)
  313. {
  314. if (num_key_value_bytes_remaining < sizeof(uint32))
  315. return false;
  316. uint32 key_value_byte_size;
  317. if (serializer.read(&key_value_byte_size, 1, sizeof(uint32)) != sizeof(uint32))
  318. return false;
  319. num_key_value_bytes_remaining -= sizeof(uint32);
  320. if (m_opposite_endianness)
  321. key_value_byte_size = utils::swap32(key_value_byte_size);
  322. if (key_value_byte_size > num_key_value_bytes_remaining)
  323. return false;
  324. uint8_vec key_value_data;
  325. if (key_value_byte_size)
  326. {
  327. key_value_data.resize(key_value_byte_size);
  328. if (serializer.read(&key_value_data[0], 1, key_value_byte_size) != key_value_byte_size)
  329. return false;
  330. }
  331. m_key_values.push_back(key_value_data);
  332. uint padding = 3 - ((key_value_byte_size + 3) % 4);
  333. if (padding)
  334. {
  335. if (serializer.read(pad_bytes, 1, padding) != padding)
  336. return false;
  337. }
  338. num_key_value_bytes_remaining -= key_value_byte_size;
  339. if (num_key_value_bytes_remaining < padding)
  340. return false;
  341. num_key_value_bytes_remaining -= padding;
  342. }
  343. // Now read the mip levels
  344. uint total_faces = get_num_mips() * get_array_size() * get_num_faces() * get_depth();
  345. if ((!total_faces) || (total_faces > 65535))
  346. return false;
  347. // See Section 2.8 of KTX file format: No rounding to block sizes should be applied for block compressed textures.
  348. // OK, I'm going to break that rule otherwise KTX can only store a subset of textures that DDS can handle for no good reason.
  349. #if 0
  350. const uint mip0_row_blocks = m_header.m_pixelWidth / m_block_dim;
  351. const uint mip0_col_blocks = CRNLIB_MAX(1, m_header.m_pixelHeight) / m_block_dim;
  352. #else
  353. const uint mip0_row_blocks = (m_header.m_pixelWidth + m_block_dim - 1) / m_block_dim;
  354. const uint mip0_col_blocks = (CRNLIB_MAX(1, m_header.m_pixelHeight) + m_block_dim - 1) / m_block_dim;
  355. #endif
  356. if ((!mip0_row_blocks) || (!mip0_col_blocks))
  357. return false;
  358. const uint mip0_depth = CRNLIB_MAX(1, m_header.m_pixelDepth); mip0_depth;
  359. bool has_valid_image_size_fields = true;
  360. bool disable_mip_and_cubemap_padding = false;
  361. #if CRNLIB_KTX_PVRTEX_WORKAROUNDS
  362. {
  363. // PVRTexTool has a bogus KTX writer that doesn't write any imageSize fields. Nice.
  364. size_t expected_bytes_remaining = 0;
  365. for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++)
  366. {
  367. uint mip_width, mip_height, mip_depth;
  368. get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
  369. const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
  370. const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
  371. if ((!mip_row_blocks) || (!mip_col_blocks))
  372. return false;
  373. expected_bytes_remaining += sizeof(uint32);
  374. if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6))
  375. {
  376. for (uint face = 0; face < get_num_faces(); face++)
  377. {
  378. uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
  379. expected_bytes_remaining += slice_size;
  380. uint num_cube_pad_bytes = 3 - ((slice_size + 3) % 4);
  381. expected_bytes_remaining += num_cube_pad_bytes;
  382. }
  383. }
  384. else
  385. {
  386. uint total_mip_size = 0;
  387. for (uint array_element = 0; array_element < get_array_size(); array_element++)
  388. {
  389. for (uint face = 0; face < get_num_faces(); face++)
  390. {
  391. for (uint zslice = 0; zslice < mip_depth; zslice++)
  392. {
  393. uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
  394. total_mip_size += slice_size;
  395. }
  396. }
  397. }
  398. expected_bytes_remaining += total_mip_size;
  399. uint num_mip_pad_bytes = 3 - ((total_mip_size + 3) % 4);
  400. expected_bytes_remaining += num_mip_pad_bytes;
  401. }
  402. }
  403. if (serializer.get_stream()->get_remaining() < expected_bytes_remaining)
  404. {
  405. has_valid_image_size_fields = false;
  406. disable_mip_and_cubemap_padding = true;
  407. console::warning("ktx_texture::read_from_stream: KTX file size is smaller than expected - trying to read anyway without imageSize fields");
  408. }
  409. }
  410. #endif
  411. for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++)
  412. {
  413. uint mip_width, mip_height, mip_depth;
  414. get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
  415. const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
  416. const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
  417. if ((!mip_row_blocks) || (!mip_col_blocks))
  418. return false;
  419. uint32 image_size = 0;
  420. if (!has_valid_image_size_fields)
  421. image_size = mip_depth * mip_row_blocks * mip_col_blocks * m_bytes_per_block * get_array_size() * get_num_faces();
  422. else
  423. {
  424. if (serializer.read(&image_size, 1, sizeof(image_size)) != sizeof(image_size))
  425. return false;
  426. if (m_opposite_endianness)
  427. image_size = utils::swap32(image_size);
  428. }
  429. if (!image_size)
  430. return false;
  431. uint total_mip_size = 0;
  432. if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6))
  433. {
  434. // plain non-array cubemap
  435. for (uint face = 0; face < get_num_faces(); face++)
  436. {
  437. CRNLIB_ASSERT(m_image_data.size() == get_image_index(mip_level, 0, face, 0));
  438. m_image_data.push_back(uint8_vec());
  439. uint8_vec& image_data = m_image_data.back();
  440. image_data.resize(image_size);
  441. if (serializer.read(&image_data[0], 1, image_size) != image_size)
  442. return false;
  443. if (m_opposite_endianness)
  444. utils::endian_swap_mem(&image_data[0], image_size, m_header.m_glTypeSize);
  445. uint num_cube_pad_bytes = disable_mip_and_cubemap_padding ? 0 : (3 - ((image_size + 3) % 4));
  446. if (serializer.read(pad_bytes, 1, num_cube_pad_bytes) != num_cube_pad_bytes)
  447. return false;
  448. total_mip_size += image_size + num_cube_pad_bytes;
  449. }
  450. }
  451. else
  452. {
  453. // 1D, 2D, 3D (normal or array texture), or array cubemap
  454. uint num_image_bytes_remaining = image_size;
  455. for (uint array_element = 0; array_element < get_array_size(); array_element++)
  456. {
  457. for (uint face = 0; face < get_num_faces(); face++)
  458. {
  459. for (uint zslice = 0; zslice < mip_depth; zslice++)
  460. {
  461. CRNLIB_ASSERT(m_image_data.size() == get_image_index(mip_level, array_element, face, zslice));
  462. uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
  463. if ((!slice_size) || (slice_size > num_image_bytes_remaining))
  464. return false;
  465. m_image_data.push_back(uint8_vec());
  466. uint8_vec& image_data = m_image_data.back();
  467. image_data.resize(slice_size);
  468. if (serializer.read(&image_data[0], 1, slice_size) != slice_size)
  469. return false;
  470. if (m_opposite_endianness)
  471. utils::endian_swap_mem(&image_data[0], slice_size, m_header.m_glTypeSize);
  472. num_image_bytes_remaining -= slice_size;
  473. total_mip_size += slice_size;
  474. }
  475. }
  476. }
  477. if (num_image_bytes_remaining)
  478. return false;
  479. }
  480. uint num_mip_pad_bytes = disable_mip_and_cubemap_padding ? 0 : (3 - ((total_mip_size + 3) % 4));
  481. if (serializer.read(pad_bytes, 1, num_mip_pad_bytes) != num_mip_pad_bytes)
  482. return false;
  483. }
  484. return true;
  485. }
  486. bool ktx_texture::write_to_stream(data_stream_serializer& serializer, bool no_keyvalue_data)
  487. {
  488. if (!consistency_check())
  489. {
  490. CRNLIB_ASSERT(0);
  491. return false;
  492. }
  493. memcpy(m_header.m_identifier, s_ktx_file_id, sizeof(m_header.m_identifier));
  494. m_header.m_endianness = m_opposite_endianness ? KTX_OPPOSITE_ENDIAN : KTX_ENDIAN;
  495. if (m_block_dim == 1)
  496. {
  497. m_header.m_glTypeSize = get_ogl_type_size(m_header.m_glType);
  498. m_header.m_glBaseInternalFormat = m_header.m_glFormat;
  499. }
  500. else
  501. {
  502. m_header.m_glBaseInternalFormat = get_ogl_base_internal_fmt(m_header.m_glInternalFormat);
  503. }
  504. m_header.m_bytesOfKeyValueData = 0;
  505. if (!no_keyvalue_data)
  506. {
  507. for (uint i = 0; i < m_key_values.size(); i++)
  508. m_header.m_bytesOfKeyValueData += sizeof(uint32) + ((m_key_values[i].size() + 3) & ~3);
  509. }
  510. if (m_opposite_endianness)
  511. m_header.endian_swap();
  512. bool success = (serializer.write(&m_header, sizeof(m_header), 1) == 1);
  513. if (m_opposite_endianness)
  514. m_header.endian_swap();
  515. if (!success)
  516. return success;
  517. uint total_key_value_bytes = 0;
  518. const uint8 padding[3] = { 0, 0, 0 };
  519. if (!no_keyvalue_data)
  520. {
  521. for (uint i = 0; i < m_key_values.size(); i++)
  522. {
  523. uint32 key_value_size = m_key_values[i].size();
  524. if (m_opposite_endianness)
  525. key_value_size = utils::swap32(key_value_size);
  526. success = (serializer.write(&key_value_size, sizeof(key_value_size), 1) == 1);
  527. total_key_value_bytes += sizeof(key_value_size);
  528. if (m_opposite_endianness)
  529. key_value_size = utils::swap32(key_value_size);
  530. if (!success)
  531. return false;
  532. if (key_value_size)
  533. {
  534. if (serializer.write(&m_key_values[i][0], key_value_size, 1) != 1)
  535. return false;
  536. total_key_value_bytes += key_value_size;
  537. uint num_padding = 3 - ((key_value_size + 3) % 4);
  538. if ((num_padding) && (serializer.write(padding, num_padding, 1) != 1))
  539. return false;
  540. total_key_value_bytes += num_padding;
  541. }
  542. }
  543. (void)total_key_value_bytes;
  544. }
  545. CRNLIB_ASSERT(total_key_value_bytes == m_header.m_bytesOfKeyValueData);
  546. for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++)
  547. {
  548. uint mip_width, mip_height, mip_depth;
  549. get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
  550. const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
  551. const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
  552. if ((!mip_row_blocks) || (!mip_col_blocks))
  553. return false;
  554. uint32 image_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
  555. if ((m_header.m_numberOfArrayElements) || (get_num_faces() == 1))
  556. image_size *= (get_array_size() * get_num_faces() * get_depth());
  557. if (!image_size)
  558. return false;
  559. if (m_opposite_endianness)
  560. image_size = utils::swap32(image_size);
  561. success = (serializer.write(&image_size, sizeof(image_size), 1) == 1);
  562. if (m_opposite_endianness)
  563. image_size = utils::swap32(image_size);
  564. if (!success)
  565. return false;
  566. uint total_mip_size = 0;
  567. if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6))
  568. {
  569. // plain non-array cubemap
  570. for (uint face = 0; face < get_num_faces(); face++)
  571. {
  572. const uint8_vec& image_data = get_image_data(get_image_index(mip_level, 0, face, 0));
  573. if ((!image_data.size()) || (image_data.size() != image_size))
  574. return false;
  575. if (m_opposite_endianness)
  576. {
  577. uint8_vec tmp_image_data(image_data);
  578. utils::endian_swap_mem(&tmp_image_data[0], tmp_image_data.size(), m_header.m_glTypeSize);
  579. if (serializer.write(&tmp_image_data[0], tmp_image_data.size(), 1) != 1)
  580. return false;
  581. }
  582. else if (serializer.write(&image_data[0], image_data.size(), 1) != 1)
  583. return false;
  584. uint num_cube_pad_bytes = 3 - ((image_data.size() + 3) % 4);
  585. if ((num_cube_pad_bytes) && (serializer.write(padding, num_cube_pad_bytes, 1) != 1))
  586. return false;
  587. total_mip_size += image_size + num_cube_pad_bytes;
  588. }
  589. }
  590. else
  591. {
  592. // 1D, 2D, 3D (normal or array texture), or array cubemap
  593. for (uint array_element = 0; array_element < get_array_size(); array_element++)
  594. {
  595. for (uint face = 0; face < get_num_faces(); face++)
  596. {
  597. for (uint zslice = 0; zslice < mip_depth; zslice++)
  598. {
  599. const uint8_vec& image_data = get_image_data(get_image_index(mip_level, array_element, face, zslice));
  600. if (!image_data.size())
  601. return false;
  602. if (m_opposite_endianness)
  603. {
  604. uint8_vec tmp_image_data(image_data);
  605. utils::endian_swap_mem(&tmp_image_data[0], tmp_image_data.size(), m_header.m_glTypeSize);
  606. if (serializer.write(&tmp_image_data[0], tmp_image_data.size(), 1) != 1)
  607. return false;
  608. }
  609. else if (serializer.write(&image_data[0], image_data.size(), 1) != 1)
  610. return false;
  611. total_mip_size += image_data.size();
  612. }
  613. }
  614. }
  615. uint num_mip_pad_bytes = 3 - ((total_mip_size + 3) % 4);
  616. if ((num_mip_pad_bytes) && (serializer.write(padding, num_mip_pad_bytes, 1) != 1))
  617. return false;
  618. total_mip_size += num_mip_pad_bytes;
  619. }
  620. CRNLIB_ASSERT((total_mip_size & 3) == 0);
  621. }
  622. return true;
  623. }
  624. bool ktx_texture::init_2D(uint width, uint height, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type)
  625. {
  626. clear();
  627. m_header.m_pixelWidth = width;
  628. m_header.m_pixelHeight = height;
  629. m_header.m_numberOfMipmapLevels = num_mips;
  630. m_header.m_glInternalFormat = ogl_internal_fmt;
  631. m_header.m_glFormat = ogl_fmt;
  632. m_header.m_glType = ogl_type;
  633. m_header.m_numberOfFaces = 1;
  634. if (!compute_pixel_info())
  635. return false;
  636. return true;
  637. }
  638. bool ktx_texture::init_2D_array(uint width, uint height, uint num_mips, uint array_size, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type)
  639. {
  640. clear();
  641. m_header.m_pixelWidth = width;
  642. m_header.m_pixelHeight = height;
  643. m_header.m_numberOfMipmapLevels = num_mips;
  644. m_header.m_numberOfArrayElements = array_size;
  645. m_header.m_glInternalFormat = ogl_internal_fmt;
  646. m_header.m_glFormat = ogl_fmt;
  647. m_header.m_glType = ogl_type;
  648. m_header.m_numberOfFaces = 1;
  649. if (!compute_pixel_info())
  650. return false;
  651. return true;
  652. }
  653. bool ktx_texture::init_3D(uint width, uint height, uint depth, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type)
  654. {
  655. clear();
  656. m_header.m_pixelWidth = width;
  657. m_header.m_pixelHeight = height;
  658. m_header.m_pixelDepth = depth;
  659. m_header.m_numberOfMipmapLevels = num_mips;
  660. m_header.m_glInternalFormat = ogl_internal_fmt;
  661. m_header.m_glFormat = ogl_fmt;
  662. m_header.m_glType = ogl_type;
  663. m_header.m_numberOfFaces = 1;
  664. if (!compute_pixel_info())
  665. return false;
  666. return true;
  667. }
  668. bool ktx_texture::init_cubemap(uint dim, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type)
  669. {
  670. clear();
  671. m_header.m_pixelWidth = dim;
  672. m_header.m_pixelHeight = dim;
  673. m_header.m_numberOfMipmapLevels = num_mips;
  674. m_header.m_glInternalFormat = ogl_internal_fmt;
  675. m_header.m_glFormat = ogl_fmt;
  676. m_header.m_glType = ogl_type;
  677. m_header.m_numberOfFaces = 6;
  678. if (!compute_pixel_info())
  679. return false;
  680. return true;
  681. }
  682. bool ktx_texture::check_header() const
  683. {
  684. if (((get_num_faces() != 1) && (get_num_faces() != 6)) || (!m_header.m_pixelWidth))
  685. return false;
  686. if ((!m_header.m_pixelHeight) && (m_header.m_pixelDepth))
  687. return false;
  688. if ((get_num_faces() == 6) && ((m_header.m_pixelDepth) || (!m_header.m_pixelHeight)))
  689. return false;
  690. if (m_header.m_numberOfMipmapLevels)
  691. {
  692. const uint max_mipmap_dimension = 1U << (m_header.m_numberOfMipmapLevels - 1U);
  693. if (max_mipmap_dimension > (CRNLIB_MAX(CRNLIB_MAX(m_header.m_pixelWidth, m_header.m_pixelHeight), m_header.m_pixelDepth)))
  694. return false;
  695. }
  696. return true;
  697. }
  698. bool ktx_texture::consistency_check() const
  699. {
  700. if (!check_header())
  701. return false;
  702. uint block_dim = 0, bytes_per_block = 0;
  703. if ((!m_header.m_glType) || (!m_header.m_glFormat))
  704. {
  705. if ((m_header.m_glType) || (m_header.m_glFormat))
  706. return false;
  707. if (!get_ogl_fmt_desc(m_header.m_glInternalFormat, m_header.m_glType, block_dim, bytes_per_block))
  708. return false;
  709. if (block_dim == 1)
  710. return false;
  711. //if ((get_width() % block_dim) || (get_height() % block_dim))
  712. // return false;
  713. }
  714. else
  715. {
  716. if (!get_ogl_fmt_desc(m_header.m_glFormat, m_header.m_glType, block_dim, bytes_per_block))
  717. return false;
  718. if (block_dim > 1)
  719. return false;
  720. }
  721. if ((m_block_dim != block_dim) || (m_bytes_per_block != bytes_per_block))
  722. return false;
  723. if (m_image_data.size() != get_total_images())
  724. return false;
  725. for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++)
  726. {
  727. uint mip_width, mip_height, mip_depth;
  728. get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
  729. const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
  730. const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
  731. if ((!mip_row_blocks) || (!mip_col_blocks))
  732. return false;
  733. for (uint array_element = 0; array_element < get_array_size(); array_element++)
  734. {
  735. for (uint face = 0; face < get_num_faces(); face++)
  736. {
  737. for (uint zslice = 0; zslice < mip_depth; zslice++)
  738. {
  739. const uint8_vec& image_data = get_image_data(get_image_index(mip_level, array_element, face, zslice));
  740. uint expected_image_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
  741. if (image_data.size() != expected_image_size)
  742. return false;
  743. }
  744. }
  745. }
  746. }
  747. return true;
  748. }
  749. const uint8_vec* ktx_texture::find_key(const char* pKey) const
  750. {
  751. const size_t n = strlen(pKey) + 1;
  752. for (uint i = 0; i < m_key_values.size(); i++)
  753. {
  754. const uint8_vec& v = m_key_values[i];
  755. if ((v.size() >= n) && (!memcmp(&v[0], pKey, n)))
  756. return &v;
  757. }
  758. return NULL;
  759. }
  760. bool ktx_texture::get_key_value_as_string(const char* pKey, dynamic_string& str) const
  761. {
  762. const uint8_vec* p = find_key(pKey);
  763. if (!p)
  764. {
  765. str.clear();
  766. return false;
  767. }
  768. const uint ofs = (static_cast<uint>(strlen(pKey)) + 1);
  769. const uint8* pValue = p->get_ptr() + ofs;
  770. const uint n = p->size() - ofs;
  771. uint i;
  772. for (i = 0; i < n; i++)
  773. if (!pValue[i])
  774. break;
  775. str.set_from_buf(pValue, i);
  776. return true;
  777. }
  778. uint ktx_texture::add_key_value(const char* pKey, const void* pVal, uint val_size)
  779. {
  780. const uint idx = m_key_values.size();
  781. m_key_values.resize(idx + 1);
  782. uint8_vec& v = m_key_values.back();
  783. v.append(reinterpret_cast<const uint8*>(pKey), static_cast<uint>(strlen(pKey)) + 1);
  784. v.append(static_cast<const uint8*>(pVal), val_size);
  785. return idx;
  786. }
  787. } // namespace crnlib