/* -*- tab-width: 4; -*- */1/* vi: set sw=2 ts=4 expandtab: */23/*4* Copyright 2019-2020 The Khronos Group Inc.5* SPDX-License-Identifier: Apache-2.06*/78/**9* @internal10* @file11* @~English12*13* @brief ktxTexture1 implementation. Support for KTX format.14*15* @author Mark Callow, github.com/MarkCallow16*/1718#if defined(_WIN32)19#define _CRT_SECURE_NO_WARNINGS20#endif2122#include <stdlib.h>23#include <string.h>2425#include "dfdutils/dfd.h"26#include "ktx.h"27#include "ktxint.h"28#include "filestream.h"29#include "memstream.h"30#include "texture1.h"31#include "unused.h"32#include "gl_format.h"3334typedef struct ktxTexture1_private {35ktx_bool_t _needSwap;36} ktxTexture1_private;3738struct ktxTexture_vtbl ktxTexture1_vtbl;39struct ktxTexture_vtblInt ktxTexture1_vtblInt;4041static KTX_error_code42ktxTexture1_constructCommon(ktxTexture1* This)43{44assert(This != NULL);4546This->classId = ktxTexture1_c;47This->vtbl = &ktxTexture1_vtbl;48This->_protected->_vtbl = ktxTexture1_vtblInt;49This->_private = (ktxTexture1_private*)malloc(sizeof(ktxTexture1_private));50if (This->_private == NULL) {51return KTX_OUT_OF_MEMORY;52}53memset(This->_private, 0, sizeof(*This->_private));5455return KTX_SUCCESS;56}5758/**59* @memberof ktxTexture1 @private60* @copydoc ktxTexture2_construct61*/62static KTX_error_code63ktxTexture1_construct(ktxTexture1* This,64const ktxTextureCreateInfo* const createInfo,65ktxTextureCreateStorageEnum storageAllocation)66{67ktxTexture_protected* prtctd;68ktxFormatSize formatSize;69GLuint typeSize;70GLenum glFormat;71KTX_error_code result;7273memset(This, 0, sizeof(*This));7475This->glInternalformat = createInfo->glInternalformat;76glGetFormatSize(This->glInternalformat, &formatSize);77if (formatSize.blockSizeInBits == 0) {78// Most likely a deprecated legacy format.79return KTX_UNSUPPORTED_TEXTURE_TYPE;80}81glFormat= glGetFormatFromInternalFormat(createInfo->glInternalformat);82if (glFormat == GL_INVALID_VALUE) {83return KTX_INVALID_VALUE;84}85result = ktxTexture_construct(ktxTexture(This), createInfo, &formatSize);86if (result != KTX_SUCCESS)87return result;8889result = ktxTexture1_constructCommon(This);90if (result != KTX_SUCCESS)91return result;92prtctd = This->_protected;9394This->isCompressed95= (formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT);96if (This->isCompressed) {97This->glFormat = 0;98This->glBaseInternalformat = glFormat;99This->glType = 0;100prtctd->_typeSize = 1;101} else {102This->glBaseInternalformat = This->glFormat = glFormat;103This->glType104= glGetTypeFromInternalFormat(createInfo->glInternalformat);105if (This->glType == GL_INVALID_VALUE) {106result = KTX_INVALID_VALUE;107goto cleanup;108}109typeSize = glGetTypeSizeFromType(This->glType);110assert(typeSize != GL_INVALID_VALUE);111112/* Do some sanity checking */113if (typeSize != 1 &&114typeSize != 2 &&115typeSize != 4)116{117/* Only 8, 16, and 32-bit types are supported for byte-swapping.118* See UNPACK_SWAP_BYTES & table 8.4 in the OpenGL 4.4 spec.119*/120result = KTX_INVALID_VALUE;121goto cleanup;122}123prtctd->_typeSize = typeSize;124}125126if (storageAllocation == KTX_TEXTURE_CREATE_ALLOC_STORAGE) {127This->dataSize128= ktxTexture_calcDataSizeTexture(ktxTexture(This));129This->pData = malloc(This->dataSize);130if (This->pData == NULL) {131result = KTX_OUT_OF_MEMORY;132goto cleanup;133}134}135return result;136137cleanup:138ktxTexture1_destruct(This);139ktxTexture_destruct(ktxTexture(This));140return result;141}142143/**144* @memberof ktxTexture1 @private145* @brief Construct a ktxTexture1 from a ktxStream reading from a KTX source.146*147* The KTX header, that must have been read prior to calling this, is passed148* to the function.149*150* The stream object is copied into the constructed ktxTexture1.151*152* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,153* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This154* will minimize memory usage by allowing, for example, loading the images155* directly from the source into a Vulkan staging buffer.156*157* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is158* provided solely to enable implementation of the @e libktx v1 API on top of159* ktxTexture1.160*161* @param[in] This pointer to a ktxTexture1-sized block of memory to162* initialize.163* @param[in] pStream pointer to the stream to read.164* @param[in] pHeader pointer to a KTX header that has already been read from165* the stream.166* @param[in] createFlags bitmask requesting specific actions during creation.167*168* @return KTX_SUCCESS on success, other KTX_* enum values on error.169*170* @exception KTX_FILE_DATA_ERROR171* Source data is inconsistent with the KTX172* specification.173* @exception KTX_FILE_READ_ERROR174* An error occurred while reading the source.175* @exception KTX_FILE_UNEXPECTED_EOF176* Not enough data in the source.177* @exception KTX_OUT_OF_MEMORY Not enough memory to load either the images or178* the key-value data.179* @exception KTX_UNKNOWN_FILE_FORMAT180* The source is not in KTX format.181* @exception KTX_UNSUPPORTED_TEXTURE_TYPE182* The source describes a texture type not183* supported by OpenGL or Vulkan, e.g, a 3D array.184*/185KTX_error_code186ktxTexture1_constructFromStreamAndHeader(ktxTexture1* This, ktxStream* pStream,187KTX_header* pHeader,188ktxTextureCreateFlags createFlags)189{190ktxTexture1_private* private;191KTX_error_code result;192KTX_supplemental_info suppInfo;193ktxStream* stream;194ktx_off_t pos;195ktx_size_t size;196ktxFormatSize formatSize;197198assert(pHeader != NULL && pStream != NULL);199200memset(This, 0, sizeof(*This));201result = ktxTexture_constructFromStream(ktxTexture(This), pStream, createFlags);202if (result != KTX_SUCCESS)203return result;204result = ktxTexture1_constructCommon(This);205if (result != KTX_SUCCESS) {206ktxTexture_destruct(ktxTexture(This));207return result;208}209210private = This->_private;211stream = ktxTexture1_getStream(This);212213result = ktxCheckHeader1_(pHeader, &suppInfo);214if (result != KTX_SUCCESS)215goto cleanup;216217/*218* Initialize from pHeader info.219*/220This->glFormat = pHeader->glFormat;221This->glInternalformat = pHeader->glInternalformat;222This->glType = pHeader->glType;223glGetFormatSize(This->glInternalformat, &formatSize);224if (formatSize.blockSizeInBits == 0) {225// Most likely a deprecated legacy format.226result = KTX_UNSUPPORTED_TEXTURE_TYPE;227goto cleanup;228}229This->_protected->_formatSize = formatSize;230This->glBaseInternalformat = pHeader->glBaseInternalformat;231// Can these be done by a ktxTexture_constructFromStream?232This->numDimensions = suppInfo.textureDimension;233This->baseWidth = pHeader->pixelWidth;234assert(suppInfo.textureDimension > 0 && suppInfo.textureDimension < 4);235switch (suppInfo.textureDimension) {236case 1:237This->baseHeight = This->baseDepth = 1;238break;239case 2:240This->baseHeight = pHeader->pixelHeight;241This->baseDepth = 1;242break;243case 3:244This->baseHeight = pHeader->pixelHeight;245This->baseDepth = pHeader->pixelDepth;246break;247}248if (pHeader->numberOfArrayElements > 0) {249This->numLayers = pHeader->numberOfArrayElements;250This->isArray = KTX_TRUE;251} else {252This->numLayers = 1;253This->isArray = KTX_FALSE;254}255This->numFaces = pHeader->numberOfFaces;256if (pHeader->numberOfFaces == 6)257This->isCubemap = KTX_TRUE;258else259This->isCubemap = KTX_FALSE;260This->numLevels = pHeader->numberOfMipLevels;261This->isCompressed = suppInfo.compressed;262This->generateMipmaps = suppInfo.generateMipmaps;263if (pHeader->endianness == KTX_ENDIAN_REF_REV)264private->_needSwap = KTX_TRUE;265This->_protected->_typeSize = pHeader->glTypeSize;266267/*268* Make an empty hash list.269*/270ktxHashList_Construct(&This->kvDataHead);271/*272* Load KVData.273*/274if (pHeader->bytesOfKeyValueData > 0) {275if (!(createFlags & KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT)) {276ktx_uint32_t kvdLen = pHeader->bytesOfKeyValueData;277ktx_uint8_t* pKvd;278279pKvd = malloc(kvdLen);280if (pKvd == NULL) {281result = KTX_OUT_OF_MEMORY;282goto cleanup;283}284285result = stream->read(stream, pKvd, kvdLen);286if (result != KTX_SUCCESS) {287free(pKvd);288goto cleanup;289}290291if (private->_needSwap) {292/* Swap the counts inside the key & value data. */293ktx_uint8_t* src = pKvd;294ktx_uint8_t* end = pKvd + kvdLen;295while (src < end) {296ktx_uint32_t* pKeyAndValueByteSize = (ktx_uint32_t*)src;297_ktxSwapEndian32(pKeyAndValueByteSize, 1);298src += _KTX_PAD4(*pKeyAndValueByteSize);299}300}301302if (!(createFlags & KTX_TEXTURE_CREATE_RAW_KVDATA_BIT)) {303char* orientation;304ktx_uint32_t orientationLen;305306result = ktxHashList_Deserialize(&This->kvDataHead,307kvdLen, pKvd);308free(pKvd);309if (result != KTX_SUCCESS) {310goto cleanup;311}312313result = ktxHashList_FindValue(&This->kvDataHead,314KTX_ORIENTATION_KEY,315&orientationLen,316(void**)&orientation);317assert(result != KTX_INVALID_VALUE);318if (result == KTX_SUCCESS) {319ktx_uint32_t count;320char orient[4] = {0, 0, 0, 0};321322count = sscanf(orientation, KTX_ORIENTATION3_FMT,323&orient[0],324&orient[1],325&orient[2]);326327if (count > This->numDimensions) {328// KTX 1 is less strict than KTX2 so there is a chance329// of having more dimensions than needed.330count = This->numDimensions;331}332switch (This->numDimensions) {333case 3:334This->orientation.z = orient[2];335FALLTHROUGH;336case 2:337This->orientation.y = orient[1];338FALLTHROUGH;339case 1:340This->orientation.x = orient[0];341}342}343} else {344This->kvDataLen = kvdLen;345This->kvData = pKvd;346}347} else {348stream->skip(stream, pHeader->bytesOfKeyValueData);349}350}351352/*353* Get the size of the image data.354*/355result = stream->getsize(stream, &size);356if (result != KTX_SUCCESS)357goto cleanup;358359result = stream->getpos(stream, &pos);360if (result != KTX_SUCCESS)361goto cleanup;362363/* Remove space for faceLodSize fields */364This->dataSize = size - pos - This->numLevels * sizeof(ktx_uint32_t);365366/*367* Load the images, if requested.368*/369if (createFlags & KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT) {370result = ktxTexture1_LoadImageData(This, NULL, 0);371}372if (result == KTX_SUCCESS)373return result;374375cleanup:376ktxTexture1_destruct(This);377return result;378}379380/**381* @memberof ktxTexture1 @private382* @brief Construct a ktxTexture1 from a ktxStream reading from a KTX source.383*384* The stream object is copied into the constructed ktxTexture1.385*386* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,387* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This388* will minimize memory usage by allowing, for example, loading the images389* directly from the source into a Vulkan staging buffer.390*391* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is392* provided solely to enable implementation of the @e libktx v1 API on top of393* ktxTexture1.394*395* @param[in] This pointer to a ktxTexture1-sized block of memory to396* initialize.397* @param[in] pStream pointer to the stream to read.398* @param[in] createFlags bitmask requesting specific actions during creation.399*400* @return KTX_SUCCESS on success, other KTX_* enum values on error.401*402* @exception KTX_FILE_READ_ERROR403* An error occurred while reading the source.404*405* For other exceptions see ktxTexture1_constructFromStreamAndHeader().406*/407static KTX_error_code408ktxTexture1_constructFromStream(ktxTexture1* This, ktxStream* pStream,409ktxTextureCreateFlags createFlags)410{411KTX_header header;412KTX_error_code result;413414// Read header.415result = pStream->read(pStream, &header, KTX_HEADER_SIZE);416if (result != KTX_SUCCESS)417return result;418419return ktxTexture1_constructFromStreamAndHeader(This, pStream,420&header, createFlags);421}422423/**424* @memberof ktxTexture1 @private425* @brief Construct a ktxTexture1 from a stdio stream reading from a KTX source.426*427* See ktxTextureInt_constructFromStream for details.428*429* @note Do not close the stdio stream until you are finished with the texture430* object.431*432* @param[in] This pointer to a ktxTextureInt-sized block of memory to433* initialize.434* @param[in] stdioStream a stdio FILE pointer opened on the source.435* @param[in] createFlags bitmask requesting specific actions during creation.436*437* @return KTX_SUCCESS on success, other KTX_* enum values on error.438*439* @exception KTX_INVALID_VALUE Either @p stdiostream or @p This is null.440*441* For other exceptions, see ktxTexture_constructFromStream().442*/443static KTX_error_code444ktxTexture1_constructFromStdioStream(ktxTexture1* This, FILE* stdioStream,445ktxTextureCreateFlags createFlags)446{447ktxStream stream;448KTX_error_code result;449450if (stdioStream == NULL || This == NULL)451return KTX_INVALID_VALUE;452453result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE);454if (result == KTX_SUCCESS)455result = ktxTexture1_constructFromStream(This, &stream, createFlags);456return result;457}458459/**460* @memberof ktxTexture1 @private461* @brief Construct a ktxTexture1 from a named KTX file.462*463* The file name must be encoded in utf-8. On Windows convert unicode names464* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.465*466* See ktxTextureInt_constructFromStream for details.467*468* @param[in] This pointer to a ktxTextureInt-sized block of memory to469* initialize.470* @param[in] filename pointer to a char array containing the file name.471* @param[in] createFlags bitmask requesting specific actions during creation.472*473* @return KTX_SUCCESS on success, other KTX_* enum values on error.474*475* @exception KTX_FILE_OPEN_FAILED The file could not be opened.476* @exception KTX_INVALID_VALUE @p filename is @c NULL.477*478* For other exceptions, see ktxTexture_constructFromStream().479*/480static KTX_error_code481ktxTexture1_constructFromNamedFile(ktxTexture1* This,482const char* const filename,483ktxTextureCreateFlags createFlags)484{485FILE* file;486ktxStream stream;487KTX_error_code result;488489if (This == NULL || filename == NULL)490return KTX_INVALID_VALUE;491492file = ktxFOpenUTF8(filename, "rb");493if (!file)494return KTX_FILE_OPEN_FAILED;495496result = ktxFileStream_construct(&stream, file, KTX_TRUE);497if (result == KTX_SUCCESS)498result = ktxTexture1_constructFromStream(This, &stream, createFlags);499500return result;501}502503/**504* @memberof ktxTexture1 @private505* @brief Construct a ktxTexture1 from KTX-formatted data in memory.506*507* See ktxTextureInt_constructFromStream for details.508*509* @param[in] This pointer to a ktxTextureInt-sized block of memory to510* initialize.511* @param[in] bytes pointer to the memory containing the serialized KTX data.512* @param[in] size length of the KTX data in bytes.513* @param[in] createFlags bitmask requesting specific actions during creation.514*515* @return KTX_SUCCESS on success, other KTX_* enum values on error.516*517* @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0.518*519* For other exceptions, see ktxTexture_constructFromStream().520*/521static KTX_error_code522ktxTexture1_constructFromMemory(ktxTexture1* This,523const ktx_uint8_t* bytes, ktx_size_t size,524ktxTextureCreateFlags createFlags)525{526ktxStream stream;527KTX_error_code result;528529if (bytes == NULL || size == 0)530return KTX_INVALID_VALUE;531532result = ktxMemStream_construct_ro(&stream, bytes, size);533if (result == KTX_SUCCESS)534result = ktxTexture1_constructFromStream(This, &stream, createFlags);535536return result;537}538539void540ktxTexture1_destruct(ktxTexture1* This)541{542if (This->_private) free(This->_private);543ktxTexture_destruct(ktxTexture(This));544}545546/**547* @defgroup reader Reader548* @brief Read KTX-formatted data.549* @{550*/551552/**553* @memberof ktxTexture1554* @ingroup writer555* @brief Create a new empty ktxTexture1.556*557* The address of the newly created ktxTexture1 is written to the location558* pointed at by @p newTex.559*560* @param[in] createInfo pointer to a ktxTextureCreateInfo struct with561* information describing the texture.562* @param[in] storageAllocation563* enum indicating whether or not to allocate storage564* for the texture images.565* @param[in,out] newTex pointer to a location in which store the address of566* the newly created texture.567*568* @return KTX_SUCCESS on success, other KTX_* enum values on error.569*570* @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a571* valid OpenGL internal format value.572* @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2573* or 3.574* @exception KTX_INVALID_VALUE One of <tt>base{Width,Height,Depth}</tt> in575* @p createInfo is 0.576* @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6.577* @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0.578* @exception KTX_INVALID_OPERATION579* The <tt>base{Width,Height,Depth}</tt> specified580* in @p createInfo are inconsistent with581* @c numDimensions.582* @exception KTX_INVALID_OPERATION583* @p createInfo is requesting a 3D array or584* 3D cubemap texture.585* @exception KTX_INVALID_OPERATION586* @p createInfo is requesting a cubemap with587* non-square or non-2D images.588* @exception KTX_INVALID_OPERATION589* @p createInfo is requesting more mip levels590* than needed for the specified591* <tt>base{Width,Height,Depth}</tt>.592* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture's images.593*/594KTX_error_code595ktxTexture1_Create(const ktxTextureCreateInfo* const createInfo,596ktxTextureCreateStorageEnum storageAllocation,597ktxTexture1** newTex)598{599KTX_error_code result;600601if (newTex == NULL)602return KTX_INVALID_VALUE;603604ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));605if (tex == NULL)606return KTX_OUT_OF_MEMORY;607608result = ktxTexture1_construct(tex, createInfo, storageAllocation);609if (result != KTX_SUCCESS) {610free(tex);611} else {612*newTex = tex;613}614return result;615}616617/**618* @memberof ktxTexture1619* @~English620* @brief Create a ktxTexture1 from a stdio stream reading from a KTX source.621*622* The address of a newly created texture reflecting the contents of the623* stdio stream is written to the location pointed at by @p newTex.624*625* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,626* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This627* will minimize memory usage by allowing, for example, loading the images628* directly from the source into a Vulkan staging buffer.629*630* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is631* provided solely to enable implementation of the @e libktx v1 API on top of632* ktxTexture1.633*634* @param[in] stdioStream stdio FILE pointer created from the desired file.635* @param[in] createFlags bitmask requesting specific actions during creation.636* @param[in,out] newTex pointer to a location in which store the address of637* the newly created texture.638*639* @return KTX_SUCCESS on success, other KTX_* enum values on error.640*641* @exception KTX_INVALID_VALUE @p newTex is @c NULL.642* @exception KTX_FILE_DATA_ERROR643* Source data is inconsistent with the KTX644* specification.645* @exception KTX_FILE_READ_ERROR646* An error occurred while reading the source.647* @exception KTX_FILE_UNEXPECTED_EOF648* Not enough data in the source.649* @exception KTX_OUT_OF_MEMORY Not enough memory to create the texture object,650* load the images or load the key-value data.651* @exception KTX_UNKNOWN_FILE_FORMAT652* The source is not in KTX format.653* @exception KTX_UNSUPPORTED_TEXTURE_TYPE654* The source describes a texture type not655* supported by OpenGL or Vulkan, e.g, a 3D array.656*/657KTX_error_code658ktxTexture1_CreateFromStdioStream(FILE* stdioStream,659ktxTextureCreateFlags createFlags,660ktxTexture1** newTex)661{662KTX_error_code result;663if (newTex == NULL)664return KTX_INVALID_VALUE;665666ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));667if (tex == NULL)668return KTX_OUT_OF_MEMORY;669670result = ktxTexture1_constructFromStdioStream(tex, stdioStream,671createFlags);672if (result == KTX_SUCCESS)673*newTex = (ktxTexture1*)tex;674else {675free(tex);676*newTex = NULL;677}678return result;679}680681/**682* @memberof ktxTexture1683* @~English684* @brief Create a ktxTexture1 from a named KTX file.685*686* The address of a newly created texture reflecting the contents of the687* file is written to the location pointed at by @p newTex.688*689* The file name must be encoded in utf-8. On Windows convert unicode names690* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.691*692* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,693* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This694* will minimize memory usage by allowing, for example, loading the images695* directly from the source into a Vulkan staging buffer.696*697* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is698* provided solely to enable implementation of the @e libktx v1 API on top of699* ktxTexture1.700*701* @param[in] filename pointer to a char array containing the file name.702* @param[in] createFlags bitmask requesting specific actions during creation.703* @param[in,out] newTex pointer to a location in which store the address of704* the newly created texture.705*706* @return KTX_SUCCESS on success, other KTX_* enum values on error.707*708* @exception KTX_FILE_OPEN_FAILED The file could not be opened.709* @exception KTX_INVALID_VALUE @p filename is @c NULL.710*711* For other exceptions, see ktxTexture1_CreateFromStdioStream().712*/713KTX_error_code714ktxTexture1_CreateFromNamedFile(const char* const filename,715ktxTextureCreateFlags createFlags,716ktxTexture1** newTex)717{718KTX_error_code result;719720if (newTex == NULL)721return KTX_INVALID_VALUE;722723ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));724if (tex == NULL)725return KTX_OUT_OF_MEMORY;726727result = ktxTexture1_constructFromNamedFile(tex, filename, createFlags);728if (result == KTX_SUCCESS)729*newTex = (ktxTexture1*)tex;730else {731free(tex);732*newTex = NULL;733}734return result;735}736737/**738* @memberof ktxTexture1739* @~English740* @brief Create a ktxTexture1 from KTX-formatted data in memory.741*742* The address of a newly created texture reflecting the contents of the743* serialized KTX data is written to the location pointed at by @p newTex.744*745* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,746* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This747* will minimize memory usage by allowing, for example, loading the images748* directly from the source into a Vulkan staging buffer.749*750* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is751* provided solely to enable implementation of the @e libktx v1 API on top of752* ktxTexture1.753*754* @param[in] bytes pointer to the memory containing the serialized KTX data.755* @param[in] size length of the KTX data in bytes.756* @param[in] createFlags bitmask requesting specific actions during creation.757* @param[in,out] newTex pointer to a location in which store the address of758* the newly created texture.759*760* @return KTX_SUCCESS on success, other KTX_* enum values on error.761*762* @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0.763*764* For other exceptions, see ktxTexture1_CreateFromStdioStream().765*/766KTX_error_code767ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size,768ktxTextureCreateFlags createFlags,769ktxTexture1** newTex)770{771KTX_error_code result;772if (newTex == NULL)773return KTX_INVALID_VALUE;774775ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));776if (tex == NULL)777return KTX_OUT_OF_MEMORY;778779result = ktxTexture1_constructFromMemory(tex, bytes, size,780createFlags);781if (result == KTX_SUCCESS)782*newTex = (ktxTexture1*)tex;783else {784free(tex);785*newTex = NULL;786}787return result;788}789790/**791* @memberof ktxTexture1792* @~English793* @brief Create a ktxTexture1 from KTX-formatted data from a `ktxStream`.794*795* The address of a newly created texture reflecting the contents of the796* serialized KTX data is written to the location pointed at by @p newTex.797*798* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,799* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This800* will minimize memory usage by allowing, for example, loading the images801* directly from the source into a Vulkan staging buffer.802*803* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is804* provided solely to enable implementation of the @e libktx v1 API on top of805* ktxTexture1.806*807* @param[in] pStream pointer to the stream to read KTX data from.808* @param[in] createFlags bitmask requesting specific actions during creation.809* @param[in,out] newTex pointer to a location in which store the address of810* the newly created texture.811*812* @return KTX_SUCCESS on success, other KTX_* enum values on error.813*814* For exceptions, see ktxTexture1_CreateFromStdioStream().815*/816KTX_error_code817ktxTexture1_CreateFromStream(ktxStream* pStream,818ktxTextureCreateFlags createFlags,819ktxTexture1** newTex)820{821KTX_error_code result;822if (newTex == NULL)823return KTX_INVALID_VALUE;824825ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));826if (tex == NULL)827return KTX_OUT_OF_MEMORY;828829result = ktxTexture1_constructFromStream(tex, pStream, createFlags);830if (result == KTX_SUCCESS)831*newTex = (ktxTexture1*)tex;832else {833free(tex);834*newTex = NULL;835}836return result;837}838839/**840* @memberof ktxTexture1841* @~English842* @brief Destroy a ktxTexture1 object.843*844* This frees the memory associated with the texture contents and the memory845* of the ktxTexture1 object. This does @e not delete any OpenGL or Vulkan846* texture objects created by ktxTexture1_GLUpload or ktxTexture1_VkUpload.847*848* @param[in] This pointer to the ktxTexture1 object to destroy849*/850void851ktxTexture1_Destroy(ktxTexture1* This)852{853ktxTexture1_destruct(This);854free(This);855}856857/**858* @memberof ktxTexture @private859* @~English860* @brief Calculate the size of the image data for the specified number861* of levels.862*863* The data size is the sum of the sizes of each level up to the number864* specified and includes any @c mipPadding.865*866* @param[in] This pointer to the ktxTexture object of interest.867* @param[in] levels number of levels whose data size to return.868*869* @return the data size in bytes.870*/871ktx_size_t872ktxTexture1_calcDataSizeLevels(ktxTexture1* This, ktx_uint32_t levels)873{874ktx_uint32_t i;875ktx_size_t dataSize = 0;876877assert(This != NULL);878assert(levels <= This->numLevels);879for (i = 0; i < levels; i++) {880ktx_size_t levelSize = ktxTexture_calcLevelSize(ktxTexture(This), i,881KTX_FORMAT_VERSION_ONE);882/* mipPadding. NOTE: this adds padding after the last level too. */883#if KTX_GL_UNPACK_ALIGNMENT != 4884dataSize += _KTX_PAD4(levelSize);885#else886dataSize += levelSize;887#endif888}889return dataSize;890}891892/**893* @memberof ktxTexture1 @private894* @~English895*896* @copydoc ktxTexture::ktxTexture_doCalcFaceLodSize897*/898ktx_size_t899ktxTexture1_calcFaceLodSize(ktxTexture1* This, ktx_uint32_t level)900{901return ktxTexture_doCalcFaceLodSize(ktxTexture(This), level,902KTX_FORMAT_VERSION_ONE);903}904905/**906* @memberof ktxTexture @private907* @~English908* @brief Return the offset of a level in bytes from the start of the image909* data in a ktxTexture.910*911* The caclulated size does not include space for storing the @c imageSize912* fields of each mip level.913*914* @param[in] This pointer to the ktxTexture object of interest.915* @param[in] level level whose offset to return.916* @param[in] fv enum specifying format version for which to calculate917* image size.918*919* @return the data size in bytes.920*/921ktx_size_t922ktxTexture1_calcLevelOffset(ktxTexture1* This, ktx_uint32_t level)923{924assert (This != NULL);925assert (level < This->numLevels);926return ktxTexture1_calcDataSizeLevels(This, level);927}928929/**930* @memberof ktxTexture1931* @~English932* @brief Find the offset of an image within a ktxTexture's image data.933*934* As there is no such thing as a 3D cubemap we make the 3rd location parameter935* do double duty.936*937* @param[in] This pointer to the ktxTexture object of interest.938* @param[in] level mip level of the image.939* @param[in] layer array layer of the image.940* @param[in] faceSlice cube map face or depth slice of the image.941* @param[in,out] pOffset pointer to location to store the offset.942*943* @return KTX_SUCCESS on success, other KTX_* enum values on error.944*945* @exception KTX_INVALID_OPERATION946* @p level, @p layer or @p faceSlice exceed the947* dimensions of the texture.948* @exception KTX_INVALID_VALID @p This is NULL.949*/950KTX_error_code951ktxTexture1_GetImageOffset(ktxTexture1* This, ktx_uint32_t level,952ktx_uint32_t layer, ktx_uint32_t faceSlice,953ktx_size_t* pOffset)954{955956if (This == NULL)957return KTX_INVALID_VALUE;958959if (level >= This->numLevels || layer >= This->numLayers)960return KTX_INVALID_OPERATION;961962if (This->isCubemap) {963if (faceSlice >= This->numFaces)964return KTX_INVALID_OPERATION;965} else {966ktx_uint32_t maxSlice = MAX(1, This->baseDepth >> level);967if (faceSlice >= maxSlice)968return KTX_INVALID_OPERATION;969}970971// Get the size of the data up to the start of the indexed level.972*pOffset = ktxTexture_calcDataSizeLevels(ktxTexture(This), level);973974// All layers, faces & slices within a level are the same size.975if (layer != 0) {976ktx_size_t layerSize;977layerSize = ktxTexture_layerSize(ktxTexture(This), level,978KTX_FORMAT_VERSION_ONE);979*pOffset += layer * layerSize;980}981if (faceSlice != 0) {982ktx_size_t imageSize;983imageSize = ktxTexture_GetImageSize(ktxTexture(This), level);984#if (KTX_GL_UNPACK_ALIGNMENT != 4)985if (This->isCubemap)986_KTX_PAD4(imageSize); // Account for cubePadding.987#endif988*pOffset += faceSlice * imageSize;989}990991return KTX_SUCCESS;992}993994/**995* @memberof ktxTexture1996* @~English997* @brief Return the total size in bytes of the uncompressed data of a ktxTexture1.998*999* This always returns the value of @c This->dataSize. The function is provided for1000* symmetry with ktxTexture2.1001*1002* @param[in] This pointer to the ktxTexture1 object of interest.1003* @return The size of the data in the texture.1004*/1005ktx_size_t1006ktxTexture1_GetDataSizeUncompressed(ktxTexture1* This)1007{1008return This->dataSize;1009}10101011/**1012* @memberof ktxTexture11013* @~English1014* @brief Calculate & return the size in bytes of an image at the specified1015* mip level.1016*1017* For arrays, this is the size of a layer, for cubemaps, the size of a face1018* and for 3D textures, the size of a depth slice.1019*1020* The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT.1021*1022* @param[in] This pointer to the ktxTexture1 object of interest.1023* @param[in] level level of interest.1024*/1025ktx_size_t1026ktxTexture1_GetImageSize(ktxTexture1* This, ktx_uint32_t level)1027{1028return ktxTexture_calcImageSize(ktxTexture(This), level,1029KTX_FORMAT_VERSION_ONE);1030}10311032/**1033* @memberof ktxTexture11034* @~English1035* @brief Calculate & return the size in bytes of all the images in the specified1036* mip level.1037*1038* For arrays, this is the size of all layers in the level, for cubemaps, the size of all1039* faces in the level and for 3D textures, the size of all depth slices in the level.1040*1041* The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT.1042*1043* @param[in] This pointer to the ktxTexture1 object of interest.1044* @param[in] level level of interest.1045*/1046ktx_size_t1047ktxTexture1_GetLevelSize(ktxTexture1* This, ktx_uint32_t level)1048{1049return ktxTexture_calcLevelSize(ktxTexture(This), level,1050KTX_FORMAT_VERSION_ONE);1051}10521053/**1054* @memberof ktxTexture1 @private1055* @~English1056* @brief Return the size of the primitive type of a single color component1057*1058* @param[in] This pointer to the ktxTexture1 object of interest.1059*1060* @return the type size in bytes.1061*/1062ktx_uint32_t1063ktxTexture1_glTypeSize(ktxTexture1* This)1064{1065assert(This != NULL);1066return This->_protected->_typeSize;1067}10681069/**1070* @memberof ktxTexture11071* @~English1072* @brief Iterate over the mip levels in a ktxTexture1 object.1073*1074* This is almost identical to @ref ktxTexture::ktxTexture_IterateLevelFaces1075* "ktxTexture_IterateLevelFaces". The difference is that the blocks of image1076* data for non-array cube maps include all faces of a mip level.1077*1078* This function works even if @p This->pData == 0 so it can be used to1079* obtain offsets and sizes for each level by callers who have loaded the data1080* externally.1081*1082* @param[in] This handle of the 1 opened on the data.1083* @param[in,out] iterCb the address of a callback function which is called1084* with the data for each image block.1085* @param[in,out] userdata the address of application-specific data which is1086* passed to the callback along with the image data.1087*1088* @return KTX_SUCCESS on success, other KTX_* enum values on error. The1089* following are returned directly by this function. @p iterCb may1090* return these for other causes or may return additional errors.1091*1092* @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not1093* decreasing1094* @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.1095*1096*/1097KTX_error_code1098ktxTexture1_IterateLevels(ktxTexture1* This, PFNKTXITERCB iterCb, void* userdata)1099{1100ktx_uint32_t miplevel;1101KTX_error_code result = KTX_SUCCESS;11021103if (This == NULL)1104return KTX_INVALID_VALUE;11051106if (iterCb == NULL)1107return KTX_INVALID_VALUE;11081109for (miplevel = 0; miplevel < This->numLevels; ++miplevel)1110{1111GLsizei width, height, depth;1112ktx_uint32_t levelSize;1113ktx_size_t offset;11141115/* Array textures have the same number of layers at each mip level. */1116width = MAX(1, This->baseWidth >> miplevel);1117height = MAX(1, This->baseHeight >> miplevel);1118depth = MAX(1, This->baseDepth >> miplevel);11191120levelSize = (ktx_uint32_t)ktxTexture_calcLevelSize(ktxTexture(This),1121miplevel,1122KTX_FORMAT_VERSION_ONE);11231124/* All array layers are passed in a group because that is how1125* GL & Vulkan need them. Hence no1126* for (layer = 0; layer < This->numLayers)1127*/1128ktxTexture_GetImageOffset(ktxTexture(This), miplevel, 0, 0, &offset);1129result = iterCb(miplevel, 0, width, height, depth,1130levelSize, This->pData + offset, userdata);1131if (result != KTX_SUCCESS)1132break;1133}11341135return result;1136}11371138/**1139* @memberof ktxTexture11140* @~English1141* @brief Iterate over the images in a ktxTexture1 object while loading the1142* image data.1143*1144* This operates similarly to @ref ktxTexture::ktxTexture_IterateLevelFaces1145* "ktxTexture_IterateLevelFaces" except that it loads the images from the1146* ktxTexture1's source to a temporary buffer while iterating. The callback1147* function must copy the image data if it wishes to preserve it as the1148* temporary buffer is reused for each level and is freed when this function1149* exits.1150*1151* This function is helpful for reducing memory usage when uploading the data1152* to a graphics API.1153*1154* @param[in] This pointer to the ktxTexture1 object of interest.1155* @param[in,out] iterCb the address of a callback function which is called1156* with the data for each image.1157* @param[in,out] userdata the address of application-specific data which is1158* passed to the callback along with the image data.1159*1160* @return KTX_SUCCESS on success, other KTX_* enum values on error. The1161* following are returned directly by this function. @p iterCb may1162* return these for other causes or may return additional errors.1163*1164* @exception KTX_FILE_DATA_ERROR mip level sizes are increasing not1165* decreasing1166* @exception KTX_INVALID_OPERATION the ktxTexture1 was not created from a1167* stream, i.e there is no data to load, or1168* this ktxTexture1's images have already1169* been loaded.1170* @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.1171* @exception KTX_OUT_OF_MEMORY not enough memory to allocate a block to1172* hold the base level image.1173*/1174KTX_error_code1175ktxTexture1_IterateLoadLevelFaces(ktxTexture1* This, PFNKTXITERCB iterCb,1176void* userdata)1177{1178DECLARE_PRIVATE(ktxTexture1);1179struct ktxTexture_protected* prtctd = This->_protected;1180ktxStream* stream = (ktxStream *)&prtctd->_stream;1181ktx_uint32_t dataSize = 0;1182ktx_uint32_t miplevel;1183KTX_error_code result = KTX_SUCCESS;1184void* data = NULL;11851186if (This == NULL)1187return KTX_INVALID_VALUE;11881189if (This->classId != ktxTexture1_c)1190return KTX_INVALID_OPERATION;11911192if (iterCb == NULL)1193return KTX_INVALID_VALUE;11941195if (prtctd->_stream.data.file == NULL)1196// This Texture not created from a stream or images are already loaded.1197return KTX_INVALID_OPERATION;11981199for (miplevel = 0; miplevel < This->numLevels; ++miplevel)1200{1201ktx_uint32_t faceLodSize;1202ktx_uint32_t faceLodSizePadded;1203ktx_uint32_t face;1204ktx_uint32_t innerIterations;1205GLsizei width, height, depth;12061207/* Array textures have the same number of layers at each mip level. */1208width = MAX(1, This->baseWidth >> miplevel);1209height = MAX(1, This->baseHeight >> miplevel);1210depth = MAX(1, This->baseDepth >> miplevel);12111212result = stream->read(stream, &faceLodSize, sizeof(ktx_uint32_t));1213if (result != KTX_SUCCESS) {1214goto cleanup;1215}1216if (private->_needSwap) {1217_ktxSwapEndian32(&faceLodSize, 1);1218}1219#if (KTX_GL_UNPACK_ALIGNMENT != 4)1220faceLodSizePadded = _KTX_PAD4(faceLodSize);1221#else1222faceLodSizePadded = faceLodSize;1223#endif1224if (!data) {1225/* allocate memory sufficient for the base miplevel */1226data = malloc(faceLodSizePadded);1227if (!data) {1228result = KTX_OUT_OF_MEMORY;1229goto cleanup;1230}1231dataSize = faceLodSizePadded;1232}1233else if (dataSize < faceLodSizePadded) {1234/* subsequent miplevels cannot be larger than the base miplevel */1235result = KTX_FILE_DATA_ERROR;1236goto cleanup;1237}12381239/* All array layers are passed in a group because that is how1240* GL & Vulkan need them. Hence no1241* for (layer = 0; layer < This->numLayers)1242*/1243if (This->isCubemap && !This->isArray)1244innerIterations = This->numFaces;1245else1246innerIterations = 1;1247for (face = 0; face < innerIterations; ++face)1248{1249/* And all z_slices are also passed as a group hence no1250* for (z_slice = 0; z_slice < This->depth)1251*/1252result = stream->read(stream, data, faceLodSizePadded);1253if (result != KTX_SUCCESS) {1254goto cleanup;1255}12561257/* Perform endianness conversion on texture data */1258if (private->_needSwap) {1259if (prtctd->_typeSize == 2)1260_ktxSwapEndian16((ktx_uint16_t*)data, faceLodSize / 2);1261else if (prtctd->_typeSize == 4)1262_ktxSwapEndian32((ktx_uint32_t*)data, faceLodSize / 4);1263}12641265result = iterCb(miplevel, face,1266width, height, depth,1267faceLodSize, data, userdata);1268}1269}12701271cleanup:1272free(data);1273// No further need for this.1274stream->destruct(stream);12751276return result;1277}12781279/**1280* @memberof ktxTexture11281* @~English1282* @brief Load all the image data from the ktxTexture1's source.1283*1284* The data is loaded into the provided buffer or to an internally allocated1285* buffer, if @p pBuffer is @c NULL.1286*1287* @param[in] This pointer to the ktxTexture object of interest.1288* @param[in] pBuffer pointer to the buffer in which to load the image data.1289* @param[in] bufSize size of the buffer pointed at by @p pBuffer.1290*1291* @return KTX_SUCCESS on success, other KTX_* enum values on error.1292*1293* @exception KTX_INVALID_VALUE @p This is NULL.1294* @exception KTX_INVALID_VALUE @p bufSize is less than the the image data size.1295* @exception KTX_INVALID_OPERATION1296* The data has already been loaded or the1297* ktxTexture was not created from a KTX source.1298* @exception KTX_OUT_OF_MEMORY Insufficient memory for the image data.1299*/1300KTX_error_code1301ktxTexture1_LoadImageData(ktxTexture1* This,1302ktx_uint8_t* pBuffer, ktx_size_t bufSize)1303{1304DECLARE_PROTECTED(ktxTexture);1305DECLARE_PRIVATE(ktxTexture1);1306ktx_uint32_t miplevel;1307ktx_uint8_t* pDest;1308ktx_uint8_t* pDestEnd;1309KTX_error_code result = KTX_SUCCESS;13101311if (This == NULL)1312return KTX_INVALID_VALUE;13131314if (prtctd->_stream.data.file == NULL)1315// This Texture not created from a stream or images already loaded;1316return KTX_INVALID_OPERATION;13171318if (pBuffer == NULL) {1319This->pData = malloc(This->dataSize);1320if (This->pData == NULL)1321return KTX_OUT_OF_MEMORY;1322pDest = This->pData;1323pDestEnd = pDest + This->dataSize;1324} else if (bufSize < This->dataSize) {1325return KTX_INVALID_VALUE;1326} else {1327pDest = pBuffer;1328pDestEnd = pBuffer + bufSize;1329}13301331// Need to loop through for correct byte swapping1332for (miplevel = 0; miplevel < This->numLevels; ++miplevel)1333{1334ktx_uint32_t faceLodSize;1335ktx_uint32_t faceLodSizePadded;1336ktx_uint32_t face;1337ktx_uint32_t innerIterations;13381339result = prtctd->_stream.read(&prtctd->_stream, &faceLodSize,1340sizeof(ktx_uint32_t));1341if (result != KTX_SUCCESS) {1342goto cleanup;1343}1344if (private->_needSwap) {1345_ktxSwapEndian32(&faceLodSize, 1);1346}1347#if (KTX_GL_UNPACK_ALIGNMENT != 4)1348faceLodSizePadded = _KTX_PAD4(faceLodSize);1349#else1350faceLodSizePadded = faceLodSize;1351#endif13521353if (This->isCubemap && !This->isArray)1354innerIterations = This->numFaces;1355else1356innerIterations = 1;1357for (face = 0; face < innerIterations; ++face)1358{1359if (pDest + faceLodSizePadded > pDestEnd) {1360result = KTX_INVALID_VALUE;1361goto cleanup;1362}1363result = prtctd->_stream.read(&prtctd->_stream, pDest,1364faceLodSizePadded);1365if (result != KTX_SUCCESS) {1366goto cleanup;1367}13681369/* Perform endianness conversion on texture data */1370if (private->_needSwap) {1371if (prtctd->_typeSize == 2)1372_ktxSwapEndian16((ktx_uint16_t*)pDest, faceLodSize / 2);1373else if (prtctd->_typeSize == 4)1374_ktxSwapEndian32((ktx_uint32_t*)pDest, faceLodSize / 4);1375}13761377pDest += faceLodSizePadded;1378}1379}13801381cleanup:1382// No further need for This->1383prtctd->_stream.destruct(&prtctd->_stream);1384return result;1385}13861387ktx_bool_t1388ktxTexture1_NeedsTranscoding(ktxTexture1* This)1389{1390UNUSED(This);1391return KTX_FALSE;1392}13931394#if !KTX_FEATURE_WRITE13951396/*1397* Stubs for writer functions that return a proper error code1398*/13991400KTX_error_code1401ktxTexture1_SetImageFromMemory(ktxTexture1* This, ktx_uint32_t level,1402ktx_uint32_t layer, ktx_uint32_t faceSlice,1403const ktx_uint8_t* src, ktx_size_t srcSize)1404{1405UNUSED(This);1406UNUSED(level);1407UNUSED(layer);1408UNUSED(faceSlice);1409UNUSED(src);1410UNUSED(srcSize);1411return KTX_INVALID_OPERATION;1412}14131414KTX_error_code1415ktxTexture1_SetImageFromStdioStream(ktxTexture1* This, ktx_uint32_t level,1416ktx_uint32_t layer, ktx_uint32_t faceSlice,1417FILE* src, ktx_size_t srcSize)1418{1419UNUSED(This);1420UNUSED(level);1421UNUSED(layer);1422UNUSED(faceSlice);1423UNUSED(src);1424UNUSED(srcSize);1425return KTX_INVALID_OPERATION;1426}14271428KTX_error_code1429ktxTexture1_WriteToStdioStream(ktxTexture1* This, FILE* dstsstr)1430{1431UNUSED(This);1432UNUSED(dstsstr);1433return KTX_INVALID_OPERATION;1434}14351436KTX_error_code1437ktxTexture1_WriteToNamedFile(ktxTexture1* This, const char* const dstname)1438{1439UNUSED(This);1440UNUSED(dstname);1441return KTX_INVALID_OPERATION;1442}14431444KTX_error_code1445ktxTexture1_WriteToMemory(ktxTexture1* This,1446ktx_uint8_t** ppDstBytes, ktx_size_t* pSize)1447{1448UNUSED(This);1449UNUSED(ppDstBytes);1450UNUSED(pSize);1451return KTX_INVALID_OPERATION;1452}14531454KTX_error_code1455ktxTexture1_WriteToStream(ktxTexture1* This,1456ktxStream* dststr)1457{1458UNUSED(This);1459UNUSED(dststr);1460return KTX_INVALID_OPERATION;1461}14621463#endif14641465/*1466* Initialized here at the end to avoid the need for multiple declarations of1467* these functions.1468*/14691470struct ktxTexture_vtblInt ktxTexture1_vtblInt = {1471(PFNCALCDATASIZELEVELS)ktxTexture1_calcDataSizeLevels,1472(PFNCALCFACELODSIZE)ktxTexture1_calcFaceLodSize,1473(PFNCALCLEVELOFFSET)ktxTexture1_calcLevelOffset1474};14751476struct ktxTexture_vtbl ktxTexture1_vtbl = {1477(PFNKTEXDESTROY)ktxTexture1_Destroy,1478(PFNKTEXGETIMAGEOFFSET)ktxTexture1_GetImageOffset,1479(PFNKTEXGETDATASIZEUNCOMPRESSED)ktxTexture1_GetDataSizeUncompressed,1480(PFNKTEXGETIMAGESIZE)ktxTexture1_GetImageSize,1481(PFNKTEXGETLEVELSIZE)ktxTexture1_GetLevelSize,1482(PFNKTEXITERATELEVELS)ktxTexture1_IterateLevels,1483(PFNKTEXITERATELOADLEVELFACES)ktxTexture1_IterateLoadLevelFaces,1484(PFNKTEXNEEDSTRANSCODING)ktxTexture1_NeedsTranscoding,1485(PFNKTEXLOADIMAGEDATA)ktxTexture1_LoadImageData,1486(PFNKTEXSETIMAGEFROMMEMORY)ktxTexture1_SetImageFromMemory,1487(PFNKTEXSETIMAGEFROMSTDIOSTREAM)ktxTexture1_SetImageFromStdioStream,1488(PFNKTEXWRITETOSTDIOSTREAM)ktxTexture1_WriteToStdioStream,1489(PFNKTEXWRITETONAMEDFILE)ktxTexture1_WriteToNamedFile,1490(PFNKTEXWRITETOMEMORY)ktxTexture1_WriteToMemory,1491(PFNKTEXWRITETOSTREAM)ktxTexture1_WriteToStream,1492};14931494/** @} */1495149614971498