/* -*- tab-width: 4; -*- */ /* vi: set sw=2 ts=4 expandtab: */ /* * Copyright 2019-2020 The Khronos Group Inc. * SPDX-License-Identifier: Apache-2.0 */ /** * @internal * @file texture2.c * @~English * * @brief ktxTexture1 implementation. Support for KTX format. * * @author Mark Callow, www.edgewise-consulting.com */ #if defined(_WIN32) #define _CRT_SECURE_NO_WARNINGS #endif #include <stdlib.h> #include <string.h> #include "dfdutils/dfd.h" #include "ktx.h" #include "ktxint.h" #include "filestream.h" #include "memstream.h" #include "texture1.h" #include "unused.h" #include "gl_format.h" ktxTexture1_private; struct ktxTexture_vtbl ktxTexture1_vtbl; struct ktxTexture_vtblInt ktxTexture1_vtblInt; static KTX_error_code ktxTexture1_constructCommon(ktxTexture1* This) { … } /** * @memberof ktxTexture1 @private * @copydoc ktxTexture2_construct */ static KTX_error_code ktxTexture1_construct(ktxTexture1* This, ktxTextureCreateInfo* createInfo, ktxTextureCreateStorageEnum storageAllocation) { … } /** * @memberof ktxTexture1 @private * @brief Construct a ktxTexture1 from a ktxStream reading from a KTX source. * * The KTX header, that must have been read prior to calling this, is passed * to the function. * * The stream object is copied into the constructed ktxTexture1. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This * will minimize memory usage by allowing, for example, loading the images * directly from the source into a Vulkan staging buffer. * * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is * provided solely to enable implementation of the @e libktx v1 API on top of * ktxTexture1. * * @param[in] This pointer to a ktxTexture1-sized block of memory to * initialize. * @param[in] pStream pointer to the stream to read. * @param[in] pHeader pointer to a KTX header that has already been read from * the stream. * @param[in] createFlags bitmask requesting specific actions during creation. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_FILE_DATA_ERROR * Source data is inconsistent with the KTX * specification. * @exception KTX_FILE_READ_ERROR * An error occurred while reading the source. * @exception KTX_FILE_UNEXPECTED_EOF * Not enough data in the source. * @exception KTX_OUT_OF_MEMORY Not enough memory to load either the images or * the key-value data. * @exception KTX_UNKNOWN_FILE_FORMAT * The source is not in KTX format. * @exception KTX_UNSUPPORTED_TEXTURE_TYPE * The source describes a texture type not * supported by OpenGL or Vulkan, e.g, a 3D array. */ KTX_error_code ktxTexture1_constructFromStreamAndHeader(ktxTexture1* This, ktxStream* pStream, KTX_header* pHeader, ktxTextureCreateFlags createFlags) { … } /** * @memberof ktxTexture1 @private * @brief Construct a ktxTexture1 from a ktxStream reading from a KTX source. * * The stream object is copied into the constructed ktxTexture1. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This * will minimize memory usage by allowing, for example, loading the images * directly from the source into a Vulkan staging buffer. * * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is * provided solely to enable implementation of the @e libktx v1 API on top of * ktxTexture1. * * @param[in] This pointer to a ktxTexture1-sized block of memory to * initialize. * @param[in] pStream pointer to the stream to read. * @param[in] createFlags bitmask requesting specific actions during creation. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_FILE_READ_ERROR * An error occurred while reading the source. * * For other exceptions see ktxTexture1_constructFromStreamAndHeader(). */ static KTX_error_code ktxTexture1_constructFromStream(ktxTexture1* This, ktxStream* pStream, ktxTextureCreateFlags createFlags) { … } /** * @memberof ktxTexture1 @private * @brief Construct a ktxTexture1 from a stdio stream reading from a KTX source. * * See ktxTextureInt_constructFromStream for details. * * @note Do not close the stdio stream until you are finished with the texture * object. * * @param[in] This pointer to a ktxTextureInt-sized block of memory to * initialize. * @param[in] stdioStream a stdio FILE pointer opened on the source. * @param[in] createFlags bitmask requesting specific actions during creation. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_INVALID_VALUE Either @p stdiostream or @p This is null. * * For other exceptions, see ktxTexture_constructFromStream(). */ static KTX_error_code ktxTexture1_constructFromStdioStream(ktxTexture1* This, FILE* stdioStream, ktxTextureCreateFlags createFlags) { … } /** * @memberof ktxTexture1 @private * @brief Construct a ktxTexture1 from a named KTX file. * * The file name must be encoded in utf-8. On Windows convert unicode names * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. * * See ktxTextureInt_constructFromStream for details. * * @param[in] This pointer to a ktxTextureInt-sized block of memory to * initialize. * @param[in] filename pointer to a char array containing the file name. * @param[in] createFlags bitmask requesting specific actions during creation. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_FILE_OPEN_FAILED The file could not be opened. * @exception KTX_INVALID_VALUE @p filename is @c NULL. * * For other exceptions, see ktxTexture_constructFromStream(). */ static KTX_error_code ktxTexture1_constructFromNamedFile(ktxTexture1* This, const char* const filename, ktxTextureCreateFlags createFlags) { … } /** * @memberof ktxTexture1 @private * @brief Construct a ktxTexture1 from KTX-formatted data in memory. * * See ktxTextureInt_constructFromStream for details. * * @param[in] This pointer to a ktxTextureInt-sized block of memory to * initialize. * @param[in] bytes pointer to the memory containing the serialized KTX data. * @param[in] size length of the KTX data in bytes. * @param[in] createFlags bitmask requesting specific actions during creation. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. * * For other exceptions, see ktxTexture_constructFromStream(). */ static KTX_error_code ktxTexture1_constructFromMemory(ktxTexture1* This, const ktx_uint8_t* bytes, ktx_size_t size, ktxTextureCreateFlags createFlags) { … } void ktxTexture1_destruct(ktxTexture1* This) { … } /** * @defgroup reader Reader * @brief Read KTX-formatted data. * @{ */ /** * @memberof ktxTexture1 * @ingroup writer * @brief Create a new empty ktxTexture1. * * The address of the newly created ktxTexture1 is written to the location * pointed at by @p newTex. * * @param[in] createInfo pointer to a ktxTextureCreateInfo struct with * information describing the texture. * @param[in] storageAllocation * enum indicating whether or not to allocate storage * for the texture images. * @param[in,out] newTex pointer to a location in which store the address of * the newly created texture. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a * valid OpenGL internal format value. * @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2 * or 3. * @exception KTX_INVALID_VALUE One of <tt>base{Width,Height,Depth}</tt> in * @p createInfo is 0. * @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6. * @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0. * @exception KTX_INVALID_OPERATION * The <tt>base{Width,Height,Depth}</tt> specified * in @p createInfo are inconsistent with * @c numDimensions. * @exception KTX_INVALID_OPERATION * @p createInfo is requesting a 3D array or * 3D cubemap texture. * @exception KTX_INVALID_OPERATION * @p createInfo is requesting a cubemap with * non-square or non-2D images. * @exception KTX_INVALID_OPERATION * @p createInfo is requesting more mip levels * than needed for the specified * <tt>base{Width,Height,Depth}</tt>. * @exception KTX_OUT_OF_MEMORY Not enough memory for the texture's images. */ KTX_error_code ktxTexture1_Create(ktxTextureCreateInfo* createInfo, ktxTextureCreateStorageEnum storageAllocation, ktxTexture1** newTex) { … } /** * @memberof ktxTexture1 * @~English * @brief Create a ktxTexture1 from a stdio stream reading from a KTX source. * * The address of a newly created texture reflecting the contents of the * stdio stream is written to the location pointed at by @p newTex. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This * will minimize memory usage by allowing, for example, loading the images * directly from the source into a Vulkan staging buffer. * * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is * provided solely to enable implementation of the @e libktx v1 API on top of * ktxTexture1. * * @param[in] stdioStream stdio FILE pointer created from the desired file. * @param[in] createFlags bitmask requesting specific actions during creation. * @param[in,out] newTex pointer to a location in which store the address of * the newly created texture. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_INVALID_VALUE @p newTex is @c NULL. * @exception KTX_FILE_DATA_ERROR * Source data is inconsistent with the KTX * specification. * @exception KTX_FILE_READ_ERROR * An error occurred while reading the source. * @exception KTX_FILE_UNEXPECTED_EOF * Not enough data in the source. * @exception KTX_OUT_OF_MEMORY Not enough memory to create the texture object, * load the images or load the key-value data. * @exception KTX_UNKNOWN_FILE_FORMAT * The source is not in KTX format. * @exception KTX_UNSUPPORTED_TEXTURE_TYPE * The source describes a texture type not * supported by OpenGL or Vulkan, e.g, a 3D array. */ KTX_error_code ktxTexture1_CreateFromStdioStream(FILE* stdioStream, ktxTextureCreateFlags createFlags, ktxTexture1** newTex) { … } /** * @memberof ktxTexture1 * @~English * @brief Create a ktxTexture1 from a named KTX file. * * The address of a newly created texture reflecting the contents of the * file is written to the location pointed at by @p newTex. * * The file name must be encoded in utf-8. On Windows convert unicode names * to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This * will minimize memory usage by allowing, for example, loading the images * directly from the source into a Vulkan staging buffer. * * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is * provided solely to enable implementation of the @e libktx v1 API on top of * ktxTexture1. * * @param[in] filename pointer to a char array containing the file name. * @param[in] createFlags bitmask requesting specific actions during creation. * @param[in,out] newTex pointer to a location in which store the address of * the newly created texture. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_FILE_OPEN_FAILED The file could not be opened. * @exception KTX_INVALID_VALUE @p filename is @c NULL. * * For other exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code ktxTexture1_CreateFromNamedFile(const char* const filename, ktxTextureCreateFlags createFlags, ktxTexture1** newTex) { … } /** * @memberof ktxTexture1 * @~English * @brief Create a ktxTexture1 from KTX-formatted data in memory. * * The address of a newly created texture reflecting the contents of the * serialized KTX data is written to the location pointed at by @p newTex. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This * will minimize memory usage by allowing, for example, loading the images * directly from the source into a Vulkan staging buffer. * * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is * provided solely to enable implementation of the @e libktx v1 API on top of * ktxTexture1. * * @param[in] bytes pointer to the memory containing the serialized KTX data. * @param[in] size length of the KTX data in bytes. * @param[in] createFlags bitmask requesting specific actions during creation. * @param[in,out] newTex pointer to a location in which store the address of * the newly created texture. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0. * * For other exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size, ktxTextureCreateFlags createFlags, ktxTexture1** newTex) { … } /** * @memberof ktxTexture1 * @~English * @brief Create a ktxTexture1 from KTX-formatted data from a `ktxStream`. * * The address of a newly created texture reflecting the contents of the * serialized KTX data is written to the location pointed at by @p newTex. * * The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set, * if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This * will minimize memory usage by allowing, for example, loading the images * directly from the source into a Vulkan staging buffer. * * The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is * provided solely to enable implementation of the @e libktx v1 API on top of * ktxTexture1. * * @param[in] pStream pointer to the stream to read KTX data from. * @param[in] createFlags bitmask requesting specific actions during creation. * @param[in,out] newTex pointer to a location in which store the address of * the newly created texture. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * For exceptions, see ktxTexture1_CreateFromStdioStream(). */ KTX_error_code ktxTexture1_CreateFromStream(ktxStream* pStream, ktxTextureCreateFlags createFlags, ktxTexture1** newTex) { … } /** * @memberof ktxTexture1 * @~English * @brief Destroy a ktxTexture1 object. * * This frees the memory associated with the texture contents and the memory * of the ktxTexture1 object. This does @e not delete any OpenGL or Vulkan * texture objects created by ktxTexture1_GLUpload or ktxTexture1_VkUpload. * * @param[in] This pointer to the ktxTexture1 object to destroy */ void ktxTexture1_Destroy(ktxTexture1* This) { … } /** * @memberof ktxTexture @private * @~English * @brief Calculate the size of the image data for the specified number * of levels. * * The data size is the sum of the sizes of each level up to the number * specified and includes any @c mipPadding. * * @param[in] This pointer to the ktxTexture object of interest. * @param[in] levels number of levels whose data size to return. * * @return the data size in bytes. */ ktx_size_t ktxTexture1_calcDataSizeLevels(ktxTexture1* This, ktx_uint32_t levels) { … } /** * @memberof ktxTexture1 @private * @~English * * @copydoc ktxTexture::ktxTexture_doCalcFaceLodSize */ ktx_size_t ktxTexture1_calcFaceLodSize(ktxTexture1* This, ktx_uint32_t level) { … } /** * @memberof ktxTexture @private * @~English * @brief Return the offset of a level in bytes from the start of the image * data in a ktxTexture. * * The caclulated size does not include space for storing the @c imageSize * fields of each mip level. * * @param[in] This pointer to the ktxTexture object of interest. * @param[in] level level whose offset to return. * @param[in] fv enum specifying format version for which to calculate * image size. * * @return the data size in bytes. */ ktx_size_t ktxTexture1_calcLevelOffset(ktxTexture1* This, ktx_uint32_t level) { … } /** * @memberof ktxTexture1 * @~English * @brief Find the offset of an image within a ktxTexture's image data. * * As there is no such thing as a 3D cubemap we make the 3rd location parameter * do double duty. * * @param[in] This pointer to the ktxTexture object of interest. * @param[in] level mip level of the image. * @param[in] layer array layer of the image. * @param[in] faceSlice cube map face or depth slice of the image. * @param[in,out] pOffset pointer to location to store the offset. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_INVALID_OPERATION * @p level, @p layer or @p faceSlice exceed the * dimensions of the texture. * @exception KTX_INVALID_VALID @p This is NULL. */ KTX_error_code ktxTexture1_GetImageOffset(ktxTexture1* This, ktx_uint32_t level, ktx_uint32_t layer, ktx_uint32_t faceSlice, ktx_size_t* pOffset) { … } /** * @memberof ktxTexture1 * @~English * @brief Return the total size in bytes of the uncompressed data of a ktxTexture1. * * This always returns the value of @c This->dataSize. The function is provided for * symmetry with ktxTexture2. * * @param[in] This pointer to the ktxTexture1 object of interest. * @return The size of the data in the texture. */ ktx_size_t ktxTexture1_GetDataSizeUncompressed(ktxTexture1* This) { … } /** * @memberof ktxTexture1 * @~English * @brief Calculate & return the size in bytes of an image at the specified * mip level. * * For arrays, this is the size of layer, for cubemaps, the size of a face * and for 3D textures, the size of a depth slice. * * The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT. * * @param[in] This pointer to the ktxTexture1 object of interest. * @param[in] level level of interest. */ ktx_size_t ktxTexture1_GetImageSize(ktxTexture1* This, ktx_uint32_t level) { … } /** * @memberof ktxTexture1 @private * @~English * @brief Return the size of the primitive type of a single color component * * @param[in] This pointer to the ktxTexture1 object of interest. * * @return the type size in bytes. */ ktx_uint32_t ktxTexture1_glTypeSize(ktxTexture1* This) { … } /** * @memberof ktxTexture1 * @~English * @brief Iterate over the mip levels in a ktxTexture1 object. * * This is almost identical to @ref ktxTexture::ktxTexture_IterateLevelFaces * "ktxTexture_IterateLevelFaces". The difference is that the blocks of image * data for non-array cube maps include all faces of a mip level. * * This function works even if @p This->pData == 0 so it can be used to * obtain offsets and sizes for each level by callers who have loaded the data * externally. * * @param[in] This handle of the 1 opened on the data. * @param[in,out] iterCb the address of a callback function which is called * with the data for each image block. * @param[in,out] userdata the address of application-specific data which is * passed to the callback along with the image data. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. The * following are returned directly by this function. @p iterCb may * return these for other causes or may return additional errors. * * @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not * decreasing * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL. * */ KTX_error_code ktxTexture1_IterateLevels(ktxTexture1* This, PFNKTXITERCB iterCb, void* userdata) { … } /** * @memberof ktxTexture1 * @~English * @brief Iterate over the images in a ktxTexture1 object while loading the * image data. * * This operates similarly to @ref ktxTexture::ktxTexture_IterateLevelFaces * "ktxTexture_IterateLevelFaces" except that it loads the images from the * ktxTexture1's source to a temporary buffer while iterating. The callback * function must copy the image data if it wishes to preserve it as the * temporary buffer is reused for each level and is freed when this function * exits. * * This function is helpful for reducing memory usage when uploading the data * to a graphics API. * * @param[in] This pointer to the ktxTexture1 object of interest. * @param[in,out] iterCb the address of a callback function which is called * with the data for each image. * @param[in,out] userdata the address of application-specific data which is * passed to the callback along with the image data. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. The * following are returned directly by this function. @p iterCb may * return these for other causes or may return additional errors. * * @exception KTX_FILE_DATA_ERROR mip level sizes are increasing not * decreasing * @exception KTX_INVALID_OPERATION the ktxTexture1 was not created from a * stream, i.e there is no data to load, or * this ktxTexture1's images have already * been loaded. * @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL. * @exception KTX_OUT_OF_MEMORY not enough memory to allocate a block to * hold the base level image. */ KTX_error_code ktxTexture1_IterateLoadLevelFaces(ktxTexture1* This, PFNKTXITERCB iterCb, void* userdata) { … } /** * @memberof ktxTexture1 * @~English * @brief Load all the image data from the ktxTexture1's source. * * The data is loaded into the provided buffer or to an internally allocated * buffer, if @p pBuffer is @c NULL. * * @param[in] This pointer to the ktxTexture object of interest. * @param[in] pBuffer pointer to the buffer in which to load the image data. * @param[in] bufSize size of the buffer pointed at by @p pBuffer. * * @return KTX_SUCCESS on success, other KTX_* enum values on error. * * @exception KTX_INVALID_VALUE @p This is NULL. * @exception KTX_INVALID_VALUE @p bufSize is less than the the image data size. * @exception KTX_INVALID_OPERATION * The data has already been loaded or the * ktxTexture was not created from a KTX source. * @exception KTX_OUT_OF_MEMORY Insufficient memory for the image data. */ KTX_error_code ktxTexture1_LoadImageData(ktxTexture1* This, ktx_uint8_t* pBuffer, ktx_size_t bufSize) { … } ktx_bool_t ktxTexture1_NeedsTranscoding(ktxTexture1* This) { … } #if !KTX_FEATURE_WRITE /* * Stubs for writer functions that return a proper error code */ KTX_error_code ktxTexture1_SetImageFromMemory(ktxTexture1* This, ktx_uint32_t level, ktx_uint32_t layer, ktx_uint32_t faceSlice, const ktx_uint8_t* src, ktx_size_t srcSize) { … } KTX_error_code ktxTexture1_SetImageFromStdioStream(ktxTexture1* This, ktx_uint32_t level, ktx_uint32_t layer, ktx_uint32_t faceSlice, FILE* src, ktx_size_t srcSize) { … } KTX_error_code ktxTexture1_WriteToStdioStream(ktxTexture1* This, FILE* dstsstr) { … } KTX_error_code ktxTexture1_WriteToNamedFile(ktxTexture1* This, const char* const dstname) { … } KTX_error_code ktxTexture1_WriteToMemory(ktxTexture1* This, ktx_uint8_t** ppDstBytes, ktx_size_t* pSize) { … } KTX_error_code ktxTexture1_WriteToStream(ktxTexture1* This, ktxStream* dststr) { … } #endif /* * Initialized here at the end to avoid the need for multiple declarations of * these functions. */ struct ktxTexture_vtblInt ktxTexture1_vtblInt = …; struct ktxTexture_vtbl ktxTexture1_vtbl = …; /** @} */