texture.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. /* -*- tab-width: 4; -*- */
  2. /* vi: set sw=2 ts=4 expandtab: */
  3. /*
  4. * Copyright 2018-2020 Mark Callow.
  5. * SPDX-License-Identifier: Apache-2.0
  6. */
  7. /**
  8. * @internal
  9. * @file writer.c
  10. * @~English
  11. *
  12. * @brief ktxTexture implementation.
  13. *
  14. * @author Mark Callow, www.edgewise-consulting.com
  15. */
  16. #if defined(_WIN32)
  17. #define _CRT_SECURE_NO_WARNINGS
  18. #ifndef __cplusplus
  19. #undef inline
  20. #define inline __inline
  21. #endif // __cplusplus
  22. #endif
  23. #include <assert.h>
  24. #include <math.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include "ktx.h"
  28. #include "ktxint.h"
  29. #include "formatsize.h"
  30. #include "filestream.h"
  31. #include "memstream.h"
  32. #include "texture1.h"
  33. #include "texture2.h"
  34. #include "unused.h"
  35. ktx_size_t ktxTexture_GetDataSize(ktxTexture* This);
  36. static ktx_uint32_t padRow(ktx_uint32_t* rowBytes);
  37. /**
  38. * @memberof ktxTexture @private
  39. * @~English
  40. * @brief Construct (initialize) a ktxTexture base class instance.
  41. *
  42. * @param[in] This pointer to a ktxTexture-sized block of memory to
  43. * initialize.
  44. * @param[in] createInfo pointer to a ktxTextureCreateInfo struct with
  45. * information describing the texture.
  46. * @param[in] formatSize pointer to a ktxFormatSize giving size information
  47. * about the texture's elements.
  48. *
  49. * @return KTX_SUCCESS on success, other KTX_* enum values on error.
  50. *
  51. * @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a
  52. * valid OpenGL internal format value.
  53. * @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2
  54. * or 3.
  55. * @exception KTX_INVALID_VALUE One of <tt>base{Width,Height,Depth}</tt> in
  56. * @p createInfo is 0.
  57. * @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6.
  58. * @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0.
  59. * @exception KTX_INVALID_OPERATION
  60. * The <tt>base{Width,Height,Depth}</tt> specified
  61. * in @p createInfo are inconsistent with
  62. * @c numDimensions.
  63. * @exception KTX_INVALID_OPERATION
  64. * @p createInfo is requesting a 3D array or
  65. * 3D cubemap texture.
  66. * @exception KTX_INVALID_OPERATION
  67. * @p createInfo is requesting a cubemap with
  68. * non-square or non-2D images.
  69. * @exception KTX_INVALID_OPERATION
  70. * @p createInfo is requesting more mip levels
  71. * than needed for the specified
  72. * <tt>base{Width,Height,Depth}</tt>.
  73. * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture.
  74. */
  75. KTX_error_code
  76. ktxTexture_construct(ktxTexture* This, ktxTextureCreateInfo* createInfo,
  77. ktxFormatSize* formatSize)
  78. {
  79. DECLARE_PROTECTED(ktxTexture);
  80. memset(This, 0, sizeof(*This));
  81. This->_protected = (struct ktxTexture_protected*)malloc(sizeof(*prtctd));
  82. if (!This->_protected)
  83. return KTX_OUT_OF_MEMORY;
  84. prtctd = This->_protected;
  85. memset(prtctd, 0, sizeof(*prtctd));
  86. memcpy(&prtctd->_formatSize, formatSize, sizeof(prtctd->_formatSize));
  87. This->isCompressed = (formatSize->flags & KTX_FORMAT_SIZE_COMPRESSED_BIT);
  88. This->orientation.x = KTX_ORIENT_X_RIGHT;
  89. This->orientation.y = KTX_ORIENT_Y_DOWN;
  90. This->orientation.z = KTX_ORIENT_Z_OUT;
  91. /* Check texture dimensions. KTX files can store 8 types of textures:
  92. * 1D, 2D, 3D, cube, and array variants of these.
  93. */
  94. if (createInfo->numDimensions < 1 || createInfo->numDimensions > 3)
  95. return KTX_INVALID_VALUE;
  96. if (createInfo->baseWidth == 0 || createInfo->baseHeight == 0
  97. || createInfo->baseDepth == 0)
  98. return KTX_INVALID_VALUE;
  99. switch (createInfo->numDimensions) {
  100. case 1:
  101. if (createInfo->baseHeight > 1 || createInfo->baseDepth > 1)
  102. return KTX_INVALID_OPERATION;
  103. break;
  104. case 2:
  105. if (createInfo->baseDepth > 1)
  106. return KTX_INVALID_OPERATION;
  107. break;
  108. case 3:
  109. /* 3D array textures and 3D cubemaps are not supported by either
  110. * OpenGL or Vulkan.
  111. */
  112. if (createInfo->isArray || createInfo->numFaces != 1
  113. || createInfo->numLayers != 1)
  114. return KTX_INVALID_OPERATION;
  115. break;
  116. }
  117. This->numDimensions = createInfo->numDimensions;
  118. This->baseWidth = createInfo->baseWidth;
  119. This->baseDepth = createInfo->baseDepth;
  120. This->baseHeight = createInfo->baseHeight;
  121. if (createInfo->numLayers == 0)
  122. return KTX_INVALID_VALUE;
  123. This->numLayers = createInfo->numLayers;
  124. This->isArray = createInfo->isArray;
  125. if (createInfo->numFaces == 6) {
  126. if (This->numDimensions != 2) {
  127. /* cube map needs 2D faces */
  128. return KTX_INVALID_OPERATION;
  129. }
  130. if (createInfo->baseWidth != createInfo->baseHeight) {
  131. /* cube maps require square images */
  132. return KTX_INVALID_OPERATION;
  133. }
  134. This->isCubemap = KTX_TRUE;
  135. } else if (createInfo->numFaces != 1) {
  136. /* numFaces must be either 1 or 6 */
  137. return KTX_INVALID_VALUE;
  138. }
  139. This->numFaces = createInfo->numFaces;
  140. /* Check number of mipmap levels */
  141. if (createInfo->numLevels == 0)
  142. return KTX_INVALID_VALUE;
  143. This->numLevels = createInfo->numLevels;
  144. This->generateMipmaps = createInfo->generateMipmaps;
  145. if (createInfo->numLevels > 1) {
  146. GLuint max_dim = MAX(MAX(createInfo->baseWidth, createInfo->baseHeight),
  147. createInfo->baseDepth);
  148. if (max_dim < ((GLuint)1 << (This->numLevels - 1)))
  149. {
  150. /* Can't have more mip levels than 1 + log2(max(width, height, depth)) */
  151. return KTX_INVALID_OPERATION;
  152. }
  153. }
  154. ktxHashList_Construct(&This->kvDataHead);
  155. return KTX_SUCCESS;
  156. }
  157. /**
  158. * @memberof ktxTexture @private
  159. * @~English
  160. * @brief Construct (initialize) the part of a ktxTexture base class that is
  161. * not related to the stream contents.
  162. *
  163. * @param[in] This pointer to a ktxTexture-sized block of memory to
  164. * initialize.
  165. *
  166. * @return KTX_SUCCESS on success, other KTX_* enum values on error.
  167. */
  168. KTX_error_code
  169. ktxTexture_constructFromStream(ktxTexture* This, ktxStream* pStream,
  170. ktxTextureCreateFlags createFlags)
  171. {
  172. ktxStream* stream;
  173. UNUSED(createFlags); // Reference to keep compiler happy.
  174. assert(This != NULL);
  175. assert(pStream->data.mem != NULL);
  176. assert(pStream->type == eStreamTypeFile
  177. || pStream->type == eStreamTypeMemory
  178. || pStream->type == eStreamTypeCustom);
  179. This->_protected = (struct ktxTexture_protected *)
  180. malloc(sizeof(struct ktxTexture_protected));
  181. stream = ktxTexture_getStream(This);
  182. // Copy stream info into struct for later use.
  183. *stream = *pStream;
  184. This->orientation.x = KTX_ORIENT_X_RIGHT;
  185. This->orientation.y = KTX_ORIENT_Y_DOWN;
  186. This->orientation.z = KTX_ORIENT_Z_OUT;
  187. return KTX_SUCCESS;
  188. }
  189. /**
  190. * @memberof ktxTexture @private
  191. * @~English
  192. * @brief Free the memory associated with the texture contents
  193. *
  194. * @param[in] This pointer to the ktxTextureInt whose texture contents are
  195. * to be freed.
  196. */
  197. void
  198. ktxTexture_destruct(ktxTexture* This)
  199. {
  200. ktxStream stream = *(ktxTexture_getStream(This));
  201. if (stream.data.file != NULL)
  202. stream.destruct(&stream);
  203. if (This->kvDataHead != NULL)
  204. ktxHashList_Destruct(&This->kvDataHead);
  205. if (This->kvData != NULL)
  206. free(This->kvData);
  207. if (This->pData != NULL)
  208. free(This->pData);
  209. free(This->_protected);
  210. }
  211. /**
  212. * @defgroup reader Reader
  213. * @brief Read KTX-formatted data.
  214. * @{
  215. */
  216. typedef enum { KTX1, KTX2 } ktxFileType_;
  217. typedef union {
  218. KTX_header ktx;
  219. KTX_header2 ktx2;
  220. } ktxHeaderUnion_;
  221. /**
  222. * @memberof ktxTexture @private
  223. * @~English
  224. * @brief Determine if stream data is KTX1 or KTX2.
  225. *
  226. * @param pStream pointer to the ktxStream to examine.
  227. * @param pFileType pointer to a ktxFileType enum where the type of the data
  228. * will be written.
  229. * @param pHeader pointer to a ktxHeaderUnion where the header info. will be
  230. * written.
  231. */
  232. static KTX_error_code
  233. ktxDetermineFileType_(ktxStream* pStream, ktxFileType_* pFileType,
  234. ktxHeaderUnion_* pHeader)
  235. {
  236. ktx_uint8_t ktx_ident_ref[12] = KTX_IDENTIFIER_REF;
  237. ktx_uint8_t ktx2_ident_ref[12] = KTX2_IDENTIFIER_REF;
  238. KTX_error_code result;
  239. assert(pStream != NULL && pFileType != NULL);
  240. assert(pStream->data.mem != NULL);
  241. assert(pStream->type == eStreamTypeFile
  242. || pStream->type == eStreamTypeMemory
  243. || pStream->type == eStreamTypeCustom);
  244. result = pStream->read(pStream, pHeader, sizeof(ktx2_ident_ref));
  245. if (result == KTX_SUCCESS) {
  246. #if BIG_ENDIAN
  247. // byte swap the heaader fields
  248. #endif
  249. // Compare identifier, is this a KTX or KTX2 file?
  250. if (!memcmp(pHeader->ktx.identifier, ktx_ident_ref, 12)) {
  251. *pFileType = KTX1;
  252. } else if (!memcmp(pHeader->ktx2.identifier, ktx2_ident_ref, 12)) {
  253. *pFileType = KTX2;
  254. } else {
  255. return KTX_UNKNOWN_FILE_FORMAT;
  256. }
  257. // Read rest of header.
  258. if (*pFileType == KTX1) {
  259. // Read rest of header.
  260. result = pStream->read(pStream, &pHeader->ktx.endianness,
  261. KTX_HEADER_SIZE - sizeof(ktx_ident_ref));
  262. } else {
  263. result = pStream->read(pStream, &pHeader->ktx2.vkFormat,
  264. KTX2_HEADER_SIZE - sizeof(ktx2_ident_ref));
  265. }
  266. }
  267. return result;
  268. }
  269. /**
  270. * @memberof ktxTexture
  271. * @~English
  272. * @brief Construct (initialize) a ktx1 or ktx2 texture according to the stream
  273. * data.
  274. *
  275. * @copydetails ktxTexture_CreateFromStdioStream
  276. */
  277. KTX_error_code
  278. ktxTexture_CreateFromStream(ktxStream* pStream,
  279. ktxTextureCreateFlags createFlags,
  280. ktxTexture** newTex)
  281. {
  282. ktxHeaderUnion_ header;
  283. ktxFileType_ fileType;
  284. KTX_error_code result;
  285. ktxTexture* tex;
  286. result = ktxDetermineFileType_(pStream, &fileType, &header);
  287. if (result != KTX_SUCCESS)
  288. return result;
  289. if (fileType == KTX1) {
  290. ktxTexture1* tex1 = (ktxTexture1*)malloc(sizeof(ktxTexture1));
  291. if (tex1 == NULL)
  292. return KTX_OUT_OF_MEMORY;
  293. memset(tex1, 0, sizeof(ktxTexture1));
  294. result = ktxTexture1_constructFromStreamAndHeader(tex1, pStream,
  295. &header.ktx,
  296. createFlags);
  297. tex = ktxTexture(tex1);
  298. } else {
  299. ktxTexture2* tex2 = (ktxTexture2*)malloc(sizeof(ktxTexture2));
  300. if (tex2 == NULL)
  301. return KTX_OUT_OF_MEMORY;
  302. memset(tex2, 0, sizeof(ktxTexture2));
  303. result = ktxTexture2_constructFromStreamAndHeader(tex2, pStream,
  304. &header.ktx2,
  305. createFlags);
  306. tex = ktxTexture(tex2);
  307. }
  308. if (result == KTX_SUCCESS)
  309. *newTex = (ktxTexture*)tex;
  310. else {
  311. free(tex);
  312. *newTex = NULL;
  313. }
  314. return result;
  315. }
  316. /**
  317. * @memberof ktxTexture
  318. * @~English
  319. * @brief Create a ktxTexture1 or ktxTexture2 from a stdio stream according
  320. * to the stream data.
  321. *
  322. * @copydetails ktxTexture1_CreateFromStdioStream()
  323. */
  324. KTX_error_code
  325. ktxTexture_CreateFromStdioStream(FILE* stdioStream,
  326. ktxTextureCreateFlags createFlags,
  327. ktxTexture** newTex)
  328. {
  329. ktxStream stream;
  330. KTX_error_code result;
  331. if (stdioStream == NULL || newTex == NULL)
  332. return KTX_INVALID_VALUE;
  333. result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE);
  334. if (result == KTX_SUCCESS) {
  335. result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
  336. }
  337. return result;
  338. }
  339. /**
  340. * @memberof ktxTexture
  341. * @~English
  342. * @brief Create a ktxTexture1 or ktxTexture2 from a named KTX file according
  343. * to the file contents.
  344. *
  345. * The address of a newly created ktxTexture reflecting the contents of the
  346. * file is written to the location pointed at by @p newTex.
  347. *
  348. * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
  349. * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This
  350. * will minimize memory usage by allowing, for example, loading the images
  351. * directly from the source into a Vulkan staging buffer.
  352. *
  353. * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
  354. * provided solely to enable implementation of the @e libktx v1 API on top of
  355. * ktxTexture.
  356. *
  357. * @param[in] filename pointer to a char array containing the file name.
  358. * @param[in] createFlags bitmask requesting specific actions during creation.
  359. * @param[in,out] newTex pointer to a location in which store the address of
  360. * the newly created texture.
  361. *
  362. * @return KTX_SUCCESS on success, other KTX_* enum values on error.
  363. * @exception KTX_FILE_OPEN_FAILED The file could not be opened.
  364. * @exception KTX_INVALID_VALUE @p filename is @c NULL.
  365. *
  366. * For other exceptions, see ktxTexture_CreateFromStdioStream().
  367. */
  368. KTX_error_code
  369. ktxTexture_CreateFromNamedFile(const char* const filename,
  370. ktxTextureCreateFlags createFlags,
  371. ktxTexture** newTex)
  372. {
  373. KTX_error_code result;
  374. ktxStream stream;
  375. FILE* file;
  376. if (filename == NULL || newTex == NULL)
  377. return KTX_INVALID_VALUE;
  378. file = fopen(filename, "rb");
  379. if (!file)
  380. return KTX_FILE_OPEN_FAILED;
  381. result = ktxFileStream_construct(&stream, file, KTX_TRUE);
  382. if (result == KTX_SUCCESS) {
  383. result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
  384. }
  385. return result;
  386. }
  387. /**
  388. * @memberof ktxTexture
  389. * @~English
  390. * @brief Create a ktxTexture1 or ktxTexture2 from KTX-formatted data in memory
  391. * according to the data contents.
  392. *
  393. * The address of a newly created ktxTexture reflecting the contents of the
  394. * serialized KTX data is written to the location pointed at by @p newTex.
  395. *
  396. * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
  397. * if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This
  398. * will minimize memory usage by allowing, for example, loading the images
  399. * directly from the source into a Vulkan staging buffer.
  400. *
  401. * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
  402. * provided solely to enable implementation of the @e libktx v1 API on top of
  403. * ktxTexture.
  404. *
  405. * @param[in] bytes pointer to the memory containing the serialized KTX data.
  406. * @param[in] size length of the KTX data in bytes.
  407. * @param[in] createFlags bitmask requesting specific actions during creation.
  408. * @param[in,out] newTex pointer to a location in which store the address of
  409. * the newly created texture.
  410. *
  411. * @return KTX_SUCCESS on success, other KTX_* enum values on error.
  412. *
  413. * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0.
  414. *
  415. * For other exceptions, see ktxTexture_CreateFromStdioStream().
  416. */
  417. KTX_error_code
  418. ktxTexture_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size,
  419. ktxTextureCreateFlags createFlags,
  420. ktxTexture** newTex)
  421. {
  422. KTX_error_code result;
  423. ktxStream stream;
  424. if (bytes == NULL || newTex == NULL || size == 0)
  425. return KTX_INVALID_VALUE;
  426. result = ktxMemStream_construct_ro(&stream, bytes, size);
  427. if (result == KTX_SUCCESS) {
  428. result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
  429. }
  430. return result;}
  431. /**
  432. * @memberof ktxTexture
  433. * @~English
  434. * @brief Return a pointer to the texture image data.
  435. *
  436. * @param[in] This pointer to the ktxTexture object of interest.
  437. */
  438. ktx_uint8_t*
  439. ktxTexture_GetData(ktxTexture* This)
  440. {
  441. return This->pData;
  442. }
  443. /**
  444. * @memberof ktxTexture
  445. * @~English
  446. * @brief Return the total size of the texture image data in bytes.
  447. *
  448. * For a ktxTexture2 with supercompressionScheme != KTX_SS_NONE this will
  449. * return the deflated size of the data.
  450. *
  451. * @param[in] This pointer to the ktxTexture object of interest.
  452. */
  453. ktx_size_t
  454. ktxTexture_GetDataSize(ktxTexture* This)
  455. {
  456. assert(This != NULL);
  457. return This->dataSize;
  458. }
  459. /**
  460. * @memberof ktxTexture
  461. * @~English
  462. * @brief Return the size in bytes of an elements of a texture's
  463. * images.
  464. *
  465. * For uncompressed textures an element is one texel. For compressed
  466. * textures it is one block.
  467. *
  468. * @param[in] This pointer to the ktxTexture object of interest.
  469. */
  470. ktx_uint32_t
  471. ktxTexture_GetElementSize(ktxTexture* This)
  472. {
  473. assert (This != NULL);
  474. return (This->_protected->_formatSize.blockSizeInBits / 8);
  475. }
  476. /**
  477. * @memberof ktxTexture @private
  478. * @~English
  479. * @brief Calculate & return the size in bytes of an image at the specified
  480. * mip level.
  481. *
  482. * For arrays, this is the size of layer, for cubemaps, the size of a face
  483. * and for 3D textures, the size of a depth slice.
  484. *
  485. * The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT.
  486. *
  487. * @param[in] This pointer to the ktxTexture object of interest.
  488. * @param[in] level level of interest.
  489. * @param[in] fv enum specifying format version for which to calculate
  490. * image size.
  491. */
  492. ktx_size_t
  493. ktxTexture_calcImageSize(ktxTexture* This, ktx_uint32_t level,
  494. ktxFormatVersionEnum fv)
  495. {
  496. DECLARE_PROTECTED(ktxTexture);
  497. struct blockCount {
  498. ktx_uint32_t x, y;
  499. } blockCount;
  500. ktx_uint32_t blockSizeInBytes;
  501. ktx_uint32_t rowBytes;
  502. assert (This != NULL);
  503. float levelWidth = (float)(This->baseWidth >> level);
  504. float levelHeight = (float)(This->baseHeight >> level);
  505. // Round up to next whole block. We can't use KTX_PADN because some of
  506. // the block sizes are not powers of 2.
  507. blockCount.x
  508. = (ktx_uint32_t)ceilf(levelWidth / prtctd->_formatSize.blockWidth);
  509. blockCount.y
  510. = (ktx_uint32_t)ceilf(levelHeight / prtctd->_formatSize.blockHeight);
  511. blockCount.x = MAX(prtctd->_formatSize.minBlocksX, blockCount.x);
  512. blockCount.y = MAX(prtctd->_formatSize.minBlocksX, blockCount.y);
  513. blockSizeInBytes = prtctd->_formatSize.blockSizeInBits / 8;
  514. if (prtctd->_formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT) {
  515. assert(This->isCompressed);
  516. return blockCount.x * blockCount.y * blockSizeInBytes;
  517. } else {
  518. assert(prtctd->_formatSize.blockWidth == 1U
  519. && prtctd->_formatSize.blockHeight == 1U
  520. && prtctd->_formatSize.blockDepth == 1U);
  521. rowBytes = blockCount.x * blockSizeInBytes;
  522. if (fv == KTX_FORMAT_VERSION_ONE)
  523. (void)padRow(&rowBytes);
  524. return rowBytes * blockCount.y;
  525. }
  526. }
  527. /**
  528. * @memberof ktxTexture
  529. * @~English
  530. * @brief Iterate over the levels or faces in a ktxTexture object.
  531. *
  532. * Blocks of image data are passed to an application-supplied callback
  533. * function. This is not a strict per-image iteration. Rather it reflects how
  534. * OpenGL needs the images. For most textures the block of data includes all
  535. * images of a mip level which implies all layers of an array. However, for
  536. * non-array cube map textures the block is a single face of the mip level,
  537. * i.e the callback is called once for each face.
  538. *
  539. * This function works even if @p This->pData == 0 so it can be used to
  540. * obtain offsets and sizes for each level by callers who have loaded the data
  541. * externally.
  542. *
  543. * @param[in] This pointer to the ktxTexture object of interest.
  544. * @param[in,out] iterCb the address of a callback function which is called
  545. * with the data for each image block.
  546. * @param[in,out] userdata the address of application-specific data which is
  547. * passed to the callback along with the image data.
  548. *
  549. * @return KTX_SUCCESS on success, other KTX_* enum values on error. The
  550. * following are returned directly by this function. @p iterCb may
  551. * return these for other causes or may return additional errors.
  552. *
  553. * @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not
  554. * decreasing
  555. * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.
  556. *
  557. */
  558. KTX_error_code
  559. ktxTexture_IterateLevelFaces(ktxTexture* This, PFNKTXITERCB iterCb,
  560. void* userdata)
  561. {
  562. ktx_uint32_t miplevel;
  563. KTX_error_code result = KTX_SUCCESS;
  564. if (This == NULL)
  565. return KTX_INVALID_VALUE;
  566. if (iterCb == NULL)
  567. return KTX_INVALID_VALUE;
  568. for (miplevel = 0; miplevel < This->numLevels; ++miplevel)
  569. {
  570. ktx_uint32_t faceLodSize;
  571. ktx_uint32_t face;
  572. ktx_uint32_t innerIterations;
  573. GLsizei width, height, depth;
  574. /* Array textures have the same number of layers at each mip level. */
  575. width = MAX(1, This->baseWidth >> miplevel);
  576. height = MAX(1, This->baseHeight >> miplevel);
  577. depth = MAX(1, This->baseDepth >> miplevel);
  578. faceLodSize = (ktx_uint32_t)ktxTexture_calcFaceLodSize(
  579. This, miplevel);
  580. /* All array layers are passed in a group because that is how
  581. * GL & Vulkan need them. Hence no
  582. * for (layer = 0; layer < This->numLayers)
  583. */
  584. if (This->isCubemap && !This->isArray)
  585. innerIterations = This->numFaces;
  586. else
  587. innerIterations = 1;
  588. for (face = 0; face < innerIterations; ++face)
  589. {
  590. /* And all z_slices are also passed as a group hence no
  591. * for (slice = 0; slice < This->depth)
  592. */
  593. ktx_size_t offset;
  594. ktxTexture_GetImageOffset(This, miplevel, 0, face, &offset);
  595. result = iterCb(miplevel, face,
  596. width, height, depth,
  597. faceLodSize, This->pData + offset, userdata);
  598. if (result != KTX_SUCCESS)
  599. break;
  600. }
  601. }
  602. return result;
  603. }
  604. /**
  605. * @internal
  606. * @brief Calculate and apply the padding needed to comply with
  607. * KTX_GL_UNPACK_ALIGNMENT.
  608. *
  609. * For uncompressed textures, KTX format specifies KTX_GL_UNPACK_ALIGNMENT = 4.
  610. *
  611. * @param[in,out] rowBytes pointer to variable containing the packed no. of
  612. * bytes in a row. The no. of bytes after padding
  613. * is written into this location.
  614. * @return the no. of bytes of padding.
  615. */
  616. static ktx_uint32_t
  617. padRow(ktx_uint32_t* rowBytes)
  618. {
  619. ktx_uint32_t rowPadding;
  620. assert (rowBytes != NULL);
  621. rowPadding = _KTX_PAD_UNPACK_ALIGN_LEN(*rowBytes);
  622. *rowBytes += rowPadding;
  623. return rowPadding;
  624. }
  625. /**
  626. * @memberof ktxTexture @private
  627. * @~English
  628. * @brief Calculate the size of an array layer at the specified mip level.
  629. *
  630. * The size of a layer is the size of an image * either the number of faces
  631. * or the number of depth slices. This is the size of a layer as needed to
  632. * find the offset within the array of images of a level and layer so the size
  633. * reflects any @c cubePadding.
  634. *
  635. * @param[in] This pointer to the ktxTexture object of interest.
  636. * @param[in] level level whose layer size to return.
  637. *
  638. * @return the layer size in bytes.
  639. */
  640. ktx_size_t
  641. ktxTexture_layerSize(ktxTexture* This, ktx_uint32_t level,
  642. ktxFormatVersionEnum fv)
  643. {
  644. /*
  645. * As there are no 3D cubemaps, the image's z block count will always be
  646. * 1 for cubemaps and numFaces will always be 1 for 3D textures so the
  647. * multiply is safe. 3D cubemaps, if they existed, would require
  648. * imageSize * (blockCount.z + This->numFaces);
  649. */
  650. DECLARE_PROTECTED(ktxTexture);
  651. ktx_uint32_t blockCountZ;
  652. ktx_size_t imageSize, layerSize;
  653. assert (This != NULL);
  654. blockCountZ = MAX(1, (This->baseDepth / prtctd->_formatSize.blockDepth) >> level);
  655. imageSize = ktxTexture_calcImageSize(This, level, fv);
  656. layerSize = imageSize * blockCountZ;
  657. if (fv == KTX_FORMAT_VERSION_ONE && KTX_GL_UNPACK_ALIGNMENT != 4) {
  658. if (This->isCubemap && !This->isArray) {
  659. /* cubePadding. NOTE: this adds padding after the last face too. */
  660. layerSize += _KTX_PAD4(layerSize);
  661. }
  662. }
  663. return layerSize * This->numFaces;
  664. }
  665. /**
  666. * @memberof ktxTexture @private
  667. * @~English
  668. * @brief Calculate the size of the specified mip level.
  669. *
  670. * The size of a level is the size of a layer * the number of layers.
  671. *
  672. * @param[in] This pointer to the ktxTexture object of interest.
  673. * @param[in] level level whose layer size to return.
  674. *
  675. * @return the level size in bytes.
  676. */
  677. ktx_size_t
  678. ktxTexture_calcLevelSize(ktxTexture* This, ktx_uint32_t level,
  679. ktxFormatVersionEnum fv)
  680. {
  681. assert (This != NULL);
  682. assert (level < This->numLevels);
  683. return ktxTexture_layerSize(This, level, fv) * This->numLayers;
  684. }
  685. /**
  686. * @memberof ktxTexture @private
  687. * @~English
  688. * @brief Calculate the faceLodSize of the specified mip level.
  689. *
  690. * The faceLodSize of a level for most textures is the size of a level. For
  691. * non-array cube map textures is the size of a face. This is the size that
  692. * must be provided to OpenGL when uploading textures. Faces get uploaded 1
  693. * at a time while all layers of an array or all slices of a 3D texture are
  694. * uploaded together.
  695. *
  696. * @param[in] This pointer to the ktxTexture object of interest.
  697. * @param[in] level level whose layer size to return.
  698. *
  699. * @return the faceLodSize size in bytes.
  700. */
  701. ktx_size_t
  702. ktxTexture_doCalcFaceLodSize(ktxTexture* This, ktx_uint32_t level,
  703. ktxFormatVersionEnum fv)
  704. {
  705. /*
  706. * For non-array cubemaps this is the size of a face. For everything
  707. * else it is the size of the level.
  708. */
  709. if (This->isCubemap && !This->isArray)
  710. return ktxTexture_calcImageSize(This, level, fv);
  711. else
  712. return ktxTexture_calcLevelSize(This, level, fv);
  713. }
  714. /**
  715. * @memberof ktxTexture @private
  716. * @~English
  717. * @brief Return the number of bytes needed to store all the image data for
  718. * a ktxTexture.
  719. *
  720. * The caclulated size does not include space for storing the @c imageSize
  721. * fields of each mip level.
  722. *
  723. * @param[in] This pointer to the ktxTexture object of interest.
  724. * @param[in] fv enum specifying format version for which to calculate
  725. * image size.
  726. *
  727. * @return the data size in bytes.
  728. */
  729. ktx_size_t
  730. ktxTexture_calcDataSizeTexture(ktxTexture* This)
  731. {
  732. assert (This != NULL);
  733. return ktxTexture_calcDataSizeLevels(This, This->numLevels);
  734. }
  735. /**
  736. * @memberof ktxTexture @private
  737. * @~English
  738. * @brief Get information about rows of an uncompresssed texture image at a
  739. * specified level.
  740. *
  741. * For an image at @p level of a ktxTexture provide the number of rows, the
  742. * packed (unpadded) number of bytes in a row and the padding necessary to
  743. * comply with KTX_GL_UNPACK_ALIGNMENT.
  744. *
  745. * @param[in] This pointer to the ktxTexture object of interest.
  746. * @param[in] level level of interest.
  747. * @param[in,out] numRows pointer to location to store the number of rows.
  748. * @param[in,out] pRowLengthBytes pointer to location to store number of bytes
  749. * in a row.
  750. * @param[in.out] pRowPadding pointer to location to store the number of bytes
  751. * of padding.
  752. */
  753. void
  754. ktxTexture_rowInfo(ktxTexture* This, ktx_uint32_t level,
  755. ktx_uint32_t* numRows, ktx_uint32_t* pRowLengthBytes,
  756. ktx_uint32_t* pRowPadding)
  757. {
  758. DECLARE_PROTECTED(ktxTexture);
  759. struct blockCount {
  760. ktx_uint32_t x;
  761. } blockCount;
  762. assert (This != NULL);
  763. assert(!This->isCompressed);
  764. assert(prtctd->_formatSize.blockWidth == 1U
  765. && prtctd->_formatSize.blockHeight == 1U
  766. && prtctd->_formatSize.blockDepth == 1U);
  767. blockCount.x = MAX(1, (This->baseWidth / prtctd->_formatSize.blockWidth) >> level);
  768. *numRows = MAX(1, (This->baseHeight / prtctd->_formatSize.blockHeight) >> level);
  769. *pRowLengthBytes = blockCount.x * prtctd->_formatSize.blockSizeInBits / 8;
  770. *pRowPadding = padRow(pRowLengthBytes);
  771. }
  772. /**
  773. * @memberof ktxTexture
  774. * @~English
  775. * @brief Return pitch betweeb rows of a texture image level in bytes.
  776. *
  777. * For uncompressed textures the pitch is the number of bytes between
  778. * rows of texels. For compressed textures it is the number of bytes
  779. * between rows of blocks. The value is padded to GL_UNPACK_ALIGNMENT,
  780. * if necessary. For all currently known compressed formats padding
  781. * will not be necessary.
  782. *
  783. * @param[in] This pointer to the ktxTexture object of interest.
  784. * @param[in] level level of interest.
  785. *
  786. * @return the row pitch in bytes.
  787. */
  788. ktx_uint32_t
  789. ktxTexture_GetRowPitch(ktxTexture* This, ktx_uint32_t level)
  790. {
  791. DECLARE_PROTECTED(ktxTexture)
  792. struct blockCount {
  793. ktx_uint32_t x;
  794. } blockCount;
  795. ktx_uint32_t pitch;
  796. blockCount.x = MAX(1, (This->baseWidth / prtctd->_formatSize.blockWidth) >> level);
  797. pitch = blockCount.x * prtctd->_formatSize.blockSizeInBits / 8;
  798. (void)padRow(&pitch);
  799. return pitch;
  800. }
  801. /**
  802. * @memberof ktxTexture @private
  803. * @~English
  804. * @brief Query if a ktxTexture has an active stream.
  805. *
  806. * Tests if a ktxTexture has unread image data. The internal stream is closed
  807. * once all the images have been read.
  808. *
  809. * @param[in] This pointer to the ktxTexture object of interest.
  810. *
  811. * @return KTX_TRUE if there is an active stream, KTX_FALSE otherwise.
  812. */
  813. ktx_bool_t
  814. ktxTexture_isActiveStream(ktxTexture* This)
  815. {
  816. assert(This != NULL);
  817. ktxStream* stream = ktxTexture_getStream(This);
  818. return stream->data.file != NULL;
  819. }
  820. /** @} */