ktx (empty) → 0.1
raw patch · 25 files changed
+7202/−0 lines, 25 filesdep +OpenGLdep +basesetup-changed
Dependencies added: OpenGL, base
Files
- KTX/LICENSING.md +7/−0
- KTX/include/ktx.h +486/−0
- KTX/lib/checkheader.c +209/−0
- KTX/lib/errstr.c +79/−0
- KTX/lib/etcdec.cxx +1842/−0
- KTX/lib/etcunpack.cxx +296/−0
- KTX/lib/gl_funcptrs.h +59/−0
- KTX/lib/gles1_funcptrs.h +79/−0
- KTX/lib/gles2_funcptrs.h +76/−0
- KTX/lib/gles3_funcptrs.h +70/−0
- KTX/lib/hashtable.c +324/−0
- KTX/lib/ktxfilestream.c +154/−0
- KTX/lib/ktxfilestream.h +51/−0
- KTX/lib/ktxint.h +327/−0
- KTX/lib/ktxmemstream.c +225/−0
- KTX/lib/ktxmemstream.h +64/−0
- KTX/lib/ktxstream.h +84/−0
- KTX/lib/loader.c +855/−0
- KTX/lib/swap.c +65/−0
- KTX/lib/uthash.h +960/−0
- KTX/lib/writer.c +735/−0
- LICENSE +21/−0
- Setup.hs +2/−0
- ktx.cabal +68/−0
- src/Graphics/Rendering/KTX.hsc +64/−0
+ KTX/LICENSING.md view
@@ -0,0 +1,7 @@+Licensing+---+The library and tools are open source software. Most of the code is licensed+under a modified BSD license. The code for unpacking ETC1, ETC2 and EAC+compressed textures has a separate license that restricts it to uses+associated with Khronos Group APIs. See [Licensing](http://www.khronos.org/opengles/sdk/tools/KTX/doc/libktx/licensing.html)+for more details.
+ KTX/include/ktx.h view
@@ -0,0 +1,486 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++#ifndef _KTX_H_+#define _KTX_H_++/**+ * @file+ * @~English+ *+ * @brief Declares the public functions and structures of the+ * KTX API.+ *+ * @author Georg Kolling, Imagination Technology+ * @author with modifications by Mark Callow, HI Corporation+ *+ * $Id: 026beff16eeb0b507d918c88ca9fcfcdecc9167d $+ * $Date$+ *+ * @todo Find a way so that applications do not have to define KTX_OPENGL{,_ES*}+ * when using the library.+ */++/*+ * This file copyright (c) 2010 The Khronos Group, Inc.+ */++/**+@~English+@page licensing Licensing++LibKTX contains code++@li (c) 2010 & (c) 2013 The Khronos Group Inc.+@li (c) 2008 and (c) 2010 HI Corporation+@li (c) 2005 Ericsson AB+@li (c) 2003-2010, Troy D. Hanson++A specific copyright is given in each source file.++@section default Default License++With the exception of the files listed explicitly below, the source+files are made available under the following BSD-like license.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.++@section hi_mark hi_mark{,_sq}.ktx++The HI logo textures are © & ™ HI Corporation and are+provided for use only in testing the KTX loader. Any other use requires+specific prior written permission from HI. Furthermore the name HI may+not be used to endorse or promote products derived from this software+without specific prior written permission.++@section uthash uthash.h++uthash.h is made available under the following revised BSD license.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+*/++/**+ * @~English+ * @mainpage The KTX Library+ *+ * @section intro_sec Introduction+ *+ * libktx is a small library of functions for creating KTX (Khronos+ * TeXture) files and instantiating OpenGL® and OpenGL® ES+ * textures from them.+ *+ * For information about the KTX format see the+ * <a href="http://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/">+ * formal specification.</a>+ *+ * The library is open source software. Most of the code is licensed under a+ * modified BSD license. The code for unpacking ETC1, ETC2 and EAC compressed+ * textures has a separate license that restricts it to uses associated with+ * Khronos Group APIs. See @ref licensing for more details.+ *+ * See @ref history for the list of changes.+ *+ * @author Mark Callow, <a href="http://www.hicorp.co.jp">HI Corporation</a>+ * @author Georg Kolling, <a href="http://www.imgtec.com">Imagination Technology</a>+ * @author Jacob Ström, <a href="http://www.ericsson.com">Ericsson AB</a>+ *+ * @version 2.0+ *+ * $Date$+ */++#include <stdio.h>++#include "KHR/khrplatform.h"++#if KTX_OPENGL++ #ifdef _WIN32+ #include <windows.h>+ #include <GL/glew.h>+ #elif KTX_USE_GETPROC+ #include <GL/glew.h>+ #else+ #define GLCOREARB_PROTOTYPES+ #include <GL/glcorearb.h>+ #endif++ #define GL_APIENTRY APIENTRY+ #define KTX_GLFUNCPTRS "gl_funcptrs.h"++#elif KTX_OPENGL_ES1++ #include <GLES/gl.h>+ #include <GLES/glext.h>++ #define KTX_GLFUNCPTRS "gles1_funcptrs.h"++#elif KTX_OPENGL_ES2++ #include <GLES2/gl2.h>+ #include <GLES2/gl2ext.h>++ #define KTX_GLFUNCPTRS "gles2_funcptrs.h"++#elif KTX_OPENGL_ES3++ #include <GLES3/gl3.h>+ #include <GLES3/gl3ext.h>++ #define KTX_GLFUNCPTRS "gles3_funcptrs.h"++#else+#error Please #define one of KTX_OPENGL, KTX_OPENGL_ES1, KTX_OPENGL_ES2 or KTX_OPENGL_ES3 as 1+#endif+++#ifdef __cplusplus+extern "C" {+#endif++/**+ * @brief Key String for standard orientation value.+ */+#define KTX_ORIENTATION_KEY "KTXorientation"+/**+ * @brief Standard format for 2D orientation value.+ */+#define KTX_ORIENTATION2_FMT "S=%c,T=%c"+/**+ * @brief Standard format for 3D orientation value.+ */+#define KTX_ORIENTATION3_FMT "S=%c,T=%c,R=%c"+/**+ * @brief Required unpack alignment+ */+#define KTX_GL_UNPACK_ALIGNMENT 4++/**+ * @brief Error codes returned by library functions.+ */+typedef enum KTX_error_code_t {+ KTX_SUCCESS = 0, /*!< Operation was successful. */+ KTX_FILE_OPEN_FAILED, /*!< The target file could not be opened. */+ KTX_FILE_WRITE_ERROR, /*!< An error occurred while writing to the file. */+ KTX_GL_ERROR, /*!< GL operations resulted in an error. */+ KTX_INVALID_OPERATION, /*!< The operation is not allowed in the current state. */+ KTX_INVALID_VALUE, /*!< A parameter value was not valid */+ KTX_NOT_FOUND, /*!< Requested key was not found */+ KTX_OUT_OF_MEMORY, /*!< Not enough memory to complete the operation. */+ KTX_UNEXPECTED_END_OF_FILE, /*!< The file did not contain enough data */+ KTX_UNKNOWN_FILE_FORMAT, /*!< The file not a KTX file */+ KTX_UNSUPPORTED_TEXTURE_TYPE, /*!< The KTX file specifies an unsupported texture type. */+} KTX_error_code;++/**+ * @brief structure used to pass information about the texture to ktxWriteKTX+ */+typedef struct KTX_texture_info_t+{+ /**+ * @brief The type of the image data.+ *+ * Values are the same as in the @p type parameter of+ * glTexImage*D. Must be 0 for compressed images.+ */+ khronos_uint32_t glType;+ /**+ * @brief The data type size to be used in case of endianness+ * conversion.+ *+ * This value is used in the event conversion is required when the+ * KTX file is loaded. It should be the size in bytes corresponding+ * to glType. Must be 1 for compressed images.+ */+ khronos_uint32_t glTypeSize;+ /**+ * @brief The format of the image(s).+ *+ * Values are the same as in the format parameter+ * of glTexImage*D. Must be 0 for compressed images.+ */+ khronos_uint32_t glFormat;+ /** @brief The internalformat of the image(s).+ *+ * Values are the same as for the internalformat parameter of+ * glTexImage*2D. Note: it will not be used when a KTX file+ * containing an uncompressed texture is loaded into OpenGL ES.+ */+ khronos_uint32_t glInternalFormat;+ /** @brief The base internalformat of the image(s)+ *+ * For non-compressed textures, should be the same as glFormat.+ * For compressed textures specifies the base internal, e.g.+ * GL_RGB, GL_RGBA.+ */+ khronos_uint32_t glBaseInternalFormat;+ /** @brief Width of the image for texture level 0, in pixels. */+ khronos_uint32_t pixelWidth;+ /** @brief Height of the texture image for level 0, in pixels.+ *+ * Must be 0 for 1D textures.+ */+ khronos_uint32_t pixelHeight;+ /** @brief Depth of the texture image for level 0, in pixels.+ *+ * Must be 0 for 1D, 2D and cube textures.+ */+ khronos_uint32_t pixelDepth;+ /** @brief The number of array elements.+ *+ * Must be 0 if not an array texture.+ */+ khronos_uint32_t numberOfArrayElements;+ /** @brief The number of cubemap faces.+ *+ * Must be 6 for cubemaps and cubemap arrays, 1 otherwise. Cubemap+ * faces must be provided in the order: +X, -X, +Y, -Y, +Z, -Z.+ */+ khronos_uint32_t numberOfFaces;+ /** @brief The number of mipmap levels.+ *+ * 1 for non-mipmapped texture. 0 indicates that a full mipmap pyramid should+ * be generated from level 0 at load time (this is usually not allowed for+ * compressed formats). Mipmaps must be provided in order from largest size to+ * smallest size. The first mipmap level is always level 0.+ */+ khronos_uint32_t numberOfMipmapLevels;+} KTX_texture_info;+++/**+ * @brief Structure used to pass image data to ktxWriteKTX.+ */+typedef struct KTX_image_info {+ GLsizei size; /*!< Size of the image data in bytes. */+ GLubyte* data; /*!< Pointer to the image data. */+} KTX_image_info;+++/**+ * @brief Structure used to return texture dimensions+ */+typedef struct KTX_dimensions {+ GLsizei width; /*!< */+ GLsizei height; /*!< */+ GLsizei depth; /*!< */+} KTX_dimensions;++/**+ * @brief Opaque handle to a KTX_hash_table.+ */+typedef void* KTX_hash_table;++/* ktxLoadTextureF+ *+ * Loads a texture from a stdio FILE.+ */+KTX_error_code+ktxLoadTextureF(FILE*, GLuint* pTexture, GLenum* pTarget,+ KTX_dimensions* pDimensions, GLboolean* pIsMipmapped,+ GLenum* pGlerror,+ unsigned int* pKvdLen, unsigned char** ppKvd);++/* ktxLoadTextureN+ *+ * Loads a texture from a KTX file on disk.+ */+KTX_error_code+ktxLoadTextureN(const char* const filename, GLuint* pTexture, GLenum* pTarget,+ KTX_dimensions* pDimensions, GLboolean* pIsMipmapped,+ GLenum* pGlerror,+ unsigned int* pKvdLen, unsigned char** ppKvd);++/* ktxLoadTextureM+ *+ * Loads a texture from a KTX file in memory.+ */+KTX_error_code+ktxLoadTextureM(const void* bytes, GLsizei size, GLuint* pTexture, GLenum* pTarget,+ KTX_dimensions* pDimensions, GLboolean* pIsMipmapped,+ GLenum* pGlerror,+ unsigned int* pKvdLen, unsigned char** ppKvd);++/* ktxWriteKTXF+ *+ * Writes a KTX file using supplied data.+ */+KTX_error_code+ktxWriteKTXF(FILE*, const KTX_texture_info* imageInfo,+ GLsizei bytesOfKeyValueData, const void* keyValueData,+ GLuint numImages, KTX_image_info images[]);++/* ktxWriteKTXN+ *+ * Writes a KTX file using supplied data.+ */+KTX_error_code+ktxWriteKTXN(const char* dstname, const KTX_texture_info* imageInfo,+ GLsizei bytesOfKeyValueData, const void* keyValueData,+ GLuint numImages, KTX_image_info images[]);++/* ktxWriteKTXM+ *+ * Writes a KTX file into memory using supplied data.+ */+KTX_error_code+ktxWriteKTXM(unsigned char** bytes, GLsizei* size, const KTX_texture_info* textureInfo,+ GLsizei bytesOfKeyValueData, const void* keyValueData,+ GLuint numImages, KTX_image_info images[]);++/* ktxErrorString()+ *+ * Returns a string corresponding to a KTX error code.+ */+const char* const ktxErrorString(KTX_error_code error);++/* ktxHashTable_Create()+ *+ * Creates a key-value hash table+ */+KTX_hash_table ktxHashTable_Create();++/* ktxHashTable_Destroy()+ *+ * Destroys a key-value hash table+ */+void ktxHashTable_Destroy(KTX_hash_table This);++/* ktxHashTable_AddKVPair()+ *+ * Adds a key-value pair to a hash table.+ */+KTX_error_code+ktxHashTable_AddKVPair(KTX_hash_table This, const char* key,+ unsigned int valueLen, const void* value);+++/* ktxHashTable_FindValue()+ *+ * Looks up a key and returns the value.+ */+KTX_error_code+ktxHashTable_FindValue(KTX_hash_table This, const char* key,+ unsigned int* pValueLen, void** pValue);+++/* ktxHashTable_Serialize()+ *+ * Serializes the hash table to a block of memory suitable for+ * writing to a KTX file.+ */+KTX_error_code+ktxHashTable_Serialize(KTX_hash_table This, unsigned int* kvdLen, unsigned char** kvd);+++/* ktxHashTable_Deserialize()+ *+ * Creates a hash table from the serialized data read from a+ * a KTX file.+ */+KTX_error_code+ktxHashTable_Deserialize(unsigned int kvdLen, void* kvd, KTX_hash_table* pKvt);+++#ifdef __cplusplus+}+#endif++/**+@page history Revision History++@section v4 Version XXX+Added:+@li CMake build files. Thanks to Pavel Rotjberg for the initial version.++Changed:+@li ktxWriteKTXF to check the validity of the type & format combinations+ passed to it.++Fixed:+@li Public Bugzilla <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=999">999</a>: 16-bit luminance texture cannot be written.+@li compile warnings from compilers stricter than MS Visual C++. Thanks to+ Pavel Rotjberg.++@section v3 Version 2.0+Added:+@li support for decoding ETC2 and EAC formats in the absence of a hardware+ decoder.+@li support for converting textures with legacy LUMINANCE, LUMINANCE_ALPHA,+ etc. formats to the equivalent R, RG, etc. format with an+ appropriate swizzle, when loading in OpenGL Core Profile contexts.+@li ktxErrorString function to return a string corresponding to an error code.+@li tests for ktxLoadTexture[FN] that run under OpenGL ES 3.0 and OpenGL 3.3.+ The latter includes an EGL on WGL wrapper that makes porting apps between+ OpenGL ES and OpenGL easier on Windows.+@li more texture formats to ktxLoadTexture[FN] and toktx tests.++Changed:+@li ktxLoadTexture[FMN] to discover the capabilities of the GL context at+ run time and load textures, or not, according to those capabilities.++Fixed:+@li failure of ktxWriteKTXF to pad image rows to 4 bytes as required by the KTX+ format.+@li ktxWriteKTXF exiting with KTX_FILE_WRITE_ERROR when attempting to write+ more than 1 byte of face-LOD padding.++Although there is only a very minor API change, the addition of ktxErrorString, the functional changes+are large enough to justify bumping the major revision number.++@section v2 Version 1.0.1+Implemented ktxLoadTextureM.+Fixed the following:+@li Public Bugzilla <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=571">571</a>: crash when null passed for pIsMipmapped.+@li Public Bugzilla <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=572">572</a>: memory leak when unpacking ETC textures.+@li Public Bugzilla <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=573">573</a>: potential crash when unpacking ETC textures with unused padding pixels.+@li Public Bugzilla <a href="http://www.khronos.org/bugzilla/show_bug.cgi?id=576">576</a>: various small fixes.++Thanks to Krystian Bigaj for the ktxLoadTextureM implementation and these fixes.++@section v1 Version 1.0+Initial release.++*/++#endif /* _KTX_H_ */
+ KTX/lib/checkheader.c view
@@ -0,0 +1,209 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 5c28a496fa7703a75b91eb8dd7b1722c2e299741 $ */++/**+ * @internal+ * @file checkheader.c+ * @~English+ *+ * @brief Function to verify a KTX file header+ *+ * @author Mark Callow, HI Corporation+ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/*+ * Author: Georg Kolling, Imagination Technology with modifications+ * by Mark Callow, HI Corporation.+ */+#include <string.h>++#include "ktx.h"+#include "ktxint.h"++#include KTX_GLFUNCPTRS++DECLARE_GL_FUNCPTRS+DECLARE_GL_EXTGLOBALS++/**+ * @internal+ * @~English+ * @brief Check a KTX file header.+ *+ * As well as checking that the header identifies a KTX file, the function+ * sanity checks the values and returns information about the texture in a+ * KTX_texinfo structure.+ *+ * @param header pointer to the KTX header to check+ * @param texinfo pointer to a KTX_texinfo structure in which to return+ * information about the texture.+ * + * @author Georg Kolling, Imagination Technology+ * @author Mark Callow, HI Corporation+ */+KTX_error_code _ktxCheckHeader(KTX_header* header, KTX_texinfo* texinfo)+{+ khronos_uint8_t identifier_reference[12] = KTX_IDENTIFIER_REF;+ khronos_uint32_t max_dim;++ /* Compare identifier, is this a KTX file? */+ if (memcmp(header->identifier, identifier_reference, 12) != 0)+ {+ return KTX_UNKNOWN_FILE_FORMAT;+ }++ if (header->endianness == KTX_ENDIAN_REF_REV)+ {+ /* Convert endianness of header fields if necessary */+ _ktxSwapEndian32(&header->glType, 12);++ if (header->glTypeSize != 1 ||+ header->glTypeSize != 2 ||+ header->glTypeSize != 4)+ {+ /* Only 8, 16, and 32-bit types supported so far */+ return KTX_INVALID_VALUE;+ }+ }+ else if (header->endianness != KTX_ENDIAN_REF)+ {+ return KTX_INVALID_VALUE;+ }++ /* Check glType and glFormat */+ texinfo->compressed = 0;+ if (header->glType == 0 || header->glFormat == 0)+ {+ if (header->glType + header->glFormat != 0)+ {+ /* either both or none of glType, glFormat must be zero */+ return KTX_INVALID_VALUE;+ }+ texinfo->compressed = 1;+ }++ /* Check texture dimensions. KTX files can store 8 types of textures:+ 1D, 2D, 3D, cube, and array variants of these. There is currently+ no GL extension that would accept 3D array or cube array textures. */+ if ((header->pixelWidth == 0) ||+ (header->pixelDepth > 0 && header->pixelHeight == 0))+ {+ /* texture must have width */+ /* texture must have height if it has depth */+ return KTX_INVALID_VALUE; + }++ texinfo->textureDimensions = 1;+ texinfo->glTarget = GL_TEXTURE_1D;+ texinfo->generateMipmaps = 0;+ if (header->pixelHeight > 0)+ {+ texinfo->textureDimensions = 2;+ texinfo->glTarget = GL_TEXTURE_2D;+ }+ if (header->pixelDepth > 0)+ {+ texinfo->textureDimensions = 3;+ texinfo->glTarget = GL_TEXTURE_3D;+ }++ if (header->numberOfFaces == 6)+ {+ if (texinfo->textureDimensions == 2)+ {+ texinfo->glTarget = GL_TEXTURE_CUBE_MAP;+ }+ else+ {+ /* cube map needs 2D faces */+ return KTX_INVALID_VALUE;+ }+ }+ else if (header->numberOfFaces != 1)+ {+ /* numberOfFaces must be either 1 or 6 */+ return KTX_INVALID_VALUE;+ }++ /* load as 2D texture if 1D textures are not supported */+ if (texinfo->textureDimensions == 1 &&+ ((texinfo->compressed && (glCompressedTexImage1D == NULL)) ||+ (!texinfo->compressed && (glTexImage1D == NULL))))+ {+ texinfo->textureDimensions = 2;+ texinfo->glTarget = GL_TEXTURE_2D;+ header->pixelHeight = 1;+ }++ if (header->numberOfArrayElements > 0)+ {+ if (texinfo->glTarget == GL_TEXTURE_1D)+ {+ texinfo->glTarget = GL_TEXTURE_1D_ARRAY_EXT;+ }+ else if (texinfo->glTarget == GL_TEXTURE_2D)+ {+ texinfo->glTarget = GL_TEXTURE_2D_ARRAY_EXT;+ }+ else+ {+ /* No API for 3D and cube arrays yet */+ return KTX_UNSUPPORTED_TEXTURE_TYPE;+ }+ texinfo->textureDimensions++;+ }++ /* reject 3D texture if unsupported */+ if (texinfo->textureDimensions == 3 &&+ ((texinfo->compressed && (glCompressedTexImage3D == NULL)) ||+ (!texinfo->compressed && (glTexImage3D == NULL))))+ {+ return KTX_UNSUPPORTED_TEXTURE_TYPE;+ }++ /* Check number of mipmap levels */+ if (header->numberOfMipmapLevels == 0)+ {+ texinfo->generateMipmaps = 1;+ header->numberOfMipmapLevels = 1;+ }+ max_dim = MAX(MAX(header->pixelWidth, header->pixelHeight), header->pixelDepth);+ if (max_dim < ((khronos_uint32_t)1 << (header->numberOfMipmapLevels - 1)))+ {+ /* Can't have more mip levels than 1 + log2(max(width, height, depth)) */+ return KTX_INVALID_VALUE;+ }++ return KTX_SUCCESS;+}
+ KTX/lib/errstr.c view
@@ -0,0 +1,79 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 66fc783ff8cf9a7836f10cccf03607bad0860246 $ */++/**+ * @file errstr.c+ * @~English+ *+ * @brief Function to return a string corresponding to a KTX error code.+ *+ * @author Mark Callow, HI Corporation+ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++#include "ktx.h"++static const char* const errorStrings[] = {+ "Operation succeeded", /* KTX_SUCCESS */+ "File open failed", /* KTX_FILE_OPEN_FAILED */+ "File write failed", /* KTX_FILE_WRITE_ERROR */+ "GL error occurred", /* KTX_GL_ERROR */+ "Operation not allowed in the current state", /* KTX_INVALID_OPERATION */+ "Invalid parameter value", /* KTX_INVALID_VALUE */+ "Key not found", /* KTX_NOT_FOUND */+ "Out of memory", /* KTX_OUT_OF_MEMORY */+ "Unexpected end of file", /* KTX_UNEXPECTED_END_OF_FILE */+ "Not a KTX file", /* KTX_UNKNOWN_FILE_FORMAT */+ "Texture type not supported by GL context" /* KTX_UNSUPPORTED_TEXTURE_TYPE */+};+static const int lastErrorCode = (sizeof(errorStrings) / sizeof(char*)) - 1;+++/**+ * @~English+ * @brief Return a string corresponding to a KTX error code.+ *+ * @param error the error code for which to return a string+ *+ * @return pointer to the message string.+ *+ * @internal Use UTF-8 for translated message strings.+ * + * @author Mark Callow, HI Corporation+ */+const char* const ktxErrorString(KTX_error_code error)+{+ if (error > lastErrorCode)+ return "Unrecognized error code";+ return errorStrings[error];+}
+ KTX/lib/etcdec.cxx view
@@ -0,0 +1,1842 @@+/**+ +@~English+@page licensing Licensing+ +@section etcdec etcdec.cxx License+ +etcdec.cxx is made available under the terms and conditions of the following+License Agreement.++Software License Agreement++PLEASE REVIEW THE FOLLOWING TERMS AND CONDITIONS PRIOR TO USING THE+ERICSSON TEXTURE COMPRESSION CODEC SOFTWARE (THE "SOFTWARE"). THE USE+OF THE SOFTWARE IS SUBJECT TO THE TERMS AND CONDITIONS OF THE+FOLLOWING SOFTWARE LICENSE AGREEMENT (THE "SLA"). IF YOU DO NOT ACCEPT+SUCH TERMS AND CONDITIONS YOU MAY NOT USE THE SOFTWARE.++Subject to the terms and conditions of the SLA, the licensee of the+Software (the "Licensee") hereby, receives a non-exclusive,+non-transferable, limited, free-of-charge, perpetual and worldwide+license, to copy, use, distribute and modify the Software, but only+for the purpose of developing, manufacturing, selling, using and+distributing products including the Software in binary form, which+products are used for compression and/or decompression according to+the Khronos standard specifications OpenGL, OpenGL ES and+WebGL. Notwithstanding anything of the above, Licensee may distribute+[etcdec.cxx] in source code form provided (i) it is in unmodified+form; and (ii) it is included in software owned by Licensee.++If Licensee institutes, or threatens to institute, patent litigation+against Ericsson or Ericsson's affiliates for using the Software for+developing, having developed, manufacturing, having manufactured,+selling, offer for sale, importing, using, leasing, operating,+repairing and/or distributing products (i) within the scope of the+Khronos framework; or (ii) using software or other intellectual+property rights owned by Ericsson or its affiliates and provided under+the Khronos framework, Ericsson shall have the right to terminate this+SLA with immediate effect. Moreover, if Licensee institutes, or+threatens to institute, patent litigation against any other licensee+of the Software for using the Software in products within the scope of+the Khronos framework, Ericsson shall have the right to terminate this+SLA with immediate effect. However, should Licensee institute, or+threaten to institute, patent litigation against any other licensee of+the Software based on such other licensee's use of any other software+together with the Software, then Ericsson shall have no right to+terminate this SLA.++This SLA does not transfer to Licensee any ownership to any Ericsson+or third party intellectual property rights. All rights not expressly+granted by Ericsson under this SLA are hereby expressly+reserved. Furthermore, nothing in this SLA shall be construed as a+right to use or sell products in a manner which conveys or purports to+convey whether explicitly, by principles of implied license, or+otherwise, any rights to any third party, under any patent of Ericsson+or of Ericsson's affiliates covering or relating to any combination of+the Software with any other software or product (not licensed+hereunder) where the right applies specifically to the combination and+not to the software or product itself.++THE SOFTWARE IS PROVIDED "AS IS". ERICSSON MAKES NO REPRESENTATIONS OF+ANY KIND, EXTENDS NO WARRANTIES OR CONDITIONS OF ANY KIND, EITHER+EXPRESS, IMPLIED OR STATUTORY; INCLUDING, BUT NOT LIMITED TO, EXPRESS,+IMPLIED OR STATUTORY WARRANTIES OR CONDITIONS OF TITLE,+MERCHANTABILITY, SATISFACTORY QUALITY, SUITABILITY, AND FITNESS FOR A+PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE+OF THE SOFTWARE IS WITH THE LICENSEE. SHOULD THE SOFTWARE PROVE+DEFECTIVE, THE LICENSEE ASSUMES THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION. ERICSSON MAKES NO WARRANTY THAT THE MANUFACTURE,+SALE, OFFERING FOR SALE, DISTRIBUTION, LEASE, USE OR IMPORTATION UNDER+THE SLA WILL BE FREE FROM INFRINGEMENT OF PATENTS, COPYRIGHTS OR OTHER+INTELLECTUAL PROPERTY RIGHTS OF OTHERS, AND THE VALIDITY OF THE+LICENSE AND THE SLA ARE SUBJECT TO LICENSEE'S SOLE RESPONSIBILITY TO+MAKE SUCH DETERMINATION AND ACQUIRE SUCH LICENSES AS MAY BE NECESSARY+WITH RESPECT TO PATENTS, COPYRIGHT AND OTHER INTELLECTUAL PROPERTY OF+THIRD PARTIES.++THE LICENSEE ACKNOWLEDGES AND ACCEPTS THAT THE SOFTWARE (I) IS NOT+LICENSED FOR; (II) IS NOT DESIGNED FOR OR INTENDED FOR; AND (III) MAY+NOT BE USED FOR; ANY MISSION CRITICAL APPLICATIONS SUCH AS, BUT NOT+LIMITED TO OPERATION OF NUCLEAR OR HEALTHCARE COMPUTER SYSTEMS AND/OR+NETWORKS, AIRCRAFT OR TRAIN CONTROL AND/OR COMMUNICATION SYSTEMS OR+ANY OTHER COMPUTER SYSTEMS AND/OR NETWORKS OR CONTROL AND/OR+COMMUNICATION SYSTEMS ALL IN WHICH CASE THE FAILURE OF THE SOFTWARE+COULD LEAD TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL, MATERIAL OR+ENVIRONMENTAL DAMAGE. LICENSEE'S RIGHTS UNDER THIS LICENSE WILL+TERMINATE AUTOMATICALLY AND IMMEDIATELY WITHOUT NOTICE IF LICENSEE+FAILS TO COMPLY WITH THIS PARAGRAPH.++IN NO EVENT SHALL ERICSSON BE LIABLE FOR ANY DAMAGES WHATSOEVER,+INCLUDING BUT NOT LIMITED TO PERSONAL INJURY, ANY GENERAL, SPECIAL,+INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF OR IN+CONNECTION WITH THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING+BUT NOT LIMITED TO LOSS OF PROFITS, BUSINESS INTERUPTIONS, OR ANY+OTHER COMMERCIAL DAMAGES OR LOSSES, LOSS OF DATA OR DATA BEING+RENDERED INACCURATE OR LOSSES SUSTAINED BY THE LICENSEE OR THIRD+PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER+SOFTWARE) REGARDLESS OF THE THEORY OF LIABILITY (CONTRACT, TORT, OR+OTHERWISE), EVEN IF THE LICENSEE OR ANY OTHER PARTY HAS BEEN ADVISED+OF THE POSSIBILITY OF SUCH DAMAGES.++Licensee acknowledges that "ERICSSON ///" is the corporate trademark+of Telefonaktiebolaget LM Ericsson and that both "Ericsson" and the+figure "///" are important features of the trade names of+Telefonaktiebolaget LM Ericsson. Nothing contained in these terms and+conditions shall be deemed to grant Licensee any right, title or+interest in the word "Ericsson" or the figure "///". No delay or+omission by Ericsson to exercise any right or power shall impair any+such right or power to be construed to be a waiver thereof. Consent by+Ericsson to, or waiver of, a breach by the Licensee shall not+constitute consent to, waiver of, or excuse for any other different or+subsequent breach.++This SLA shall be governed by the substantive law of Sweden. Any+dispute, controversy or claim arising out of or in connection with+this SLA, or the breach, termination or invalidity thereof, shall be+submitted to the exclusive jurisdiction of the Swedish Courts.++*/++//// etcpack v2.74+//// +//// NO WARRANTY +//// +//// BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE THE PROGRAM IS PROVIDED+//// "AS IS". ERICSSON MAKES NO REPRESENTATIONS OF ANY KIND, EXTENDS NO+//// WARRANTIES OR CONDITIONS OF ANY KIND; EITHER EXPRESS, IMPLIED OR+//// STATUTORY; INCLUDING, BUT NOT LIMITED TO, EXPRESS, IMPLIED OR+//// STATUTORY WARRANTIES OR CONDITIONS OF TITLE, MERCHANTABILITY,+//// SATISFACTORY QUALITY, SUITABILITY AND FITNESS FOR A PARTICULAR+//// PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE+//// PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME+//// THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. ERICSSON+//// MAKES NO WARRANTY THAT THE MANUFACTURE, SALE, OFFERING FOR SALE,+//// DISTRIBUTION, LEASE, USE OR IMPORTATION UNDER THE LICENSE WILL BE FREE+//// FROM INFRINGEMENT OF PATENTS, COPYRIGHTS OR OTHER INTELLECTUAL+//// PROPERTY RIGHTS OF OTHERS, AND THE VALIDITY OF THE LICENSE IS SUBJECT+//// TO YOUR SOLE RESPONSIBILITY TO MAKE SUCH DETERMINATION AND ACQUIRE+//// SUCH LICENSES AS MAY BE NECESSARY WITH RESPECT TO PATENTS, COPYRIGHT+//// AND OTHER INTELLECTUAL PROPERTY OF THIRD PARTIES.+//// +//// FOR THE AVOIDANCE OF DOUBT THE PROGRAM (I) IS NOT LICENSED FOR; (II)+//// IS NOT DESIGNED FOR OR INTENDED FOR; AND (III) MAY NOT BE USED FOR;+//// ANY MISSION CRITICAL APPLICATIONS SUCH AS, BUT NOT LIMITED TO+//// OPERATION OF NUCLEAR OR HEALTHCARE COMPUTER SYSTEMS AND/OR NETWORKS,+//// AIRCRAFT OR TRAIN CONTROL AND/OR COMMUNICATION SYSTEMS OR ANY OTHER+//// COMPUTER SYSTEMS AND/OR NETWORKS OR CONTROL AND/OR COMMUNICATION+//// SYSTEMS ALL IN WHICH CASE THE FAILURE OF THE PROGRAM COULD LEAD TO+//// DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL, MATERIAL OR ENVIRONMENTAL+//// DAMAGE. YOUR RIGHTS UNDER THIS LICENSE WILL TERMINATE AUTOMATICALLY+//// AND IMMEDIATELY WITHOUT NOTICE IF YOU FAIL TO COMPLY WITH THIS+//// PARAGRAPH.+//// +//// IN NO EVENT WILL ERICSSON, BE LIABLE FOR ANY DAMAGES WHATSOEVER,+//// INCLUDING BUT NOT LIMITED TO PERSONAL INJURY, ANY GENERAL, SPECIAL,+//// INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN+//// CONNECTION WITH THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT+//// NOT LIMITED TO LOSS OF PROFITS, BUSINESS INTERUPTIONS, OR ANY OTHER+//// COMMERCIAL DAMAGES OR LOSSES, LOSS OF DATA OR DATA BEING RENDERED+//// INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF+//// THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) REGARDLESS OF THE+//// THEORY OF LIABILITY (CONTRACT, TORT OR OTHERWISE), EVEN IF SUCH HOLDER+//// OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.+//// +//// (C) Ericsson AB 2013. All Rights Reserved.+//// ++#include <stdio.h>+#include <stdlib.h>++// Typedefs+typedef unsigned char uint8;+typedef unsigned short uint16;+typedef short int16;++// Macros to help with bit extraction/insertion+#define SHIFT(size,startpos) ((startpos)-(size)+1)+#define MASK(size, startpos) (((2<<(size-1))-1) << SHIFT(size,startpos))+#define PUTBITS( dest, data, size, startpos) dest = ((dest & ~MASK(size, startpos)) | ((data << SHIFT(size, startpos)) & MASK(size,startpos)))+#define SHIFTHIGH(size, startpos) (((startpos)-32)-(size)+1)+#define MASKHIGH(size, startpos) (((1<<(size))-1) << SHIFTHIGH(size,startpos))+#define PUTBITSHIGH(dest, data, size, startpos) dest = ((dest & ~MASKHIGH(size, startpos)) | ((data << SHIFTHIGH(size, startpos)) & MASKHIGH(size,startpos)))+#define GETBITS(source, size, startpos) (( (source) >> ((startpos)-(size)+1) ) & ((1<<(size)) -1))+#define GETBITSHIGH(source, size, startpos) (( (source) >> (((startpos)-32)-(size)+1) ) & ((1<<(size)) -1))+#ifndef PGMOUT+#define PGMOUT 0+#endif+// Thumb macros and definitions+#define R_BITS59T 4+#define G_BITS59T 4+#define B_BITS59T 4+#define R_BITS58H 4+#define G_BITS58H 4+#define B_BITS58H 4+#define MAXIMUM_ERROR (255*255*16*1000)+#define R 0+#define G 1+#define B 2+#define BLOCKHEIGHT 4+#define BLOCKWIDTH 4+#define BINPOW(power) (1<<(power))+#define TABLE_BITS_59T 3+#define TABLE_BITS_58H 3++// Helper Macros+#define CLAMP(ll,x,ul) (((x)<(ll)) ? (ll) : (((x)>(ul)) ? (ul) : (x)))+#define JAS_ROUND(x) (((x) < 0.0 ) ? ((int)((x)-0.5)) : ((int)((x)+0.5)))++#define RED_CHANNEL(img,width,x,y,channels) img[channels*(y*width+x)+0]+#define GREEN_CHANNEL(img,width,x,y,channels) img[channels*(y*width+x)+1]+#define BLUE_CHANNEL(img,width,x,y,channels) img[channels*(y*width+x)+2]+#define ALPHA_CHANNEL(img,width,x,y,channels) img[channels*(y*width+x)+3]+++// Global tables+static uint8 table59T[8] = {3,6,11,16,23,32,41,64}; // 3-bit table for the 59 bit T-mode+static uint8 table58H[8] = {3,6,11,16,23,32,41,64}; // 3-bit table for the 58 bit H-mode+static int compressParams[16][4] = {{-8, -2, 2, 8}, {-8, -2, 2, 8}, {-17, -5, 5, 17}, {-17, -5, 5, 17}, {-29, -9, 9, 29}, {-29, -9, 9, 29}, {-42, -13, 13, 42}, {-42, -13, 13, 42}, {-60, -18, 18, 60}, {-60, -18, 18, 60}, {-80, -24, 24, 80}, {-80, -24, 24, 80}, {-106, -33, 33, 106}, {-106, -33, 33, 106}, {-183, -47, 47, 183}, {-183, -47, 47, 183}};+static int unscramble[4] = {2, 3, 1, 0};+int alphaTableInitialized = 0;+int alphaTable[256][8];+int alphaBase[16][4] = { + {-15,-9,-6,-3},+ {-13,-10,-7,-3},+ {-13,-8,-5,-2},+ {-13,-6,-4,-2},+ {-12,-8,-6,-3},+ {-11,-9,-7,-3},+ {-11,-8,-7,-4},+ {-11,-8,-5,-3},+ { -10,-8,-6,-2},+ { -10,-8,-5,-2},+ { -10,-8,-4,-2},+ { -10,-7,-5,-2},+ { -10,-7,-4,-3},+ { -10,-3,-2, -1},+ { -9,-8,-6,-4},+ { -9,-7,-5,-3}+ };++// Global variables+int formatSigned = 0;++// Enums+ enum{PATTERN_H = 0, + PATTERN_T = 1};+++// Code used to create the valtab+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void setupAlphaTable() +{+ if(alphaTableInitialized)+ return;+ alphaTableInitialized = 1;++ //read table used for alpha compression+ int buf;+ for(int i = 16; i<32; i++) + {+ for(int j=0; j<8; j++) + {+ buf=alphaBase[i-16][3-j%4];+ if(j<4)+ alphaTable[i][j]=buf;+ else+ alphaTable[i][j]=(-buf-1);+ }+ }+ + //beyond the first 16 values, the rest of the table is implicit.. so calculate that!+ for(int i=0; i<256; i++) + {+ //fill remaining slots in table with multiples of the first ones.+ int mul = i/16;+ int old = 16+i%16;+ for(int j = 0; j<8; j++) + {+ alphaTable[i][j]=alphaTable[old][j]*mul;+ //note: we don't do clamping here, though we could, because we'll be clamped afterwards anyway.+ }+ }+}++// Read a word in big endian style+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void read_big_endian_2byte_word(unsigned short *blockadr, FILE *f)+{+ uint8 bytes[2];+ unsigned short block;++ (void) fread(&bytes[0], 1, 1, f);+ (void) fread(&bytes[1], 1, 1, f);++ block = 0;+ block |= bytes[0];+ block = block << 8;+ block |= bytes[1];++ blockadr[0] = block;+}++// Read a word in big endian style+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void read_big_endian_4byte_word(unsigned int *blockadr, FILE *f)+{+ uint8 bytes[4];+ unsigned int block;++ (void) fread(&bytes[0], 1, 1, f);+ (void) fread(&bytes[1], 1, 1, f);+ (void) fread(&bytes[2], 1, 1, f);+ (void) fread(&bytes[3], 1, 1, f);++ block = 0;+ block |= bytes[0];+ block = block << 8;+ block |= bytes[1];+ block = block << 8;+ block |= bytes[2];+ block = block << 8;+ block |= bytes[3];++ blockadr[0] = block;+}++// The format stores the bits for the three extra modes in a roundabout way to be able to+// fit them without increasing the bit rate. This function converts them into something+// that is easier to work with. +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void unstuff57bits(unsigned int planar_word1, unsigned int planar_word2, unsigned int &planar57_word1, unsigned int &planar57_word2)+{+ // Get bits from twotimer configuration for 57 bits+ // + // Go to this bit layout:+ //+ // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + // -----------------------------------------------------------------------------------------------+ // |R0 |G01G02 |B01B02 ;B03 |RH1 |RH2|GH |+ // -----------------------------------------------------------------------------------------------+ //+ // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0+ // -----------------------------------------------------------------------------------------------+ // |BH |RV |GV |BV | not used | + // -----------------------------------------------------------------------------------------------+ //+ // From this:+ // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + // ------------------------------------------------------------------------------------------------+ // |//|R0 |G01|/|G02 |B01|/ // //|B02 |//|B03 |RH1 |df|RH2|+ // ------------------------------------------------------------------------------------------------+ //+ // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0+ // -----------------------------------------------------------------------------------------------+ // |GH |BH |RV |GV |BV |+ // -----------------------------------------------------------------------------------------------+ //+ // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + // ---------------------------------------------------------------------------------------------------+ // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip|+ // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit |+ // ---------------------------------------------------------------------------------------------------++ uint8 RO, GO1, GO2, BO1, BO2, BO3, RH1, RH2, GH, BH, RV, GV, BV;++ RO = GETBITSHIGH( planar_word1, 6, 62);+ GO1 = GETBITSHIGH( planar_word1, 1, 56);+ GO2 = GETBITSHIGH( planar_word1, 6, 54);+ BO1 = GETBITSHIGH( planar_word1, 1, 48);+ BO2 = GETBITSHIGH( planar_word1, 2, 44);+ BO3 = GETBITSHIGH( planar_word1, 3, 41);+ RH1 = GETBITSHIGH( planar_word1, 5, 38);+ RH2 = GETBITSHIGH( planar_word1, 1, 32);+ GH = GETBITS( planar_word2, 7, 31);+ BH = GETBITS( planar_word2, 6, 24);+ RV = GETBITS( planar_word2, 6, 18);+ GV = GETBITS( planar_word2, 7, 12);+ BV = GETBITS( planar_word2, 6, 5);++ planar57_word1 = 0; planar57_word2 = 0;+ PUTBITSHIGH( planar57_word1, RO, 6, 63);+ PUTBITSHIGH( planar57_word1, GO1, 1, 57);+ PUTBITSHIGH( planar57_word1, GO2, 6, 56);+ PUTBITSHIGH( planar57_word1, BO1, 1, 50);+ PUTBITSHIGH( planar57_word1, BO2, 2, 49);+ PUTBITSHIGH( planar57_word1, BO3, 3, 47);+ PUTBITSHIGH( planar57_word1, RH1, 5, 44);+ PUTBITSHIGH( planar57_word1, RH2, 1, 39);+ PUTBITSHIGH( planar57_word1, GH, 7, 38);+ PUTBITS( planar57_word2, BH, 6, 31);+ PUTBITS( planar57_word2, RV, 6, 25);+ PUTBITS( planar57_word2, GV, 7, 19);+ PUTBITS( planar57_word2, BV, 6, 12);+}++// The format stores the bits for the three extra modes in a roundabout way to be able to+// fit them without increasing the bit rate. This function converts them into something+// that is easier to work with. +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void unstuff58bits(unsigned int thumbH_word1, unsigned int thumbH_word2, unsigned int &thumbH58_word1, unsigned int &thumbH58_word2)+{+ // Go to this layout:+ //+ // |63 62 61 60 59 58|57 56 55 54 53 52 51|50 49|48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33|32 |+ // |-------empty-----|part0---------------|part1|part2------------------------------------------|part3|+ //+ // from this:+ // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + // --------------------------------------------------------------------------------------------------|+ // |//|part0 |// // //|part1|//|part2 |df|part3|+ // --------------------------------------------------------------------------------------------------|++ unsigned int part0, part1, part2, part3;++ // move parts+ part0 = GETBITSHIGH( thumbH_word1, 7, 62);+ part1 = GETBITSHIGH( thumbH_word1, 2, 52);+ part2 = GETBITSHIGH( thumbH_word1,16, 49);+ part3 = GETBITSHIGH( thumbH_word1, 1, 32);+ thumbH58_word1 = 0;+ PUTBITSHIGH( thumbH58_word1, part0, 7, 57);+ PUTBITSHIGH( thumbH58_word1, part1, 2, 50);+ PUTBITSHIGH( thumbH58_word1, part2, 16, 48);+ PUTBITSHIGH( thumbH58_word1, part3, 1, 32);++ thumbH58_word2 = thumbH_word2;+}++// The format stores the bits for the three extra modes in a roundabout way to be able to+// fit them without increasing the bit rate. This function converts them into something+// that is easier to work with. +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void unstuff59bits(unsigned int thumbT_word1, unsigned int thumbT_word2, unsigned int &thumbT59_word1, unsigned int &thumbT59_word2)+{+ // Get bits from twotimer configuration 59 bits. + // + // Go to this bit layout:+ //+ // |63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32|+ // |----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--|+ //+ // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00|+ // |----------------------------------------index bits---------------------------------------------|+ //+ //+ // From this:+ // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + // -----------------------------------------------------------------------------------------------+ // |// // //|R0a |//|R0b |G0 |B0 |R1 |G1 |B1 |da |df|db|+ // -----------------------------------------------------------------------------------------------+ //+ // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00|+ // |----------------------------------------index bits---------------------------------------------|+ //+ // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 + // -----------------------------------------------------------------------------------------------+ // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |df|fp|+ // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bt|bt|+ // ------------------------------------------------------------------------------------------------++ uint8 R0a;++ // Fix middle part+ thumbT59_word1 = thumbT_word1 >> 1;+ // Fix db (lowest bit of d)+ PUTBITSHIGH( thumbT59_word1, thumbT_word1, 1, 32);+ // Fix R0a (top two bits of R0)+ R0a = GETBITSHIGH( thumbT_word1, 2, 60);+ PUTBITSHIGH( thumbT59_word1, R0a, 2, 58);++ // Zero top part (not needed)+ PUTBITSHIGH( thumbT59_word1, 0, 5, 63);++ thumbT59_word2 = thumbT_word2;+}++// The color bits are expanded to the full color+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressColor(int R_B, int G_B, int B_B, uint8 (colors_RGB444)[2][3], uint8 (colors)[2][3]) +{+ // The color should be retrieved as:+ //+ // c = round(255/(r_bits^2-1))*comp_color+ //+ // This is similar to bit replication+ // + // Note -- this code only work for bit replication from 4 bits and up --- 3 bits needs+ // two copy operations.++ colors[0][R] = (colors_RGB444[0][R] << (8 - R_B)) | (colors_RGB444[0][R] >> (R_B - (8-R_B)) );+ colors[0][G] = (colors_RGB444[0][G] << (8 - G_B)) | (colors_RGB444[0][G] >> (G_B - (8-G_B)) );+ colors[0][B] = (colors_RGB444[0][B] << (8 - B_B)) | (colors_RGB444[0][B] >> (B_B - (8-B_B)) );+ colors[1][R] = (colors_RGB444[1][R] << (8 - R_B)) | (colors_RGB444[1][R] >> (R_B - (8-R_B)) );+ colors[1][G] = (colors_RGB444[1][G] << (8 - G_B)) | (colors_RGB444[1][G] >> (G_B - (8-G_B)) );+ colors[1][B] = (colors_RGB444[1][B] << (8 - B_B)) | (colors_RGB444[1][B] >> (B_B - (8-B_B)) );+}++void calculatePaintColors59T(uint8 d, uint8 p, uint8 (colors)[2][3], uint8 (possible_colors)[4][3]) +{+ //////////////////////////////////////////////+ //+ // C3 C1 C4----C1---C2+ // | | |+ // | | |+ // |-------| |+ // | | |+ // | | |+ // C4 C2 C3+ //+ //////////////////////////////////////////////++ // C4+ possible_colors[3][R] = CLAMP(0,colors[1][R] - table59T[d],255);+ possible_colors[3][G] = CLAMP(0,colors[1][G] - table59T[d],255);+ possible_colors[3][B] = CLAMP(0,colors[1][B] - table59T[d],255);+ + if (p == PATTERN_T) + {+ // C3+ possible_colors[0][R] = colors[0][R];+ possible_colors[0][G] = colors[0][G];+ possible_colors[0][B] = colors[0][B];+ // C2+ possible_colors[1][R] = CLAMP(0,colors[1][R] + table59T[d],255);+ possible_colors[1][G] = CLAMP(0,colors[1][G] + table59T[d],255);+ possible_colors[1][B] = CLAMP(0,colors[1][B] + table59T[d],255);+ // C1+ possible_colors[2][R] = colors[1][R];+ possible_colors[2][G] = colors[1][G];+ possible_colors[2][B] = colors[1][B];++ } + else + {+ printf("Invalid pattern. Terminating");+ exit(1);+ }+}+// Decompress a T-mode block (simple packing)+// Simple 59T packing:+//|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32|+//|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--|+//+//|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00|+//|----------------------------------------index bits---------------------------------------------|+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockTHUMB59Tc(unsigned int block_part1, unsigned int block_part2, uint8 *img,int width,int height,int startx,int starty, int channels)+{+ uint8 colorsRGB444[2][3];+ uint8 colors[2][3];+ uint8 paint_colors[4][3];+ uint8 distance;+ uint8 block_mask[4][4];++ // First decode left part of block.+ colorsRGB444[0][R]= GETBITSHIGH(block_part1, 4, 58);+ colorsRGB444[0][G]= GETBITSHIGH(block_part1, 4, 54);+ colorsRGB444[0][B]= GETBITSHIGH(block_part1, 4, 50);++ colorsRGB444[1][R]= GETBITSHIGH(block_part1, 4, 46);+ colorsRGB444[1][G]= GETBITSHIGH(block_part1, 4, 42);+ colorsRGB444[1][B]= GETBITSHIGH(block_part1, 4, 38);++ distance = GETBITSHIGH(block_part1, TABLE_BITS_59T, 34);++ // Extend the two colors to RGB888 + decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); + calculatePaintColors59T(distance, PATTERN_T, colors, paint_colors);+ + // Choose one of the four paint colors for each texel+ for (uint8 x = 0; x < BLOCKWIDTH; ++x) + {+ for (uint8 y = 0; y < BLOCKHEIGHT; ++y) + {+ //block_mask[x][y] = GETBITS(block_part2,2,31-(y*4+x)*2);+ block_mask[x][y] = GETBITS(block_part2,1,(y+x*4)+16)<<1;+ block_mask[x][y] |= GETBITS(block_part2,1,(y+x*4));+ img[channels*((starty+y)*width+startx+x)+R] =+ CLAMP(0,paint_colors[block_mask[x][y]][R],255); // RED+ img[channels*((starty+y)*width+startx+x)+G] =+ CLAMP(0,paint_colors[block_mask[x][y]][G],255); // GREEN+ img[channels*((starty+y)*width+startx+x)+B] =+ CLAMP(0,paint_colors[block_mask[x][y]][B],255); // BLUE+ }+ }+}++void decompressBlockTHUMB59T(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty)+{+ decompressBlockTHUMB59Tc(block_part1, block_part2, img, width, height, startx, starty, 3);+}++// Calculate the paint colors from the block colors +// using a distance d and one of the H- or T-patterns.+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void calculatePaintColors58H(uint8 d, uint8 p, uint8 (colors)[2][3], uint8 (possible_colors)[4][3]) +{+ + //////////////////////////////////////////////+ //+ // C3 C1 C4----C1---C2+ // | | |+ // | | |+ // |-------| |+ // | | |+ // | | |+ // C4 C2 C3+ //+ //////////////////////////////////////////////++ // C4+ possible_colors[3][R] = CLAMP(0,colors[1][R] - table58H[d],255);+ possible_colors[3][G] = CLAMP(0,colors[1][G] - table58H[d],255);+ possible_colors[3][B] = CLAMP(0,colors[1][B] - table58H[d],255);+ + if (p == PATTERN_H) + { + // C1+ possible_colors[0][R] = CLAMP(0,colors[0][R] + table58H[d],255);+ possible_colors[0][G] = CLAMP(0,colors[0][G] + table58H[d],255);+ possible_colors[0][B] = CLAMP(0,colors[0][B] + table58H[d],255);+ // C2+ possible_colors[1][R] = CLAMP(0,colors[0][R] - table58H[d],255);+ possible_colors[1][G] = CLAMP(0,colors[0][G] - table58H[d],255);+ possible_colors[1][B] = CLAMP(0,colors[0][B] - table58H[d],255);+ // C3+ possible_colors[2][R] = CLAMP(0,colors[1][R] + table58H[d],255);+ possible_colors[2][G] = CLAMP(0,colors[1][G] + table58H[d],255);+ possible_colors[2][B] = CLAMP(0,colors[1][B] + table58H[d],255);+ } + else + {+ printf("Invalid pattern. Terminating");+ exit(1);+ }+}++// Decompress an H-mode block +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockTHUMB58Hc(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty, int channels)+{+ unsigned int col0, col1;+ uint8 colors[2][3];+ uint8 colorsRGB444[2][3];+ uint8 paint_colors[4][3];+ uint8 distance;+ uint8 block_mask[4][4];+ + // First decode left part of block.+ colorsRGB444[0][R]= GETBITSHIGH(block_part1, 4, 57);+ colorsRGB444[0][G]= GETBITSHIGH(block_part1, 4, 53);+ colorsRGB444[0][B]= GETBITSHIGH(block_part1, 4, 49);++ colorsRGB444[1][R]= GETBITSHIGH(block_part1, 4, 45);+ colorsRGB444[1][G]= GETBITSHIGH(block_part1, 4, 41);+ colorsRGB444[1][B]= GETBITSHIGH(block_part1, 4, 37);++ distance = 0;+ distance = (GETBITSHIGH(block_part1, 2, 33)) << 1;++ col0 = GETBITSHIGH(block_part1, 12, 57);+ col1 = GETBITSHIGH(block_part1, 12, 45);++ if(col0 >= col1)+ {+ distance |= 1;+ }++ // Extend the two colors to RGB888 + decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); + + calculatePaintColors58H(distance, PATTERN_H, colors, paint_colors);+ + // Choose one of the four paint colors for each texel+ for (uint8 x = 0; x < BLOCKWIDTH; ++x) + {+ for (uint8 y = 0; y < BLOCKHEIGHT; ++y) + {+ //block_mask[x][y] = GETBITS(block_part2,2,31-(y*4+x)*2);+ block_mask[x][y] = GETBITS(block_part2,1,(y+x*4)+16)<<1;+ block_mask[x][y] |= GETBITS(block_part2,1,(y+x*4));+ img[channels*((starty+y)*width+startx+x)+R] =+ CLAMP(0,paint_colors[block_mask[x][y]][R],255); // RED+ img[channels*((starty+y)*width+startx+x)+G] =+ CLAMP(0,paint_colors[block_mask[x][y]][G],255); // GREEN+ img[channels*((starty+y)*width+startx+x)+B] =+ CLAMP(0,paint_colors[block_mask[x][y]][B],255); // BLUE+ }+ }+}+void decompressBlockTHUMB58H(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty)+{+ decompressBlockTHUMB58Hc(block_part1, block_part2, img, width, height, startx, starty, 3);+}++// Decompress the planar mode.+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockPlanar57c(unsigned int compressed57_1, unsigned int compressed57_2, uint8 *img, int width, int height, int startx, int starty, int channels)+{+ uint8 colorO[3], colorH[3], colorV[3];++ colorO[0] = GETBITSHIGH( compressed57_1, 6, 63);+ colorO[1] = GETBITSHIGH( compressed57_1, 7, 57);+ colorO[2] = GETBITSHIGH( compressed57_1, 6, 50);+ colorH[0] = GETBITSHIGH( compressed57_1, 6, 44);+ colorH[1] = GETBITSHIGH( compressed57_1, 7, 38);+ colorH[2] = GETBITS( compressed57_2, 6, 31);+ colorV[0] = GETBITS( compressed57_2, 6, 25);+ colorV[1] = GETBITS( compressed57_2, 7, 19);+ colorV[2] = GETBITS( compressed57_2, 6, 12);++ colorO[0] = (colorO[0] << 2) | (colorO[0] >> 4);+ colorO[1] = (colorO[1] << 1) | (colorO[1] >> 6);+ colorO[2] = (colorO[2] << 2) | (colorO[2] >> 4);++ colorH[0] = (colorH[0] << 2) | (colorH[0] >> 4);+ colorH[1] = (colorH[1] << 1) | (colorH[1] >> 6);+ colorH[2] = (colorH[2] << 2) | (colorH[2] >> 4);++ colorV[0] = (colorV[0] << 2) | (colorV[0] >> 4);+ colorV[1] = (colorV[1] << 1) | (colorV[1] >> 6);+ colorV[2] = (colorV[2] << 2) | (colorV[2] >> 4);++ int xx, yy;++ for( xx=0; xx<4; xx++)+ {+ for( yy=0; yy<4; yy++)+ {+ img[channels*width*(starty+yy) + channels*(startx+xx) + 0] = CLAMP(0, ((xx*(colorH[0]-colorO[0]) + yy*(colorV[0]-colorO[0]) + 4*colorO[0] + 2) >> 2),255);+ img[channels*width*(starty+yy) + channels*(startx+xx) + 1] = CLAMP(0, ((xx*(colorH[1]-colorO[1]) + yy*(colorV[1]-colorO[1]) + 4*colorO[1] + 2) >> 2),255);+ img[channels*width*(starty+yy) + channels*(startx+xx) + 2] = CLAMP(0, ((xx*(colorH[2]-colorO[2]) + yy*(colorV[2]-colorO[2]) + 4*colorO[2] + 2) >> 2),255);++ //Equivalent method+ /*img[channels*width*(starty+yy) + channels*(startx+xx) + 0] = (int)CLAMP(0, JAS_ROUND((xx*(colorH[0]-colorO[0])/4.0 + yy*(colorV[0]-colorO[0])/4.0 + colorO[0])), 255);+ img[channels*width*(starty+yy) + channels*(startx+xx) + 1] = (int)CLAMP(0, JAS_ROUND((xx*(colorH[1]-colorO[1])/4.0 + yy*(colorV[1]-colorO[1])/4.0 + colorO[1])), 255);+ img[channels*width*(starty+yy) + channels*(startx+xx) + 2] = (int)CLAMP(0, JAS_ROUND((xx*(colorH[2]-colorO[2])/4.0 + yy*(colorV[2]-colorO[2])/4.0 + colorO[2])), 255);*/+ + }+ }+}+void decompressBlockPlanar57(unsigned int compressed57_1, unsigned int compressed57_2, uint8 *img, int width, int height, int startx, int starty)+{+ decompressBlockPlanar57c(compressed57_1, compressed57_2, img, width, height, startx, starty, 3);+}+// Decompress an ETC1 block (or ETC2 using individual or differential mode).+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockDiffFlipC(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty, int channels)+{+ uint8 avg_color[3], enc_color1[3], enc_color2[3];+ signed char diff[3];+ int table;+ int index,shift;+ int r,g,b;+ int diffbit;+ int flipbit;++ diffbit = (GETBITSHIGH(block_part1, 1, 33));+ flipbit = (GETBITSHIGH(block_part1, 1, 32));++ if( !diffbit )+ {+ // We have diffbit = 0.++ // First decode left part of block.+ avg_color[0]= GETBITSHIGH(block_part1, 4, 63);+ avg_color[1]= GETBITSHIGH(block_part1, 4, 55);+ avg_color[2]= GETBITSHIGH(block_part1, 4, 47);++ // Here, we should really multiply by 17 instead of 16. This can+ // be done by just copying the four lower bits to the upper ones+ // while keeping the lower bits.+ avg_color[0] |= (avg_color[0] <<4);+ avg_color[1] |= (avg_color[1] <<4);+ avg_color[2] |= (avg_color[2] <<4);++ table = GETBITSHIGH(block_part1, 3, 39) << 1;++ unsigned int pixel_indices_MSB, pixel_indices_LSB;+ + pixel_indices_MSB = GETBITS(block_part2, 16, 31);+ pixel_indices_LSB = GETBITS(block_part2, 16, 15);++ if( (flipbit) == 0 )+ {+ // We should not flip+ shift = 0;+ for(int x=startx; x<startx+2; x++)+ {+ for(int y=starty; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ r=RED_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[0]+compressParams[table][index],255);+ g=GREEN_CHANNEL(img,width,x,y,channels)=CLAMP(0,avg_color[1]+compressParams[table][index],255);+ b=BLUE_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[2]+compressParams[table][index],255);+ }+ }+ }+ else+ {+ // We should flip+ shift = 0;+ for(int x=startx; x<startx+4; x++)+ {+ for(int y=starty; y<starty+2; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ r=RED_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[0]+compressParams[table][index],255);+ g=GREEN_CHANNEL(img,width,x,y,channels)=CLAMP(0,avg_color[1]+compressParams[table][index],255);+ b=BLUE_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[2]+compressParams[table][index],255);+ }+ shift+=2;+ }+ }++ // Now decode other part of block. + avg_color[0]= GETBITSHIGH(block_part1, 4, 59);+ avg_color[1]= GETBITSHIGH(block_part1, 4, 51);+ avg_color[2]= GETBITSHIGH(block_part1, 4, 43);++ // Here, we should really multiply by 17 instead of 16. This can+ // be done by just copying the four lower bits to the upper ones+ // while keeping the lower bits.+ avg_color[0] |= (avg_color[0] <<4);+ avg_color[1] |= (avg_color[1] <<4);+ avg_color[2] |= (avg_color[2] <<4);++ table = GETBITSHIGH(block_part1, 3, 36) << 1;+ pixel_indices_MSB = GETBITS(block_part2, 16, 31);+ pixel_indices_LSB = GETBITS(block_part2, 16, 15);++ if( (flipbit) == 0 )+ {+ // We should not flip+ shift=8;+ for(int x=startx+2; x<startx+4; x++)+ {+ for(int y=starty; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ r=RED_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[0]+compressParams[table][index],255);+ g=GREEN_CHANNEL(img,width,x,y,channels)=CLAMP(0,avg_color[1]+compressParams[table][index],255);+ b=BLUE_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[2]+compressParams[table][index],255);+ }+ }+ }+ else+ {+ // We should flip+ shift=2;+ for(int x=startx; x<startx+4; x++)+ {+ for(int y=starty+2; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ r=RED_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[0]+compressParams[table][index],255);+ g=GREEN_CHANNEL(img,width,x,y,channels)=CLAMP(0,avg_color[1]+compressParams[table][index],255);+ b=BLUE_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[2]+compressParams[table][index],255);+ }+ shift += 2;+ }+ }+ }+ else+ {+ // We have diffbit = 1. ++// 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 +// ---------------------------------------------------------------------------------------------------+// | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip|+// | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit |+// ---------------------------------------------------------------------------------------------------+// +// +// c) bit layout in bits 31 through 0 (in both cases)+// +// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0+// --------------------------------------------------------------------------------------------------+// | most significant pixel index bits | least significant pixel index bits | +// | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a |+// -------------------------------------------------------------------------------------------------- ++ // First decode left part of block.+ enc_color1[0]= GETBITSHIGH(block_part1, 5, 63);+ enc_color1[1]= GETBITSHIGH(block_part1, 5, 55);+ enc_color1[2]= GETBITSHIGH(block_part1, 5, 47);++ // Expand from 5 to 8 bits+ avg_color[0] = (enc_color1[0] <<3) | (enc_color1[0] >> 2);+ avg_color[1] = (enc_color1[1] <<3) | (enc_color1[1] >> 2);+ avg_color[2] = (enc_color1[2] <<3) | (enc_color1[2] >> 2);++ table = GETBITSHIGH(block_part1, 3, 39) << 1;++ unsigned int pixel_indices_MSB, pixel_indices_LSB;+ + pixel_indices_MSB = GETBITS(block_part2, 16, 31);+ pixel_indices_LSB = GETBITS(block_part2, 16, 15);++ if( (flipbit) == 0 )+ {+ // We should not flip+ shift = 0;+ for(int x=startx; x<startx+2; x++)+ {+ for(int y=starty; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ r=RED_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[0]+compressParams[table][index],255);+ g=GREEN_CHANNEL(img,width,x,y,channels)=CLAMP(0,avg_color[1]+compressParams[table][index],255);+ b=BLUE_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[2]+compressParams[table][index],255);+ }+ }+ }+ else+ {+ // We should flip+ shift = 0;+ for(int x=startx; x<startx+4; x++)+ {+ for(int y=starty; y<starty+2; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ r=RED_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[0]+compressParams[table][index],255);+ g=GREEN_CHANNEL(img,width,x,y,channels)=CLAMP(0,avg_color[1]+compressParams[table][index],255);+ b=BLUE_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[2]+compressParams[table][index],255);+ }+ shift+=2;+ }+ }++ // Now decode right part of block. + diff[0]= GETBITSHIGH(block_part1, 3, 58);+ diff[1]= GETBITSHIGH(block_part1, 3, 50);+ diff[2]= GETBITSHIGH(block_part1, 3, 42);++ // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5);+ diff[1] = (diff[1] << 5);+ diff[2] = (diff[2] << 5);+ diff[0] = diff[0] >> 5;+ diff[1] = diff[1] >> 5;+ diff[2] = diff[2] >> 5;++ // Calculale second color+ enc_color2[0]= enc_color1[0] + diff[0];+ enc_color2[1]= enc_color1[1] + diff[1];+ enc_color2[2]= enc_color1[2] + diff[2];++ // Expand from 5 to 8 bits+ avg_color[0] = (enc_color2[0] <<3) | (enc_color2[0] >> 2);+ avg_color[1] = (enc_color2[1] <<3) | (enc_color2[1] >> 2);+ avg_color[2] = (enc_color2[2] <<3) | (enc_color2[2] >> 2);++ table = GETBITSHIGH(block_part1, 3, 36) << 1;+ pixel_indices_MSB = GETBITS(block_part2, 16, 31);+ pixel_indices_LSB = GETBITS(block_part2, 16, 15);++ if( (flipbit) == 0 )+ {+ // We should not flip+ shift=8;+ for(int x=startx+2; x<startx+4; x++)+ {+ for(int y=starty; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ r=RED_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[0]+compressParams[table][index],255);+ g=GREEN_CHANNEL(img,width,x,y,channels)=CLAMP(0,avg_color[1]+compressParams[table][index],255);+ b=BLUE_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[2]+compressParams[table][index],255);+ }+ }+ }+ else+ {+ // We should flip+ shift=2;+ for(int x=startx; x<startx+4; x++)+ {+ for(int y=starty+2; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ r=RED_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[0]+compressParams[table][index],255);+ g=GREEN_CHANNEL(img,width,x,y,channels)=CLAMP(0,avg_color[1]+compressParams[table][index],255);+ b=BLUE_CHANNEL(img,width,x,y,channels) =CLAMP(0,avg_color[2]+compressParams[table][index],255);+ }+ shift += 2;+ }+ }+ }+}+void decompressBlockDiffFlip(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty)+{+ decompressBlockDiffFlipC(block_part1, block_part2, img, width, height, startx, starty, 3);+}++// Decompress an ETC2 RGB block+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockETC2c(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty, int channels)+{+ int diffbit;+ signed char color1[3];+ signed char diff[3];+ signed char red, green, blue;++ diffbit = (GETBITSHIGH(block_part1, 1, 33));++ if( diffbit )+ {+ // We have diffbit = 1;++ // Base color+ color1[0]= GETBITSHIGH(block_part1, 5, 63);+ color1[1]= GETBITSHIGH(block_part1, 5, 55);+ color1[2]= GETBITSHIGH(block_part1, 5, 47);++ // Diff color+ diff[0]= GETBITSHIGH(block_part1, 3, 58);+ diff[1]= GETBITSHIGH(block_part1, 3, 50);+ diff[2]= GETBITSHIGH(block_part1, 3, 42);++ // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5);+ diff[1] = (diff[1] << 5);+ diff[2] = (diff[2] << 5);+ diff[0] = diff[0] >> 5;+ diff[1] = diff[1] >> 5;+ diff[2] = diff[2] >> 5;++ red = color1[0] + diff[0];+ green = color1[1] + diff[1];+ blue = color1[2] + diff[2];++ if(red < 0 || red > 31)+ {+ unsigned int block59_part1, block59_part2;+ unstuff59bits(block_part1, block_part2, block59_part1, block59_part2);+ decompressBlockTHUMB59Tc(block59_part1, block59_part2, img, width, height, startx, starty, channels);+ }+ else if (green < 0 || green > 31)+ {+ unsigned int block58_part1, block58_part2;+ unstuff58bits(block_part1, block_part2, block58_part1, block58_part2);+ decompressBlockTHUMB58Hc(block58_part1, block58_part2, img, width, height, startx, starty, channels);+ }+ else if(blue < 0 || blue > 31)+ {+ unsigned int block57_part1, block57_part2;++ unstuff57bits(block_part1, block_part2, block57_part1, block57_part2);+ decompressBlockPlanar57c(block57_part1, block57_part2, img, width, height, startx, starty, channels);+ }+ else+ {+ decompressBlockDiffFlipC(block_part1, block_part2, img, width, height, startx, starty, channels);+ }+ }+ else+ {+ // We have diffbit = 0;+ decompressBlockDiffFlipC(block_part1, block_part2, img, width, height, startx, starty, channels);+ }+}+void decompressBlockETC2(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty)+{+ decompressBlockETC2c(block_part1, block_part2, img, width, height, startx, starty, 3);+}+// Decompress an ETC2 block with punchthrough alpha+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockDifferentialWithAlphaC(unsigned int block_part1, unsigned int block_part2, uint8* img, uint8* alpha, int width, int height, int startx, int starty, int channelsRGB)+{+ + uint8 avg_color[3], enc_color1[3], enc_color2[3];+ signed char diff[3];+ int table;+ int index,shift;+ int r,g,b;+ int diffbit;+ int flipbit;+ int channelsA;++ if(channelsRGB == 3)+ {+ // We will decode the alpha data to a separate memory area. + channelsA = 1;+ }+ else+ {+ // We will decode the RGB data and the alpha data to the same memory area, + // interleaved as RGBA. + channelsA = 4;+ alpha = &img[0+3];+ }++ //the diffbit now encodes whether or not the entire alpha channel is 255.+ diffbit = (GETBITSHIGH(block_part1, 1, 33));+ flipbit = (GETBITSHIGH(block_part1, 1, 32));++ // First decode left part of block.+ enc_color1[0]= GETBITSHIGH(block_part1, 5, 63);+ enc_color1[1]= GETBITSHIGH(block_part1, 5, 55);+ enc_color1[2]= GETBITSHIGH(block_part1, 5, 47);++ // Expand from 5 to 8 bits+ avg_color[0] = (enc_color1[0] <<3) | (enc_color1[0] >> 2);+ avg_color[1] = (enc_color1[1] <<3) | (enc_color1[1] >> 2);+ avg_color[2] = (enc_color1[2] <<3) | (enc_color1[2] >> 2);++ table = GETBITSHIGH(block_part1, 3, 39) << 1;++ unsigned int pixel_indices_MSB, pixel_indices_LSB;+ + pixel_indices_MSB = GETBITS(block_part2, 16, 31);+ pixel_indices_LSB = GETBITS(block_part2, 16, 15);++ if( (flipbit) == 0 )+ {+ // We should not flip+ shift = 0;+ for(int x=startx; x<startx+2; x++)+ {+ for(int y=starty; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];++ int mod = compressParams[table][index];+ if(diffbit==0&&(index==1||index==2)) + {+ mod=0;+ }+ + r=RED_CHANNEL(img,width,x,y,channelsRGB) =CLAMP(0,avg_color[0]+mod,255);+ g=GREEN_CHANNEL(img,width,x,y,channelsRGB)=CLAMP(0,avg_color[1]+mod,255);+ b=BLUE_CHANNEL(img,width,x,y,channelsRGB) =CLAMP(0,avg_color[2]+mod,255);+ if(diffbit==0&&index==1) + {+ alpha[(y*width+x)*channelsA]=0;+ r=RED_CHANNEL(img,width,x,y,channelsRGB)=0;+ g=GREEN_CHANNEL(img,width,x,y,channelsRGB)=0;+ b=BLUE_CHANNEL(img,width,x,y,channelsRGB)=0;+ }+ else + {+ alpha[(y*width+x)*channelsA]=255;+ }++ }+ }+ }+ else+ {+ // We should flip+ shift = 0;+ for(int x=startx; x<startx+4; x++)+ {+ for(int y=starty; y<starty+2; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];+ int mod = compressParams[table][index];+ if(diffbit==0&&(index==1||index==2)) + {+ mod=0;+ }+ r=RED_CHANNEL(img,width,x,y,channelsRGB) =CLAMP(0,avg_color[0]+mod,255);+ g=GREEN_CHANNEL(img,width,x,y,channelsRGB)=CLAMP(0,avg_color[1]+mod,255);+ b=BLUE_CHANNEL(img,width,x,y,channelsRGB) =CLAMP(0,avg_color[2]+mod,255);+ if(diffbit==0&&index==1) + {+ alpha[(y*width+x)*channelsA]=0;+ r=RED_CHANNEL(img,width,x,y,channelsRGB)=0;+ g=GREEN_CHANNEL(img,width,x,y,channelsRGB)=0;+ b=BLUE_CHANNEL(img,width,x,y,channelsRGB)=0;+ }+ else + {+ alpha[(y*width+x)*channelsA]=255;+ }+ }+ shift+=2;+ }+ }+ // Now decode right part of block. + diff[0]= GETBITSHIGH(block_part1, 3, 58);+ diff[1]= GETBITSHIGH(block_part1, 3, 50);+ diff[2]= GETBITSHIGH(block_part1, 3, 42);++ // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5);+ diff[1] = (diff[1] << 5);+ diff[2] = (diff[2] << 5);+ diff[0] = diff[0] >> 5;+ diff[1] = diff[1] >> 5;+ diff[2] = diff[2] >> 5;++ // Calculate second color+ enc_color2[0]= enc_color1[0] + diff[0];+ enc_color2[1]= enc_color1[1] + diff[1];+ enc_color2[2]= enc_color1[2] + diff[2];++ // Expand from 5 to 8 bits+ avg_color[0] = (enc_color2[0] <<3) | (enc_color2[0] >> 2);+ avg_color[1] = (enc_color2[1] <<3) | (enc_color2[1] >> 2);+ avg_color[2] = (enc_color2[2] <<3) | (enc_color2[2] >> 2);++ table = GETBITSHIGH(block_part1, 3, 36) << 1;+ pixel_indices_MSB = GETBITS(block_part2, 16, 31);+ pixel_indices_LSB = GETBITS(block_part2, 16, 15);++ if( (flipbit) == 0 )+ {+ // We should not flip+ shift=8;+ for(int x=startx+2; x<startx+4; x++)+ {+ for(int y=starty; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];+ int mod = compressParams[table][index];+ if(diffbit==0&&(index==1||index==2)) + {+ mod=0;+ }+ + r=RED_CHANNEL(img,width,x,y,channelsRGB) =CLAMP(0,avg_color[0]+mod,255);+ g=GREEN_CHANNEL(img,width,x,y,channelsRGB)=CLAMP(0,avg_color[1]+mod,255);+ b=BLUE_CHANNEL(img,width,x,y,channelsRGB) =CLAMP(0,avg_color[2]+mod,255);+ if(diffbit==0&&index==1) + {+ alpha[(y*width+x)*channelsA]=0;+ r=RED_CHANNEL(img,width,x,y,channelsRGB)=0;+ g=GREEN_CHANNEL(img,width,x,y,channelsRGB)=0;+ b=BLUE_CHANNEL(img,width,x,y,channelsRGB)=0;+ }+ else + {+ alpha[(y*width+x)*channelsA]=255;+ }+ }+ }+ }+ else+ {+ // We should flip+ shift=2;+ for(int x=startx; x<startx+4; x++)+ {+ for(int y=starty+2; y<starty+4; y++)+ {+ index = ((pixel_indices_MSB >> shift) & 1) << 1;+ index |= ((pixel_indices_LSB >> shift) & 1);+ shift++;+ index=unscramble[index];+ int mod = compressParams[table][index];+ if(diffbit==0&&(index==1||index==2)) + {+ mod=0;+ }+ + r=RED_CHANNEL(img,width,x,y,channelsRGB) =CLAMP(0,avg_color[0]+mod,255);+ g=GREEN_CHANNEL(img,width,x,y,channelsRGB)=CLAMP(0,avg_color[1]+mod,255);+ b=BLUE_CHANNEL(img,width,x,y,channelsRGB) =CLAMP(0,avg_color[2]+mod,255);+ if(diffbit==0&&index==1) + {+ alpha[(y*width+x)*channelsA]=0;+ r=RED_CHANNEL(img,width,x,y,channelsRGB)=0;+ g=GREEN_CHANNEL(img,width,x,y,channelsRGB)=0;+ b=BLUE_CHANNEL(img,width,x,y,channelsRGB)=0;+ }+ else + {+ alpha[(y*width+x)*channelsA]=255;+ }+ }+ shift += 2;+ }+ }+}+void decompressBlockDifferentialWithAlpha(unsigned int block_part1, unsigned int block_part2, uint8* img, uint8* alpha, int width, int height, int startx, int starty)+{+ decompressBlockDifferentialWithAlphaC(block_part1, block_part2, img, alpha, width, height, startx, starty, 3);+}+++// similar to regular decompression, but alpha channel is set to 0 if pixel index is 2, otherwise 255.+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockTHUMB59TAlphaC(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alpha, int width, int height, int startx, int starty, int channelsRGB)+{++ uint8 colorsRGB444[2][3];+ uint8 colors[2][3];+ uint8 paint_colors[4][3];+ uint8 distance;+ uint8 block_mask[4][4];+ int channelsA;++ if(channelsRGB == 3)+ {+ // We will decode the alpha data to a separate memory area. + channelsA = 1;+ }+ else+ {+ // We will decode the RGB data and the alpha data to the same memory area, + // interleaved as RGBA. + channelsA = 4;+ alpha = &img[0+3];+ }++ // First decode left part of block.+ colorsRGB444[0][R]= GETBITSHIGH(block_part1, 4, 58);+ colorsRGB444[0][G]= GETBITSHIGH(block_part1, 4, 54);+ colorsRGB444[0][B]= GETBITSHIGH(block_part1, 4, 50);++ colorsRGB444[1][R]= GETBITSHIGH(block_part1, 4, 46);+ colorsRGB444[1][G]= GETBITSHIGH(block_part1, 4, 42);+ colorsRGB444[1][B]= GETBITSHIGH(block_part1, 4, 38);++ distance = GETBITSHIGH(block_part1, TABLE_BITS_59T, 34);++ // Extend the two colors to RGB888 + decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); + calculatePaintColors59T(distance, PATTERN_T, colors, paint_colors);+ + // Choose one of the four paint colors for each texel+ for (uint8 x = 0; x < BLOCKWIDTH; ++x) + {+ for (uint8 y = 0; y < BLOCKHEIGHT; ++y) + {+ //block_mask[x][y] = GETBITS(block_part2,2,31-(y*4+x)*2);+ block_mask[x][y] = GETBITS(block_part2,1,(y+x*4)+16)<<1;+ block_mask[x][y] |= GETBITS(block_part2,1,(y+x*4));+ img[channelsRGB*((starty+y)*width+startx+x)+R] = + CLAMP(0,paint_colors[block_mask[x][y]][R],255); // RED+ img[channelsRGB*((starty+y)*width+startx+x)+G] =+ CLAMP(0,paint_colors[block_mask[x][y]][G],255); // GREEN+ img[channelsRGB*((starty+y)*width+startx+x)+B] =+ CLAMP(0,paint_colors[block_mask[x][y]][B],255); // BLUE+ if(block_mask[x][y]==2) + {+ alpha[channelsA*(x+startx+(y+starty)*width)]=0;+ img[channelsRGB*((starty+y)*width+startx+x)+R] =0;+ img[channelsRGB*((starty+y)*width+startx+x)+G] =0;+ img[channelsRGB*((starty+y)*width+startx+x)+B] =0;+ }+ else+ alpha[channelsA*(x+startx+(y+starty)*width)]=255;+ }+ }+}+void decompressBlockTHUMB59TAlpha(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alpha, int width, int height, int startx, int starty)+{+ decompressBlockTHUMB59TAlphaC(block_part1, block_part2, img, alpha, width, height, startx, starty, 3);+}+++// Decompress an H-mode block with alpha+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockTHUMB58HAlphaC(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alpha, int width, int height, int startx, int starty, int channelsRGB)+{+ unsigned int col0, col1;+ uint8 colors[2][3];+ uint8 colorsRGB444[2][3];+ uint8 paint_colors[4][3];+ uint8 distance;+ uint8 block_mask[4][4];+ int channelsA; ++ if(channelsRGB == 3)+ {+ // We will decode the alpha data to a separate memory area. + channelsA = 1;+ }+ else+ {+ // We will decode the RGB data and the alpha data to the same memory area, + // interleaved as RGBA. + channelsA = 4;+ alpha = &img[0+3];+ }++ // First decode left part of block.+ colorsRGB444[0][R]= GETBITSHIGH(block_part1, 4, 57);+ colorsRGB444[0][G]= GETBITSHIGH(block_part1, 4, 53);+ colorsRGB444[0][B]= GETBITSHIGH(block_part1, 4, 49);++ colorsRGB444[1][R]= GETBITSHIGH(block_part1, 4, 45);+ colorsRGB444[1][G]= GETBITSHIGH(block_part1, 4, 41);+ colorsRGB444[1][B]= GETBITSHIGH(block_part1, 4, 37);++ distance = 0;+ distance = (GETBITSHIGH(block_part1, 2, 33)) << 1;++ col0 = GETBITSHIGH(block_part1, 12, 57);+ col1 = GETBITSHIGH(block_part1, 12, 45);++ if(col0 >= col1)+ {+ distance |= 1;+ }++ // Extend the two colors to RGB888 + decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); + + calculatePaintColors58H(distance, PATTERN_H, colors, paint_colors);+ + // Choose one of the four paint colors for each texel+ for (uint8 x = 0; x < BLOCKWIDTH; ++x) + {+ for (uint8 y = 0; y < BLOCKHEIGHT; ++y) + {+ //block_mask[x][y] = GETBITS(block_part2,2,31-(y*4+x)*2);+ block_mask[x][y] = GETBITS(block_part2,1,(y+x*4)+16)<<1;+ block_mask[x][y] |= GETBITS(block_part2,1,(y+x*4));+ img[channelsRGB*((starty+y)*width+startx+x)+R] =+ CLAMP(0,paint_colors[block_mask[x][y]][R],255); // RED+ img[channelsRGB*((starty+y)*width+startx+x)+G] =+ CLAMP(0,paint_colors[block_mask[x][y]][G],255); // GREEN+ img[channelsRGB*((starty+y)*width+startx+x)+B] =+ CLAMP(0,paint_colors[block_mask[x][y]][B],255); // BLUE+ + if(block_mask[x][y]==2) + {+ alpha[channelsA*(x+startx+(y+starty)*width)]=0;+ img[channelsRGB*((starty+y)*width+startx+x)+R] =0;+ img[channelsRGB*((starty+y)*width+startx+x)+G] =0;+ img[channelsRGB*((starty+y)*width+startx+x)+B] =0;+ }+ else+ alpha[channelsA*(x+startx+(y+starty)*width)]=255;+ }+ }+}+void decompressBlockTHUMB58HAlpha(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alpha, int width, int height, int startx, int starty)+{+ decompressBlockTHUMB58HAlphaC(block_part1, block_part2, img, alpha, width, height, startx, starty, 3);+}+// Decompression function for ETC2_RGBA1 format.+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockETC21BitAlphaC(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alphaimg, int width, int height, int startx, int starty, int channelsRGB)+{+ int diffbit;+ signed char color1[3];+ signed char diff[3];+ signed char red, green, blue;+ int channelsA; ++ if(channelsRGB == 3)+ {+ // We will decode the alpha data to a separate memory area. + channelsA = 1;+ }+ else+ {+ // We will decode the RGB data and the alpha data to the same memory area, + // interleaved as RGBA. + channelsA = 4;+ alphaimg = &img[0+3];+ }++ diffbit = (GETBITSHIGH(block_part1, 1, 33));++ if( diffbit )+ {+ // We have diffbit = 1, meaning no transparent pixels. regular decompression.++ // Base color+ color1[0]= GETBITSHIGH(block_part1, 5, 63);+ color1[1]= GETBITSHIGH(block_part1, 5, 55);+ color1[2]= GETBITSHIGH(block_part1, 5, 47);++ // Diff color+ diff[0]= GETBITSHIGH(block_part1, 3, 58);+ diff[1]= GETBITSHIGH(block_part1, 3, 50);+ diff[2]= GETBITSHIGH(block_part1, 3, 42);++ // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5);+ diff[1] = (diff[1] << 5);+ diff[2] = (diff[2] << 5);+ diff[0] = diff[0] >> 5;+ diff[1] = diff[1] >> 5;+ diff[2] = diff[2] >> 5;++ red = color1[0] + diff[0];+ green = color1[1] + diff[1];+ blue = color1[2] + diff[2];++ if(red < 0 || red > 31)+ {+ unsigned int block59_part1, block59_part2;+ unstuff59bits(block_part1, block_part2, block59_part1, block59_part2);+ decompressBlockTHUMB59Tc(block59_part1, block59_part2, img, width, height, startx, starty, channelsRGB);+ }+ else if (green < 0 || green > 31)+ {+ unsigned int block58_part1, block58_part2;+ unstuff58bits(block_part1, block_part2, block58_part1, block58_part2);+ decompressBlockTHUMB58Hc(block58_part1, block58_part2, img, width, height, startx, starty, channelsRGB);+ }+ else if(blue < 0 || blue > 31)+ {+ unsigned int block57_part1, block57_part2;++ unstuff57bits(block_part1, block_part2, block57_part1, block57_part2);+ decompressBlockPlanar57c(block57_part1, block57_part2, img, width, height, startx, starty, channelsRGB);+ }+ else+ {+ decompressBlockDifferentialWithAlphaC(block_part1, block_part2, img, alphaimg, width, height, startx, starty, channelsRGB);+ }+ for(int x=startx; x<startx+4; x++) + {+ for(int y=starty; y<starty+4; y++) + {+ alphaimg[channelsA*(x+y*width)]=255;+ }+ }+ }+ else+ {+ // We have diffbit = 0, transparent pixels. Only T-, H- or regular diff-mode possible.+ + // Base color+ color1[0]= GETBITSHIGH(block_part1, 5, 63);+ color1[1]= GETBITSHIGH(block_part1, 5, 55);+ color1[2]= GETBITSHIGH(block_part1, 5, 47);++ // Diff color+ diff[0]= GETBITSHIGH(block_part1, 3, 58);+ diff[1]= GETBITSHIGH(block_part1, 3, 50);+ diff[2]= GETBITSHIGH(block_part1, 3, 42);++ // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5);+ diff[1] = (diff[1] << 5);+ diff[2] = (diff[2] << 5);+ diff[0] = diff[0] >> 5;+ diff[1] = diff[1] >> 5;+ diff[2] = diff[2] >> 5;++ red = color1[0] + diff[0];+ green = color1[1] + diff[1];+ blue = color1[2] + diff[2];+ if(red < 0 || red > 31)+ {+ unsigned int block59_part1, block59_part2;+ unstuff59bits(block_part1, block_part2, block59_part1, block59_part2);+ decompressBlockTHUMB59TAlphaC(block59_part1, block59_part2, img, alphaimg, width, height, startx, starty, channelsRGB);+ }+ else if(green < 0 || green > 31) + {+ unsigned int block58_part1, block58_part2;+ unstuff58bits(block_part1, block_part2, block58_part1, block58_part2);+ decompressBlockTHUMB58HAlphaC(block58_part1, block58_part2, img, alphaimg, width, height, startx, starty, channelsRGB);+ }+ else if(blue < 0 || blue > 31)+ {+ unsigned int block57_part1, block57_part2;++ unstuff57bits(block_part1, block_part2, block57_part1, block57_part2);+ decompressBlockPlanar57c(block57_part1, block57_part2, img, width, height, startx, starty, channelsRGB);+ for(int x=startx; x<startx+4; x++) + {+ for(int y=starty; y<starty+4; y++) + {+ alphaimg[channelsA*(x+y*width)]=255;+ }+ }+ }+ else+ decompressBlockDifferentialWithAlphaC(block_part1, block_part2, img,alphaimg, width, height, startx, starty, channelsRGB);+ }+}+void decompressBlockETC21BitAlpha(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alphaimg, int width, int height, int startx, int starty)+{+ decompressBlockETC21BitAlphaC(block_part1, block_part2, img, alphaimg, width, height, startx, starty, 3);+}+//+// Utility functions used for alpha compression+//++// bit number frompos is extracted from input, and moved to bit number topos in the return value.+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+uint8 getbit(uint8 input, int frompos, int topos) +{+ uint8 output=0;+ if(frompos>topos)+ return ((1<<frompos)&input)>>(frompos-topos);+ return ((1<<frompos)&input)<<(topos-frompos);+}++// takes as input a value, returns the value clamped to the interval [0,255].+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+int clamp(int val) +{+ if(val<0)+ val=0;+ if(val>255)+ val=255;+ return val;+}++// Decodes tha alpha component in a block coded with GL_COMPRESSED_RGBA8_ETC2_EAC.+// Note that this decoding is slightly different from that of GL_COMPRESSED_R11_EAC.+// However, a hardware decoder can share gates between the two formats as explained+// in the specification under GL_COMPRESSED_R11_EAC.+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockAlphaC(uint8* data, uint8* img, int width, int height, int ix, int iy, int channels) +{+ int alpha = data[0];+ int table = data[1];+ + int bit=0;+ int byte=2;+ //extract an alpha value for each pixel.+ for(int x=0; x<4; x++) + {+ for(int y=0; y<4; y++) + {+ //Extract table index+ int index=0;+ for(int bitpos=0; bitpos<3; bitpos++) + {+ index|=getbit(data[byte],7-bit,2-bitpos);+ bit++;+ if(bit>7) + {+ bit=0;+ byte++;+ }+ }+ img[(ix+x+(iy+y)*width)*channels]=clamp(alpha +alphaTable[table][index]);+ }+ }+}+void decompressBlockAlpha(uint8* data, uint8* img, int width, int height, int ix, int iy) +{+ decompressBlockAlphaC(data, img, width, height, ix, iy, 1);+}++// Does decompression and then immediately converts from 11 bit signed to a 16-bit format.+// +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+int16 get16bits11signed(int base, int table, int mul, int index) +{+ int elevenbase = base-128;+ if(elevenbase==-128)+ elevenbase=-127;+ elevenbase*=8;+ //i want the positive value here+ int tabVal = -alphaBase[table][3-index%4]-1;+ //and the sign, please+ int sign = 1-(index/4);+ + if(sign)+ tabVal=tabVal+1;+ int elevenTabVal = tabVal*8;++ if(mul!=0)+ elevenTabVal*=mul;+ else+ elevenTabVal/=8;++ if(sign)+ elevenTabVal=-elevenTabVal;++ //calculate sum+ int elevenbits = elevenbase+elevenTabVal;++ //clamp..+ if(elevenbits>=1024)+ elevenbits=1023;+ else if(elevenbits<-1023)+ elevenbits=-1023;+ //this is the value we would actually output.. + //but there aren't any good 11-bit file or uncompressed GL formats+ //so we extend to 15 bits signed.+ sign = elevenbits<0;+ elevenbits=abs(elevenbits);+ int16 fifteenbits = (elevenbits<<5)+(elevenbits>>5);+ int16 sixteenbits=fifteenbits;++ if(sign)+ sixteenbits=-sixteenbits;+ + return sixteenbits;+}++// Does decompression and then immediately converts from 11 bit signed to a 16-bit format +// Calculates the 11 bit value represented by base, table, mul and index, and extends it to 16 bits.+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+uint16 get16bits11bits(int base, int table, int mul, int index) +{+ int elevenbase = base*8+4;++ //i want the positive value here+ int tabVal = -alphaBase[table][3-index%4]-1;+ //and the sign, please+ int sign = 1-(index/4);+ + if(sign)+ tabVal=tabVal+1;+ int elevenTabVal = tabVal*8;++ if(mul!=0)+ elevenTabVal*=mul;+ else+ elevenTabVal/=8;++ if(sign)+ elevenTabVal=-elevenTabVal;++ //calculate sum+ int elevenbits = elevenbase+elevenTabVal;++ //clamp..+ if(elevenbits>=256*8)+ elevenbits=256*8-1;+ else if(elevenbits<0)+ elevenbits=0;+ //elevenbits now contains the 11 bit alpha value as defined in the spec.++ //extend to 16 bits before returning, since we don't have any good 11-bit file formats.+ uint16 sixteenbits = (elevenbits<<5)+(elevenbits>>6);++ return sixteenbits;+}++// Decompresses a block using one of the GL_COMPRESSED_R11_EAC or GL_COMPRESSED_SIGNED_R11_EAC-formats+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved.+void decompressBlockAlpha16bitC(uint8* data, uint8* img, int width, int height, int ix, int iy, int channels) +{+ int alpha = data[0];+ int table = data[1];++ if(formatSigned) + {+ //if we have a signed format, the base value is given as a signed byte. We convert it to (0-255) here,+ //so more code can be shared with the unsigned mode.+ alpha = *((signed char*)(&data[0]));+ alpha = alpha+128;+ }++ int bit=0;+ int byte=2;+ //extract an alpha value for each pixel.+ for(int x=0; x<4; x++) + {+ for(int y=0; y<4; y++) + {+ //Extract table index+ int index=0;+ for(int bitpos=0; bitpos<3; bitpos++) + {+ index|=getbit(data[byte],7-bit,2-bitpos);+ bit++;+ if(bit>7) + {+ bit=0;+ byte++;+ }+ }+ int windex = channels*(2*(ix+x+(iy+y)*width));+#if !PGMOUT+ if(formatSigned)+ {+ *(int16 *)&img[windex] = get16bits11signed(alpha,(table%16),(table/16),index);+ }+ else+ {+ *(uint16 *)&img[windex] = get16bits11bits(alpha,(table%16),(table/16),index);+ }+#else+ //make data compatible with the .pgm format. See the comment in compressBlockAlpha16() for details.+ uint16 uSixteen;+ if (formatSigned)+ {+ //the pgm-format only allows unsigned images,+ //so we add 2^15 to get a 16-bit value.+ uSixteen = get16bits11signed(alpha,(table%16),(table/16),index) + 256*128;+ }+ else+ {+ uSixteen = get16bits11bits(alpha,(table%16),(table/16),index);+ }+ //byte swap for pgm+ img[windex] = uSixteen/256;+ img[windex+1] = uSixteen%256;+#endif++ }+ } +}++void decompressBlockAlpha16bit(uint8* data, uint8* img, int width, int height, int ix, int iy)+{+ decompressBlockAlpha16bitC(data, img, width, height, ix, iy, 1);+}
+ KTX/lib/etcunpack.cxx view
@@ -0,0 +1,296 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: d555f6fdc46c28e4db334b44fdb8ac5b4bcef91a $ */++/* @internal+ * @~English+ * @file+ *+ * Unpack a texture compressed with ETC1+ *+ * @author Mark Callow, HI Corporation.+ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++#include <assert.h>+#include <stdlib.h>+#include "ktx.h"+#include "ktxint.h"++#if SUPPORT_SOFTWARE_ETC_UNPACK+typedef unsigned int uint;+typedef unsigned char uint8;++extern void decompressBlockETC2c(uint block_part1, uint block_part2, uint8* img,+ int width, int height, int startx, int starty, int channels);+extern void decompressBlockETC21BitAlphaC(uint block_part1, uint block_part2, uint8* img, uint8* alphaimg,+ int width, int height, int startx, int starty, int channels);+extern void decompressBlockAlphaC(uint8* data, uint8* img,+ int width, int height, int startx, int starty, int channels);+extern void decompressBlockAlpha16bitC(uint8* data, uint8* img,+ int width, int height, int startx, int starty, int channels);++extern void setupAlphaTable();++// This global variable affects the behaviour of decompressBlockAlpha16bitC.+extern int formatSigned;++static void+readBigEndian4byteWord(khronos_uint32_t* pBlock, const GLubyte *s)+{+ *pBlock = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];+}+++/* Unpack an ETC1_RGB8_OES format compressed texture */+extern "C" KTX_error_code+_ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat,+ khronos_uint32_t activeWidth, khronos_uint32_t activeHeight,+ GLubyte** dstImage,+ GLenum* format, GLenum* internalFormat, GLenum* type,+ GLint R16Formats, GLboolean supportsSRGB)+{+ unsigned int width, height;+ unsigned int block_part1, block_part2;+ unsigned int x, y;+ /*const*/ GLubyte* src = (GLubyte*)srcETC;+ // AF_11BIT is used to compress R11 & RG11 though its not alpha data.+ enum {AF_NONE, AF_1BIT, AF_8BIT, AF_11BIT} alphaFormat = AF_NONE;+ int dstChannels, dstChannelBytes;++ switch (srcFormat) {+ case GL_COMPRESSED_SIGNED_R11_EAC:+ if (R16Formats & _KTX_R16_FORMATS_SNORM) {+ dstChannelBytes = sizeof(GLshort);+ dstChannels = 1;+ formatSigned = GL_TRUE;+ *internalFormat = GL_R16_SNORM;+ *format = GL_RED;+ *type = GL_SHORT;+ alphaFormat = AF_11BIT;+ } else+ return KTX_UNSUPPORTED_TEXTURE_TYPE; + break;++ case GL_COMPRESSED_R11_EAC:+ if (R16Formats & _KTX_R16_FORMATS_NORM) {+ dstChannelBytes = sizeof(GLshort);+ dstChannels = 1;+ formatSigned = GL_FALSE;+ *internalFormat = GL_R16;+ *format = GL_RED;+ *type = GL_UNSIGNED_SHORT;+ alphaFormat = AF_11BIT;+ } else+ return KTX_UNSUPPORTED_TEXTURE_TYPE; + break;++ case GL_COMPRESSED_SIGNED_RG11_EAC:+ if (R16Formats & _KTX_R16_FORMATS_SNORM) {+ dstChannelBytes = sizeof(GLshort);+ dstChannels = 2;+ formatSigned = GL_TRUE;+ *internalFormat = GL_RG16_SNORM;+ *format = GL_RG;+ *type = GL_SHORT;+ alphaFormat = AF_11BIT;+ } else+ return KTX_UNSUPPORTED_TEXTURE_TYPE; + break;++ case GL_COMPRESSED_RG11_EAC:+ if (R16Formats & _KTX_R16_FORMATS_NORM) {+ dstChannelBytes = sizeof(GLshort);+ dstChannels = 2;+ formatSigned = GL_FALSE;+ *internalFormat = GL_RG16;+ *format = GL_RG;+ *type = GL_UNSIGNED_SHORT;+ alphaFormat = AF_11BIT;+ } else+ return KTX_UNSUPPORTED_TEXTURE_TYPE; + break;++ case GL_ETC1_RGB8_OES:+ case GL_COMPRESSED_RGB8_ETC2:+ dstChannelBytes = sizeof(GLubyte);+ dstChannels = 3;+ *internalFormat = GL_RGB8;+ *format = GL_RGB;+ *type = GL_UNSIGNED_BYTE;+ break;++ case GL_COMPRESSED_RGBA8_ETC2_EAC:+ dstChannelBytes = sizeof(GLubyte);+ dstChannels = 4;+ *internalFormat = GL_RGBA8;+ *format = GL_RGBA;+ *type = GL_UNSIGNED_BYTE;+ alphaFormat = AF_8BIT;+ break;++ case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:+ dstChannelBytes = sizeof(GLubyte);+ dstChannels = 4;+ *internalFormat = GL_RGBA8;+ *format = GL_RGBA;+ *type = GL_UNSIGNED_BYTE;+ alphaFormat = AF_1BIT;+ break;++ case GL_COMPRESSED_SRGB8_ETC2:+ if (supportsSRGB) {+ dstChannelBytes = sizeof(GLubyte);+ dstChannels = 3;+ *internalFormat = GL_SRGB8;+ *format = GL_RGB;+ *type = GL_UNSIGNED_BYTE;+ } else+ return KTX_UNSUPPORTED_TEXTURE_TYPE; + break;++ case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:+ if (supportsSRGB) {+ dstChannelBytes = sizeof(GLubyte);+ dstChannels = 4;+ *internalFormat = GL_SRGB8_ALPHA8;+ *format = GL_RGBA;+ *type = GL_UNSIGNED_BYTE;+ alphaFormat = AF_8BIT;+ } else+ return KTX_UNSUPPORTED_TEXTURE_TYPE; + break;++ case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:+ if (supportsSRGB) {+ dstChannelBytes = sizeof(GLubyte);+ dstChannels = 4;+ *internalFormat = GL_SRGB8_ALPHA8;+ *format = GL_RGBA;+ *type = GL_UNSIGNED_BYTE;+ alphaFormat = AF_1BIT;+ } else+ return KTX_UNSUPPORTED_TEXTURE_TYPE; + break;++ default:+ assert(0); // Upper levels should be passing only one of the above srcFormats.+ }++ /* active_{width,height} show how many pixels contain active data,+ * (the rest are just for making sure we have a 2*a x 4*b size).+ */++ /* Compute the full width & height. */+ width = ((activeWidth+3)/4)*4;+ height = ((activeHeight+3)/4)*4;++ /* printf("Width = %d, Height = %d\n", width, height); */+ /* printf("active pixel area: top left %d x %d area.\n", activeWidth, activeHeight); */++ *dstImage = (GLubyte*)malloc(dstChannels*dstChannelBytes*width*height);+ if (!*dstImage) {+ return KTX_OUT_OF_MEMORY;+ }+ + if (alphaFormat != AF_NONE)+ setupAlphaTable();++ // NOTE: none of the decompress functions actually use the <height> parameter+ if (alphaFormat == AF_11BIT) {+ // One or two 11-bit alpha channels for R or RG.+ for (y=0; y < height/4; y++) {+ for (x=0; x < width/4; x++) {+ decompressBlockAlpha16bitC(src, *dstImage, width, height, 4*x, 4*y, dstChannels);+ src += 8;+ if (srcFormat == GL_COMPRESSED_RG11_EAC || srcFormat == GL_COMPRESSED_SIGNED_RG11_EAC) {+ decompressBlockAlpha16bitC(src, *dstImage + dstChannelBytes, width, height, 4*x, 4*y, dstChannels);+ src += 8;+ }+ }+ }+ } else {+ for (y=0; y < height/4; y++) {+ for (x=0; x < width/4; x++) {+ // Decode alpha channel for RGBA+ if (alphaFormat == AF_8BIT) {+ decompressBlockAlphaC(src, *dstImage + 3, width, height, 4*x, 4*y, dstChannels);+ src += 8;+ }+ // Decode color dstChannels+ readBigEndian4byteWord(&block_part1, src);+ src += 4;+ readBigEndian4byteWord(&block_part2, src);+ src += 4;+ if (alphaFormat == AF_1BIT)+ decompressBlockETC21BitAlphaC(block_part1, block_part2, *dstImage, 0, width, height, 4*x, 4*y, dstChannels);+ else+ decompressBlockETC2c(block_part1, block_part2, *dstImage, width, height, 4*x, 4*y, dstChannels);+ }+ }+ }++ /* Ok, now write out the active pixels to the destination image.+ * (But only if the active pixels differ from the total pixels)+ */++ if( !(height == activeHeight && width == activeWidth) ) {+ int dstPixelBytes = dstChannels * dstChannelBytes;+ int dstRowBytes = dstPixelBytes * width;+ int activeRowBytes = activeWidth * dstPixelBytes;+ GLubyte *newimg = (GLubyte*)malloc(dstPixelBytes * activeWidth * activeHeight);+ unsigned int xx, yy;+ int zz;++ if (!newimg) {+ free(*dstImage);+ return KTX_OUT_OF_MEMORY;+ }+ + /* Convert from total area to active area: */++ for (yy = 0; yy < activeHeight; yy++) {+ for (xx = 0; xx < activeWidth; xx++) {+ for (zz = 0; zz < dstPixelBytes; zz++) {+ newimg[ yy*activeRowBytes + xx*dstPixelBytes + zz ] = (*dstImage)[ yy*dstRowBytes + xx*dstPixelBytes + zz];+ }+ }+ }++ free(*dstImage);+ *dstImage = newimg;+ }++ return KTX_SUCCESS;+}++#endif /* SUPPORT_SOFTWARE_ETC_UNPACK */
+ KTX/lib/gl_funcptrs.h view
@@ -0,0 +1,59 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 75ba91467bd9953cfa4bd4000f40e7ea6bf90d85 $ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/*+ * Author: Mark Callow based on code from Georg Kolling+ */++#ifndef _GL_FUNCPTRS_H_+#define _GL_FUNCPTRS_H_++#ifdef __cplusplus+extern "C" {+#endif++#define DECLARE_GL_FUNCPTRS++/* remove this if you use GLEW and already have this */+extern int GLEW_OES_compressed_ETC1_RGB8_texture;++/* and make this macro empty */+#define DECLARE_GL_EXTGLOBALS \+ int GLEW_OES_compressed_ETC1_RGB8_texture = 0;++#ifdef __cplusplus+}+#endif++#endif /* GL_FUNCPTRS */
+ KTX/lib/gles1_funcptrs.h view
@@ -0,0 +1,79 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 813736feacba1142549e915a1a8cfe27d2deafc4 $ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/*+ * Author: Mark Callow based on code from Georg Kolling+ */++#ifndef _GLES1_FUNCPTRS_H_+#define _GLES1_FUNCPTRS_H_++#ifdef __cplusplus+extern "C" {+#endif++/* remove these where already defined as typedefs (GCC 4 complains of duplicate definitions) */+typedef void (GL_APIENTRY* PFNGLTEXIMAGE1DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);+typedef void (GL_APIENTRY* PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);+typedef void (GL_APIENTRY* PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);+typedef void (GL_APIENTRY* PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);+typedef void (GL_APIENTRY* PFNGLGENERATEMIPMAPPROC) (GLenum target);++/* remove these where already defined as functions */+extern PFNGLTEXIMAGE1DPROC glTexImage1D;+extern PFNGLTEXIMAGE3DPROC glTexImage3D;+extern PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D;+extern PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D;+extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;++/* and these */+#define DECLARE_GL_FUNCPTRS \+ PFNGLTEXIMAGE1DPROC glTexImage1D = 0; \+ PFNGLTEXIMAGE3DPROC glTexImage3D = 0; \+ PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D = 0; \+ PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D = 0; \+ PFNGLGENERATEMIPMAPPROC glGenerateMipmap = 0;++/* remove this if you use GLEW and already have this */+extern int GLEW_OES_compressed_ETC1_RGB8_texture;++/* and make this macro empty */+#define DECLARE_GL_EXTGLOBALS \+ int GLEW_OES_compressed_ETC1_RGB8_texture = 0;++#ifdef __cplusplus+}+#endif++#endif /* GLES1_FUNCPTRS */
+ KTX/lib/gles2_funcptrs.h view
@@ -0,0 +1,76 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 533eabaad64677e05ae09588f4279d46a32d776c $ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/*+ * Author: Mark Callow based on code from Georg Kolling+ */++#ifndef _GLES2_FUNCPTRS_H_+#define _GLES2_FUNCPTRS_H_++#ifdef __cplusplus+extern "C" {+#endif++/* remove these where already defined as typedefs (GCC 4 complains of duplicate definitions) */+typedef void (GL_APIENTRY* PFNGLTEXIMAGE1DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);+typedef void (GL_APIENTRY* PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);+typedef void (GL_APIENTRY* PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);+typedef void (GL_APIENTRY* PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);++/* remove these where already defined as functions */+extern PFNGLTEXIMAGE1DPROC glTexImage1D;+extern PFNGLTEXIMAGE3DPROC glTexImage3D;+extern PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D;+extern PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D;++/* and these */+#define DECLARE_GL_FUNCPTRS \+ PFNGLTEXIMAGE1DPROC glTexImage1D = 0; \+ PFNGLTEXIMAGE3DPROC glTexImage3D = 0; \+ PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D = 0; \+ PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D = 0;++/* remove this if you use GLEW and already have this */+extern int GLEW_OES_compressed_ETC1_RGB8_texture;++/* and make this macro empty */+#define DECLARE_GL_EXTGLOBALS \+ int GLEW_OES_compressed_ETC1_RGB8_texture = 0;++#ifdef __cplusplus+}+#endif++#endif /* GLES2_FUNCPTRS */
+ KTX/lib/gles3_funcptrs.h view
@@ -0,0 +1,70 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 5e1de2ac1d62a6fa0112f5dca750ae1bd2aab126 $ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/*+ * Author: Mark Callow based on code from Georg Kolling+ */++#ifndef _GLES3_FUNCPTRS_H_+#define _GLES3_FUNCPTRS_H_++#ifdef __cplusplus+extern "C" {+#endif++/* remove these where already defined as typedefs (GCC 4 complains of duplicate definitions) */+typedef void (GL_APIENTRY* PFNGLTEXIMAGE1DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);+typedef void (GL_APIENTRY* PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);++/* remove these where already defined as functions */+extern PFNGLTEXIMAGE1DPROC glTexImage1D;+extern PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D;++/* and these */+#define DECLARE_GL_FUNCPTRS \+ PFNGLTEXIMAGE1DPROC glTexImage1D = 0; \+ PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D = 0;++/* remove this if you use GLEW and already have this */+extern int GLEW_OES_compressed_ETC1_RGB8_texture;++/* and make this macro empty */+#define DECLARE_GL_EXTGLOBALS \+ int GLEW_OES_compressed_ETC1_RGB8_texture = 0;++#ifdef __cplusplus+}+#endif++#endif /* GLES3_FUNCPTRS */
+ KTX/lib/hashtable.c view
@@ -0,0 +1,324 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 38d57d885272a48bc32e906349cc6b610c1453c0 $ */++/**+ * @file hashtable.c+ * @~English+ *+ * @brief Functions for creating and using a hash table of key-value+ * pairs.+ *+ * @author Mark Callow, HI Corporation+ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group".++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++#include <stdio.h>+#include <stdlib.h>+#include <assert.h>++#include "uthash.h"++#include "ktx.h"+#include "ktxint.h"+++/**+ * @internal+ * @struct _keyAndValue+ * @brief Hash table entry structure+ */+typedef struct _keyAndValue {+ unsigned int keyLen; /*!< Length of the key */+ char* key; /*!< Pointer to key string */+ unsigned int valueLen; /*!< Length of the value */+ void* value; /*!< Pointer to the value */+ UT_hash_handle hh; /*!< handle used by UT hash */+} key_and_value_t;+/**+ * @internal+ * @typedef key_and_value_t+ * @brief type of a hash table entry.+ */++/**+ * @~English+ * @brief Create an empty hash table for storying key-value pairs.+ *+ * @return pointer to the newly created hash table or NULL if there+ * is not enough memory.+ *+ *+ */+KTX_hash_table+ktxHashTable_Create()+{+ key_and_value_t** kvt = (key_and_value_t**)malloc(sizeof (key_and_value_t**));+ *kvt = NULL;+ return (KTX_hash_table)kvt;+}+++/**+ * @~English+ * @brief Destroy a hash table.+ *+ * All memory associated with the hash table and its keys and values+ * is freed.+ *+ * @param [in] This pointer to the hash table to be destroyed.+ */+ /*+ * @memberof ktxHashTable @public+ */+void+ktxHashTable_Destroy(KTX_hash_table This)+{+ key_and_value_t* kv;++ for(kv = *(key_and_value_t**)This; kv != NULL;) {+ key_and_value_t* tmp = (key_and_value_t*)kv->hh.next;+ HASH_DELETE(hh, /*head*/*(key_and_value_t**)This, kv);+ free(kv);+ kv = tmp;+ }+ free(This);+}+++/**+ * @~English+ * @brief Adds a key value pair to a hash table+ *+ * @param [in] This pointer to the target hash table.+ * @param [in] key pointer to the UTF8 NUL-terminated string to be used as the key.+ * @param [in] valueLen the number of bytes of data in @p value.+ * @param [in] value pointer to the bytes of data constituting the value.+ *+ * @return KTX_SUCCESS or one of the following error codes.+ *+ * @exception KTX_INVALID_VALUE if @p This, @p key or @p value are NULL, @p key is an+ * empty string or @p valueLen == 0.+ */+/*+ * @memberof ktxHashTable @public+ */+KTX_error_code+ktxHashTable_AddKVPair(KTX_hash_table This, const char* key, unsigned int valueLen, const void* value)+{+ if (This && key && value && valueLen != 0) {+ int keyLen = strlen(key) + 1;+ /* key_and_value_t* head = *(key_and_value_t**)This; */+ key_and_value_t* kv;++ if (keyLen == 1)+ return KTX_INVALID_VALUE; /* Empty string */++ /* Allocate all the memory as a block */+ kv = (key_and_value_t*)malloc(sizeof(key_and_value_t) + keyLen + valueLen);+ /* Put key first */+ kv->key = (char *)kv + sizeof(key_and_value_t);+ kv->keyLen = keyLen;+ /* then value */+ kv->value = kv->key + keyLen;+ kv->valueLen = valueLen;+ memcpy(kv->key, key, keyLen);+ memcpy(kv->value, value, valueLen);++ HASH_ADD_KEYPTR( hh, /*head*/*(key_and_value_t**)This, kv->key, kv->keyLen-1, kv);+ return KTX_SUCCESS;+ } else+ return KTX_INVALID_VALUE;+}+++/**+ * @~English+ * @brief Looks up a key a hash table and returns the value.+ *+ * @param [in] This pointer to the target hash table.+ * @param [in] key pointer to a UTF8 NUL-terminated string to find.+ * @param [in,out] pValueLen @p *pValueLen is set to the number of bytes of+ * data in the returned value.+ * @param [in,out] ppValue @p *ppValue is set to the point to the value for+ * @p key.+ *+ * @return KTX_SUCCESS or one of the following error codes.+ *+ * @exception KTX_INVALID_VALUE if @p This, @p key or @p pValueLen or @p ppValue+ * is NULL.+ * @exception KTX_NOT_FOUND an entry matching @p key was not found.+ */+/*+ * @memberof ktxHashTable @public+ */+KTX_error_code+ktxHashTable_FindValue(KTX_hash_table This, const char* key, unsigned int* pValueLen, void** ppValue)+{+ if (This && key && pValueLen && ppValue) {+ key_and_value_t* kv;+ /* key_and_value_t* head = *(key_and_value_t**)This; */++ HASH_FIND_STR( /*head*/*(key_and_value_t**)This, key, kv ); /* kv: output pointer */++ if (kv) {+ *pValueLen = kv->valueLen;+ *ppValue = kv->value;+ return KTX_SUCCESS;+ } else+ return KTX_NOT_FOUND;+ } else+ return KTX_INVALID_VALUE;+}+++/**+ * @~English+ * @brief Serialize a hash table to a block of data suitable for writing+ * to a file.+ *+ * The caller is responsible for freeing the data block returned by this+ * function.+ *+ * @param [in] This pointer to the target hash table.+ * @param [in,out] pKvdLen @p *pKvdLen is set to the number of bytes of+ * data in the returned data block.+ * @param [in,out] ppKvd @p *ppKvd is set to the point to the block of+ * memory containing the serialized data.+ *+ * @return KTX_SUCCESS or one of the following error codes.+ *+ * @exception KTX_INVALID_VALUE if @p This, @p pKvdLen or @p ppKvd is NULL.+ * @exception KTX_OUT_OF_MEMORY there was not enough memory to serialize the data.+ */+ /* @memberof ktxHashTable @public+ */+KTX_error_code+ktxHashTable_Serialize(KTX_hash_table This, unsigned int* pKvdLen, unsigned char** ppKvd)+{++ if (This && pKvdLen && ppKvd) {+ key_and_value_t* kv;+ unsigned int bytesOfKeyValueData = 0;+ unsigned int keyValueLen;+ unsigned char* sd;+ char padding[4] = {0, 0, 0, 0};++ for (kv = *(key_and_value_t**)This; kv != NULL; kv = kv->hh.next) {+ /* sizeof(*sd) is to make space to write keyAndValueByteSize */+ keyValueLen = kv->keyLen + kv->valueLen + sizeof(khronos_uint32_t);+ /* Add valuePadding */+ keyValueLen += 3 - ((keyValueLen + 3) % 4);+ bytesOfKeyValueData += keyValueLen;+ }+ sd = malloc(bytesOfKeyValueData);+ if (!sd)+ return KTX_OUT_OF_MEMORY;++ *pKvdLen = bytesOfKeyValueData;+ *ppKvd = sd;++ for (kv = *(key_and_value_t **)This; kv != NULL; kv = kv->hh.next) {+ int padLen;++ keyValueLen = kv->keyLen + kv->valueLen;+ *(khronos_uint32_t*)sd = keyValueLen;+ sd += sizeof(khronos_uint32_t);+ memcpy(sd, kv->key, kv->keyLen);+ sd += kv->keyLen;+ memcpy(sd, kv->value, kv->valueLen);+ sd += kv->valueLen;+ padLen = 3 - ((keyValueLen + 3) % 4);+ memcpy(sd, padding, padLen);+ sd += padLen;+ }+ return KTX_SUCCESS;+ } else+ return KTX_INVALID_VALUE;+}+++/**+ * @~English+ * @brief Create a hash table from a block of serialized key-value+ * data read from a file.+ *+ * The caller is responsible for freeing the returned hash table.+ *+ * @param [in] kvdLen the length of the serialized key-value data.+ * @param [in] pKvd pointer to the serialized key-value data.+ * @param [in,out] pHt @p *pHt is set to point to the created hash+ * table.+ *+ * @return KTX_SUCCESS or one of the following error codes.+ *+ * @exception KTX_INVALID_VALUE if @p pKvd or @p pHt is NULL or kvdLen == 0.+ * @exception KTX_OUT_OF_MEMORY there was not enough memory to create the hash+ * table.+ */+ /* @memberof ktxHashTable @public+ */+KTX_error_code+ktxHashTable_Deserialize(unsigned int kvdLen, void* pKvd, KTX_hash_table* pHt)+{+ KTX_hash_table kvt;+ char* src = pKvd;++ if (kvdLen == 0 || pKvd == NULL || pHt == NULL)+ return KTX_INVALID_VALUE;++ kvt = ktxHashTable_Create();+ if (kvt == NULL)+ return KTX_OUT_OF_MEMORY;++ while (src < (char *)pKvd + kvdLen) {+ char* key;+ int keyLen;+ void* value;+ khronos_uint32_t keyAndValueByteSize = *((khronos_uint32_t*)src);++ src += sizeof(keyAndValueByteSize);+ key = src;+ keyLen = strlen(key) + 1;+ value = key + keyLen;++ ktxHashTable_AddKVPair(kvt, key, keyAndValueByteSize - keyLen, value);+ /* Round keyAndValueByteSize */+ keyAndValueByteSize = (keyAndValueByteSize + 3) & ~(khronos_uint32_t)3;+ src += keyAndValueByteSize;+ }++ *pHt = kvt;+ return KTX_SUCCESS;+}++
+ KTX/lib/ktxfilestream.c view
@@ -0,0 +1,154 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/**+ * @file+ * @~English+ *+ * @brief FImplementation of ktxStream for FILE.+ *+ * @author Maksim Kolesin, Under Development+ * @author Georg Kolling, Imagination Technology+ * @author Mark Callow, HI Corporation+ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group".++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++#include <string.h>+#include <stdlib.h>++#include "KHR/khrplatform.h"+#include "ktx.h"+#include "ktxint.h"+#include "ktxfilestream.h"++/**+ * @internal+ * @~English+ * @brief Read bytes from a ktxFileStream.+ *+ * @param [out] dst pointer to a block of memory with a size+ of at least @p size bytes, converted to a void*.+ * @param [in] size total size of bytes to be read.+ * @param [in] src pointer to a FILE object, converted to a void*, that specifies an input stream.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p dst is @c NULL or @p src is @c NULL.+ * @exception KTX_UNEXPECTED_END_OF_FILE the file does not contain the expected amount of data.+ */+static+KTX_error_code ktxFileStream_read(void* dst, const GLsizei size, void* src)+{+ if (!dst || !src)+ return KTX_INVALID_VALUE;++ if (fread(dst, size, 1, (FILE*)src) != 1)+ return KTX_UNEXPECTED_END_OF_FILE;++ return KTX_SUCCESS;+}++/**+ * @internal+ * @~English+ * @brief Skip bytes in a ktxFileStream.+ *+ * @param [in] count number of bytes to be skipped.+ * @param [in] src pointer to a FILE object, converted to a void*, that specifies an input stream.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p dst is @c NULL or @p count is less than zero.+ * @exception KTX_UNEXPECTED_END_OF_FILE the file does not contain the expected amount of data.+ */+static+KTX_error_code ktxFileStream_skip(const GLsizei count, void* src)+{+ if (!src || (count < 0))+ return KTX_INVALID_VALUE;++ if (fseek((FILE*)src, count, SEEK_CUR) != 0)+ return KTX_UNEXPECTED_END_OF_FILE;++ return KTX_SUCCESS;+}++/**+ * @internal+ * @~English+ * @brief Write bytes to a ktxFileStream.+ *+ * @param [in] src pointer to the array of elements to be written, converted to a const void*.+ * @param [in] size size in bytes of each element to be written.+ * @param [in] count number of elements, each one with a @p size of size bytes.+ * @param [out] dst pointer to a FILE object, converted to a void*, that specifies an output stream.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p dst is @c NULL or @p src is @c NULL.+ * @exception KTX_FILE_WRITE_ERROR a system error occurred while writing the file.+ */+static+KTX_error_code ktxFileStream_write(const void *src, const GLsizei size, const GLsizei count, void* dst)+{+ if (!dst || !src)+ return KTX_INVALID_VALUE;++ if (fwrite(src, size, count, (FILE*)dst) != count)+ return KTX_FILE_WRITE_ERROR;++ return KTX_SUCCESS;+}++/**+ * @internal+ * @~English+ * @brief Initializes a ktxFileStream.+ *+ * @param [in] stream+ * @param [in] file+ *+ * @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error.+ *+ * @exception KTX_INVALID_VALUE @p stream is @c NULL or @p file is @c NULL.+ */+KTX_error_code ktxFileInit(struct ktxStream* stream, FILE* file)+{+ if (!stream || !file)+ return KTX_INVALID_VALUE;++ stream->src = (void*)file;+ stream->read = ktxFileStream_read;+ stream->skip = ktxFileStream_skip;+ stream->write = ktxFileStream_write;++ return KTX_SUCCESS;+}
+ KTX/lib/ktxfilestream.h view
@@ -0,0 +1,51 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group".++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/*+ * Author: Maksim Kolesin from original code+ * by Mark Callow and Georg Kolling+ */++#ifndef _KTXFILESTREAM_H_+#define _KTXFILESTREAM_H_++#include "KHR/khrplatform.h"+#include "ktx.h"+#include "ktxint.h"+#include "ktxstream.h"++/*+ * ktxFileInit: Initialize a ktxStream to a ktxFileStream with a FILE object+ */+KTX_error_code ktxFileInit(struct ktxStream* stream, FILE* file);++#endif /* _KTXFILESTREAM_H_ */
+ KTX/lib/ktxint.h view
@@ -0,0 +1,327 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: a694f52e03818dfba0de386459aa63031b23d3ea $ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/* + * Author: Mark Callow from original code by Georg Kolling+ */++#ifndef _KTXINT_H_+#define _KTXINT_H_++/* Define this to include the ETC unpack software in the library. */+#ifndef SUPPORT_SOFTWARE_ETC_UNPACK+ /* Include for all GL versions because have seen OpenGL ES 3+ * implementaions that do not support ETC1 (ARM Mali emulator v1.0)!+ */+ #define SUPPORT_SOFTWARE_ETC_UNPACK 1+#endif++#ifndef SUPPORT_LEGACY_FORMAT_CONVERSION+ #if KTX_OPENGL+ #define SUPPORT_LEGACY_FORMAT_CONVERSION 1+ #elif KTX_OPENGL_ES1+ /* ES1, ES2 & ES3 support the legacy formats */+ #define SUPPORT_LEGACY_FORMAT_CONVERSION 0+ #endif+#endif++#ifdef __cplusplus+extern "C" {+#endif+++#define KTX_IDENTIFIER_REF { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }+#define KTX_ENDIAN_REF (0x04030201)+#define KTX_ENDIAN_REF_REV (0x01020304)+#define KTX_HEADER_SIZE (64)++/**+ * @internal+ * @brief KTX file header+ *+ * See the KTX specification for descriptions+ * + */+typedef struct KTX_header_t {+ khronos_uint8_t identifier[12];+ khronos_uint32_t endianness;+ khronos_uint32_t glType;+ khronos_uint32_t glTypeSize;+ khronos_uint32_t glFormat;+ khronos_uint32_t glInternalFormat;+ khronos_uint32_t glBaseInternalFormat;+ khronos_uint32_t pixelWidth;+ khronos_uint32_t pixelHeight;+ khronos_uint32_t pixelDepth;+ khronos_uint32_t numberOfArrayElements;+ khronos_uint32_t numberOfFaces;+ khronos_uint32_t numberOfMipmapLevels;+ khronos_uint32_t bytesOfKeyValueData;+} KTX_header;++/* This will cause compilation to fail if the struct size doesn't match */+typedef int KTX_header_SIZE_ASSERT [sizeof(KTX_header) == KTX_HEADER_SIZE];++/**+ * @internal+ * @brief _ktxCheckHeader returns texture information in this structure+ *+ * TO DO: document properly+ */+typedef struct KTX_texinfo_t {+ /* Data filled in by _ktxCheckHeader() */+ khronos_uint32_t textureDimensions;+ khronos_uint32_t glTarget;+ khronos_uint32_t compressed;+ khronos_uint32_t generateMipmaps;+} KTX_texinfo;++/**+ * @internal+ * @brief used to pass GL context capabilites to subroutines.+ */+#define _KTX_NO_R16_FORMATS 0x0+#define _KTX_R16_FORMATS_NORM 0x1+#define _KTX_R16_FORMATS_SNORM 0x2+#define _KTX_ALL_R16_FORMATS (_KTX_R16_FORMATS_NORM | _KTX_R16_FORMATS_SNORM)+extern GLint _ktxR16Formats;+extern GLboolean _ktxSupportsSRGB;+++/*+ * These defines are needed to compile the KTX library. When+ * these things are not available in the GL header in use at+ * compile time, the library provides its own support, handles+ * the expected run-time errors or just needs the token value.+ */+#ifndef GL_LUMINANCE+#define GL_ALPHA 0x1906+#define GL_LUMINANCE 0x1909+#define GL_LUMINANCE_ALPHA 0x190A+#endif+#ifndef GL_INTENSITY+#define GL_INTENSITY 0x8049+#endif+#if SUPPORT_LEGACY_FORMAT_CONVERSION+/* For loading legacy KTX files. */+#ifndef GL_LUMINANCE4+#define GL_ALPHA4 0x803B+#define GL_ALPHA8 0x803C+#define GL_ALPHA12 0x803D+#define GL_ALPHA16 0x803E+#define GL_LUMINANCE4 0x803F+#define GL_LUMINANCE8 0x8040+#define GL_LUMINANCE12 0x8041+#define GL_LUMINANCE16 0x8042+#define GL_LUMINANCE4_ALPHA4 0x8043+#define GL_LUMINANCE6_ALPHA2 0x8044+#define GL_LUMINANCE8_ALPHA8 0x8045+#define GL_LUMINANCE12_ALPHA4 0x8046+#define GL_LUMINANCE12_ALPHA12 0x8047+#define GL_LUMINANCE16_ALPHA16 0x8048+#endif+#ifndef GL_INTENSITY4+#define GL_INTENSITY4 0x804A+#define GL_INTENSITY8 0x804B+#define GL_INTENSITY12 0x804C+#define GL_INTENSITY16 0x804D+#endif+#ifndef GL_SLUMINANCE+#define GL_SLUMINANCE_ALPHA 0x8C44+#define GL_SLUMINANCE8_ALPHA8 0x8C45+#define GL_SLUMINANCE 0x8C46+#define GL_SLUMINANCE8 0x8C47+#endif+#endif /* SUPPORT_LEGACY_FORMAT_CONVERSION */+#ifndef GL_TEXTURE_1D+#define GL_TEXTURE_1D 0x0DE0+#endif+#ifndef GL_TEXTURE_3D+#define GL_TEXTURE_3D 0x806F+#endif+#ifndef GL_TEXTURE_CUBE_MAP+#define GL_TEXTURE_CUBE_MAP 0x8513+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515+#endif+/* from GL_EXT_texture_array */+#ifndef GL_TEXTURE_1D_ARRAY_EXT+#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18+#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A+#endif+#ifndef GL_GENERATE_MIPMAP+#define GL_GENERATE_MIPMAP 0x8191+#endif++/* For writer.c */+#if !defined(GL_BGR)+#define GL_BGR 0x80E0+#define GL_BGRA 0x80E1+#endif+#if !defined(GL_RED_INTEGER)+#define GL_RED_INTEGER 0x8D94+#define GL_RGB_INTEGER 0x8D98+#define GL_RGBA_INTEGER 0x8D99+#endif+#if !defined(GL_GREEN_INTEGER)+#define GL_GREEN_INTEGER 0x8D95+#define GL_BLUE_INTEGER 0x8D96+#define GL_ALPHA_INTEGER 0x8D97+#endif+#if !defined (GL_BGR_INTEGER)+#define GL_BGR_INTEGER 0x8D9A+#define GL_BGRA_INTEGER 0x8D9B+#endif+#if !defined(GL_INT)+#define GL_INT 0x1404+#define GL_UNSIGNED_INT 0x1405+#endif+#if !defined(GL_HALF_FLOAT)+typedef unsigned short GLhalf;+#define GL_HALF_FLOAT 0x140B+#endif+#if !defined(GL_UNSIGNED_BYTE_3_3_2)+#define GL_UNSIGNED_BYTE_3_3_2 0x8032+#define GL_UNSIGNED_INT_8_8_8_8 0x8035+#define GL_UNSIGNED_INT_10_10_10_2 0x8036+#endif+#if !defined(GL_UNSIGNED_BYTE_2_3_3_REV)+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362+#define GL_UNSIGNED_SHORT_5_6_5 0x8363+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368+#endif+#if !defined(GL_UNSIGNED_INT_24_8)+#define GL_DEPTH_STENCIL 0x84F9+#define GL_UNSIGNED_INT_24_8 0x84FA+#endif+#if !defined(GL_UNSIGNED_INT_5_9_9_9_REV)+#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E+#endif+#if !defined(GL_UNSIGNED_INT_10F_11F_11F_REV)+#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B+#endif+#if !defined (GL_FLOAT_32_UNSIGNED_INT_24_8_REV)+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD+#endif++#ifndef GL_ETC1_RGB8_OES+#define GL_ETC1_RGB8_OES 0x8D64+#endif++#if SUPPORT_SOFTWARE_ETC_UNPACK+#ifndef GL_COMPRESSED_R11_EAC+#define GL_COMPRESSED_R11_EAC 0x9270+#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271+#define GL_COMPRESSED_RG11_EAC 0x9272+#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273+#define GL_COMPRESSED_RGB8_ETC2 0x9274+#define GL_COMPRESSED_SRGB8_ETC2 0x9275+#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276+#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277+#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278+#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279+#endif+#ifndef GL_R16_SNORM+#define GL_R16_SNORM 0x8F98+#define GL_RG16_SNORM 0x8F99+#endif+#ifndef GL_RED+#define GL_RED 0x1903+#define GL_GREEN 0x1904+#define GL_BLUE 0x1905+#define GL_RG 0x8227+#define GL_RG_INTEGER 0x8228+#endif+#ifndef GL_R16+#define GL_R16 0x822A+#define GL_RG16 0x822C+#endif+#ifndef GL_RGB8+#define GL_RGB8 0x8051+#define GL_RGBA8 0x8058+#endif+#ifndef GL_SRGB8+#define GL_SRGB8 0x8C41+#define GL_SRGB8_ALPHA8 0x8C43+#endif+#endif++#ifndef GL_MAJOR_VERSION+#define GL_MAJOR_VERSION 0x821B+#define GL_MINOR_VERSION 0x821C+#endif++#ifndef GL_CONTEXT_PROFILE_MASK+#define GL_CONTEXT_PROFILE_MASK 0x9126+#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002+#endif++#ifndef MAX+#define MAX(x, y) (((x) > (y)) ? (x) : (y))+#endif++/* CheckHeader+ * + * Reads the KTX file header and performs some sanity checking on the values+ */+KTX_error_code _ktxCheckHeader(KTX_header* header, KTX_texinfo* texinfo);++/*+ * SwapEndian16: Swaps endianness in an array of 16-bit values+ */+void _ktxSwapEndian16(khronos_uint16_t* pData16, int count);++/*+ * SwapEndian32: Swaps endianness in an array of 32-bit values+ */+void _ktxSwapEndian32(khronos_uint32_t* pData32, int count);++/*+ * UncompressETC: uncompresses an ETC compressed texture image+ */+KTX_error_code _ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat,+ khronos_uint32_t active_width, khronos_uint32_t active_height,+ GLubyte** dstImage,+ GLenum* format, GLenum* internalFormat, GLenum* type,+ GLint R16Formats, GLboolean supportsSRGB);++#ifdef __cplusplus+}+#endif++#endif /* _KTXINT_H_ */
+ KTX/lib/ktxmemstream.c view
@@ -0,0 +1,225 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/**+ * @file+ * @~English+ *+ * @brief Implementation of ktxStream for memory.+ *+ * @author Maksim Kolesin, Under Development+ * @author Georg Kolling, Imagination Technology+ * @author Mark Callow, HI Corporation+ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group".++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++#include <string.h>+#include <stdlib.h>++#include "KHR/khrplatform.h"+#include "ktx.h"+#include "ktxint.h"+#include "ktxmemstream.h"++/**+ * @internal+ * @~English+ * @brief Expand a ktxMem to fit to a newsize.+ *+ * @param [in] mem pointer to ktxMem struct to expand.+ * @param [in] newsize minimum new size required.+ *+ * @return KTX_SUCCESS on success, KTX_OUT_OF_MEMORY on error.+ *+ * @exception KTX_OUT_OF_MEMORY System failed to allocate sufficient memory.+ */+static+KTX_error_code ktxMem_expand(struct ktxMem *mem, const GLsizei newsize)+{+ GLsizei new_alloc_size = mem->alloc_size;+ while (new_alloc_size < newsize)+ new_alloc_size <<= 1;++ if (new_alloc_size == mem->alloc_size)+ return KTX_SUCCESS;++ mem->bytes = (unsigned char*)realloc(mem->bytes, new_alloc_size);+ if(!mem->bytes)+ {+ mem->alloc_size = 0;+ mem->used_size = 0;+ return KTX_OUT_OF_MEMORY;+ }++ mem->alloc_size = new_alloc_size;+ return KTX_SUCCESS;+}++/**+ * @internal+ * @~English+ * @brief Read bytes from a ktxMemStream.+ *+ * @param [out] dst pointer to memory where to copy read bytes.+ * @param [in] count number of bytes to read.+ * @param [in] src pointer to ktxMem struct, converted to a void*, that specifies an input stream.+ *+ * @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error.+ *+ * @exception KTX_INVALID_VALUE @p dst is @c NULL or @p mem is @c NULL or not sufficient data is available in ktxMem.+ */+static+KTX_error_code ktxMemStream_read(void* dst, const GLsizei count, void* src)+{+ struct ktxMem* mem = (struct ktxMem*)src;++ if(!dst || !mem || (mem->pos + count > mem->used_size) || (mem->pos + count < mem->pos))+ return KTX_INVALID_VALUE;++ memcpy(dst, mem->bytes + mem->pos, count);+ mem->pos += count;++ return KTX_SUCCESS;+}++/**+ * @internal+ * @~English+ * @brief Skip bytes in a ktxFileStream.+ *+ * @param [in] count number of bytes to skip.+ * @param [in] src pointer to a ktxMem struct, converted to a void*, that specifies an input stream.+ *+ * @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error.+ *+ * @exception KTX_INVALID_VALUE @p mem is @c NULL or not sufficient data is available in ktxMem.+ */+static+KTX_error_code ktxMemStream_skip(const GLsizei count, void* src)+{+ struct ktxMem* mem = (struct ktxMem*)src;++ if(!mem || (mem->pos + count > mem->used_size) || (mem->pos + count < mem->pos))+ return KTX_INVALID_VALUE;++ mem->pos += count;++ return KTX_SUCCESS;+}++/**+ * @internal+ * @~English+ * @brief Write bytes to a ktxFileStream.+ *+ * @param [in] src pointer to the array of elements to be written, converted to a const void*.+ * @param [in] size size in bytes of each element to be written.+ * @param [in] count number of elements, each one with a @p size of size bytes.+ * @param [out] dst pointer to a ktxMem struct, converted to a void*, that specifies an output stream.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p dst is @c NULL or @p mem is @c NULL.+ * @exception KTX_OUT_OF_MEMORY See ktxMem_expand() for causes.+ */+static+KTX_error_code ktxMemStream_write(const void* src, const GLsizei size, const GLsizei count, void* dst)+{+ struct ktxMem* mem = (struct ktxMem*)dst;+ KTX_error_code rc = KTX_SUCCESS;++ if(!dst || !mem)+ return KTX_INVALID_VALUE;++ if(mem->alloc_size < mem->used_size + size*count)+ {+ rc = ktxMem_expand(mem, mem->used_size + size*count);+ if(rc != KTX_SUCCESS)+ return rc;+ }++ memcpy(mem->bytes + mem->used_size, src, size*count);+ mem->used_size += size*count;++ return KTX_SUCCESS;+}++/**+ * @brief Default allocation size for a ktxMemStream.+ */+#define KTX_MEM_DEFAULT_ALLOCATED_SIZE 256++/**+ * @internal+ * @~English+ * @brief Initialize a ktxMemStream.+ *+ * @param [in] stream pointer to a ktxStream struct to initialize.+ * @param [in] mem pointer to a ktxMem struct to use in ktxMemStream.+ * @param [in] bytes pointer to an array of bytes to use as initial data.+ * @param [in] size size of array of initial data for ktxMemStream.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p stream is @c NULL or @p mem is @c NULL or @p size is less than 0.+ * @exception KTX_OUT_OF_MEMORY system failed to allocate sufficient memory.+ */+KTX_error_code ktxMemInit(struct ktxStream* stream, struct ktxMem* mem, const void* bytes, GLsizei size)+{+ if (!stream || !mem || size < 0)+ return KTX_INVALID_VALUE;++ if(!bytes)+ {+ if (size == 0)+ size = KTX_MEM_DEFAULT_ALLOCATED_SIZE;+ mem->bytes = (unsigned char*)malloc(size);+ if (!mem->bytes)+ return KTX_OUT_OF_MEMORY;+ mem->alloc_size = size;+ mem->used_size = 0;+ mem->pos = 0;+ }+ else+ {+ mem->bytes = (unsigned char*)bytes;+ mem->used_size = size;+ mem->alloc_size = size;+ mem->pos = 0;+ }++ stream->src = mem;+ stream->read = ktxMemStream_read;+ stream->skip = ktxMemStream_skip;+ stream->write = ktxMemStream_write;++ return KTX_SUCCESS;+}
+ KTX/lib/ktxmemstream.h view
@@ -0,0 +1,64 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group".++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/*+ * Author: Maksim Kolesin from original code+ * by Mark Callow and Georg Kolling+ */++#ifndef _KTXMEMSTREAM_H_+#define _KTXMEMSTREAM_H_++#include "KHR/khrplatform.h"+#include "ktx.h"+#include "ktxint.h"+#include "ktxstream.h"++/**+ * @internal+ * @brief Structure to store information+ * about data allocated for ktxMemStream+ */+struct ktxMem+{+ unsigned char* bytes;+ GLsizei alloc_size;+ GLsizei used_size;+ GLsizei pos;+};++/*+ * ktxMemInit: Initialize a ktxStream to a ktxMemStream with ktxMem struct and/or array of bytes+ */+KTX_error_code ktxMemInit(struct ktxStream* stream, struct ktxMem* mem, const void* bytes, GLsizei size);++#endif /* _KTXMEMSTREAM_H_ */
+ KTX/lib/ktxstream.h view
@@ -0,0 +1,84 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group".++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++/*+ * Author: Maksim Kolesin from original code+ * by Mark Callow and Georg Kolling+ */++#ifndef _KTXSTREAM_H_+#define _KTXSTREAM_H_++#include "ktx.h"++/* @private is not preventing the typedefs, structs and defines from+ * appearing in the Doxygen output even though EXTRACT_PRIVATE is NO+ * in the config file. To prevent these items appearing I have changed+ * the special comments to ordinary comments, and have set+ * HIDE_UNDOC_MEMBERS = YES in the Doxygen config file.+ *+ * Items declared "static" are omitted, as expected, due to EXTRACT_STATIC+ * being NO, so there is no need to convert those to ordinary comments.+ */+/*+ * @private+ * @~English+ * @brief type for a pointer to a stream reading function+ */+typedef KTX_error_code(*ktxStream_read)(void* dst, const GLsizei count, void* src);+/*+ * @private+ * @~English+ * @brief type for a pointer to a stream skipping function+ */+typedef KTX_error_code(*ktxStream_skip)(const GLsizei count, void* src);+/*+ * @private+ * @~English+ * @brief type for a pointer to a stream reading function+ */+typedef KTX_error_code(*ktxStream_write)(const void *src, const GLsizei size, const GLsizei count, void* dst);++/*+ * @private+ * @~English+ * @brief KTX stream interface+ */+struct ktxStream+{+ void* src; /**< pointer to the stream source */+ ktxStream_read read; /**< pointer to function for reading bytes */+ ktxStream_skip skip; /**< pointer to function for skipping bytes */+ ktxStream_write write; /**< pointer to function for writing bytes */+};++#endif /* _KTXSTREAM_H_ */
+ KTX/lib/loader.c view
@@ -0,0 +1,855 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 357385446ea454dcee3c9ce6d663723a3bcdc7b3 $ */++/**+ * @file+ * @~English+ *+ * @brief Functions for instantiating GL or GLES textures from KTX files.+ *+ * @author Georg Kolling, Imagination Technology+ * @author Mark Callow, HI Corporation+ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group".++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++#include <string.h>+#include <stdlib.h>++#include "KHR/khrplatform.h"+#include "ktx.h"+#include "ktxint.h"+#include "ktxstream.h"+#include "ktxfilestream.h"+#include "ktxmemstream.h"++#include KTX_GLFUNCPTRS++/* @private is not preventing the typedefs, structs and defines from+ * appearing in the Doxygen output even though EXTRACT_PRIVATE is NO+ * in the config file. To prevent these items appearing I have changed+ * the special comments to ordinary comments, and have set+ * HIDE_UNDOC_MEMBERS = YES in the Doxygen config file.+ *+ * Items declared "static" are omitted, as expected, due to EXTRACT_STATIC+ * being NO, so there is no need to convert those to ordinary comments.+ */+/*+ * @private+ * @~English+ * @brief additional contextProfile bit indicating an OpenGL ES context.+ *+ * This is the same value NVIDIA returns when using an OpenGL ES profile+ * of their desktop drivers. However it is not specified in any official+ * specification as OpenGL ES does not support the GL_CONTEXT_PROFILE_MASK+ * query.+ */+#define _CONTEXT_ES_PROFILE_BIT 0x4++/*+ * @private+ * @~English+ * @name Supported Sized Format Macros+ *+ * These macros describe values that may be used with the sizedFormats+ * variable.+ */+/**@{*/+#define _NON_LEGACY_FORMATS 0x1 /*< @private @internal non-legacy sized formats are supported. */+#define _LEGACY_FORMATS 0x2 /*< @private @internal legacy sized formats are supported. */+/*+ * @private+ * @~English+ * @brief all sized formats are supported+ */+#define _ALL_SIZED_FORMATS (_NON_LEGACY_FORMATS | _LEGACY_FORMATS)+#define _NO_SIZED_FORMATS 0 /*< @private @internal no sized formats are supported. */+/**@}*/++/**+ * @private+ * @~English+ * @brief indicates the profile of the current context.+ */+static GLint contextProfile = 0;+/**+ * @private+ * @~English+ * @brief indicates what sized texture formats are supported+ * by the current context.+ */+static GLint sizedFormats = _ALL_SIZED_FORMATS;+static GLboolean supportsSwizzle = GL_TRUE;+/**+ * @private+ * @~English+ * @brief indicates which R16 & RG16 formats are supported by the current context.+ */+static GLint R16Formats = _KTX_ALL_R16_FORMATS;+/**+ * @private+ * @~English+ * @brief indicates if the current context supports sRGB textures.+ */+static GLboolean supportsSRGB = GL_TRUE;++/**+ * @private+ * ~English+ * @brief workaround mismatch of glGetString declaration and standard string+ * function parameters.+ */+#define glGetString(x) (const char*)glGetString(x)++/**+ * @private+ * @~English+ * @brief Discover the capabilities of the current GL context.+ *+ * Queries the context and sets several the following internal variables indicating+ * the capabilities of the context:+ *+ * @li sizedFormats+ * @li supportsSwizzle+ * @li supportsSRGB+ * @li b16Formats+ *+ */+static void discoverContextCapabilities(void)+{+ GLint majorVersion = 1;+ GLint minorVersion = 0;++ if (strstr(glGetString(GL_VERSION), "GL ES") != NULL)+ contextProfile = _CONTEXT_ES_PROFILE_BIT;+ // MAJOR & MINOR only introduced in GL {,ES} 3.0+ glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);+ glGetIntegerv(GL_MINOR_VERSION, &minorVersion);+ if (glGetError() != GL_NO_ERROR) {+ // < v3.0; resort to the old-fashioned way.+ if (contextProfile & _CONTEXT_ES_PROFILE_BIT)+ sscanf(glGetString(GL_VERSION), "OpenGL ES %d.%d ", &majorVersion, &minorVersion);+ else+ sscanf(glGetString(GL_VERSION), "OpenGL %d.%d ", &majorVersion, &minorVersion);+ }+ if (contextProfile & _CONTEXT_ES_PROFILE_BIT) {+ if (majorVersion < 3) {+ supportsSwizzle = GL_FALSE;+ sizedFormats = _NO_SIZED_FORMATS;+ R16Formats = _KTX_NO_R16_FORMATS;+ supportsSRGB = GL_FALSE;+ } else {+ sizedFormats = _NON_LEGACY_FORMATS;+ }+ if (strstr(glGetString(GL_EXTENSIONS), "GL_OES_required_internalformat") != NULL) {+ sizedFormats |= _ALL_SIZED_FORMATS;+ }+ // There are no OES extensions for sRGB textures or R16 formats.+ } else {+ // PROFILE_MASK was introduced in OpenGL 3.2.+ // Profiles: CONTEXT_CORE_PROFILE_BIT 0x1, CONTEXT_COMPATIBILITY_PROFILE_BIT 0x2.+ glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &contextProfile);+ if (glGetError() == GL_NO_ERROR) {+ // >= 3.2+ if (majorVersion == 3 && minorVersion < 3)+ supportsSwizzle = GL_FALSE;+ if ((contextProfile & GL_CONTEXT_CORE_PROFILE_BIT))+ sizedFormats &= ~_LEGACY_FORMATS;+ } else {+ // < 3.2+ contextProfile = GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;+ supportsSwizzle = GL_FALSE;+ // sRGB textures introduced in 2.0+ if (majorVersion < 2 && strstr(glGetString(GL_EXTENSIONS), "GL_EXT_texture_sRGB") == NULL) {+ supportsSRGB = GL_FALSE;+ }+ // R{,G]16 introduced in 3.0; R{,G}16_SNORM introduced in 3.1.+ if (majorVersion == 3) {+ if (minorVersion == 0)+ R16Formats &= ~_KTX_R16_FORMATS_SNORM;+ } else if (strstr(glGetString(GL_EXTENSIONS), "GL_ARB_texture_rg") != NULL) {+ R16Formats &= ~_KTX_R16_FORMATS_SNORM;+ } else {+ R16Formats = _KTX_NO_R16_FORMATS;+ }+ }+ }+}++#if SUPPORT_LEGACY_FORMAT_CONVERSION+/**+ * @internal+ * @~English+ * @brief Convert deprecated legacy-format texture to modern format.+ *+ * The function sets the GL_TEXTURE_SWIZZLEs necessary to get the same+ * behavior as the legacy format.+ *+ * @param [in] target texture target on which the swizzle will+ * be set.+ * @param [in, out] pFormat pointer to variable holding the base format of the+ * texture. The new base format is written here.+ * @param [in, out] pInternalFormat pointer to variable holding the internalformat+ * of the texture. The new internalformat is+ * written here.+ * @return void unrecognized formats will be passed on to OpenGL. Any loading error+ * that arises will be handled in the usual way.+ */+static void convertFormat(GLenum target, GLenum* pFormat, GLenum* pInternalFormat) {+ switch (*pFormat) {+ case GL_ALPHA:+ {+ GLint swizzle[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};+ *pFormat = GL_RED;+ glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);+ switch (*pInternalFormat) {+ case GL_ALPHA:+ case GL_ALPHA4:+ case GL_ALPHA8:+ *pInternalFormat = GL_R8;+ break;+ case GL_ALPHA12:+ case GL_ALPHA16:+ *pInternalFormat = GL_R16;+ break;+ }+ }+ case GL_LUMINANCE:+ {+ GLint swizzle[] = {GL_RED, GL_RED, GL_RED, GL_ONE};+ *pFormat = GL_RED;+ glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);+ switch (*pInternalFormat) {+ case GL_LUMINANCE:+ case GL_LUMINANCE4:+ case GL_LUMINANCE8:+ *pInternalFormat = GL_R8;+ break;+ case GL_LUMINANCE12:+ case GL_LUMINANCE16:+ *pInternalFormat = GL_R16;+ break;+#if 0+ // XXX Must avoid setting TEXTURE_SWIZZLE in these cases+ // XXX Must manually swizzle.+ case GL_SLUMINANCE:+ case GL_SLUMINANCE8:+ *pInternalFormat = GL_SRGB8;+ break;+#endif+ }+ break;+ }+ case GL_LUMINANCE_ALPHA:+ {+ GLint swizzle[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};+ *pFormat = GL_RG;+ glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);+ switch (*pInternalFormat) {+ case GL_LUMINANCE_ALPHA:+ case GL_LUMINANCE4_ALPHA4:+ case GL_LUMINANCE6_ALPHA2:+ case GL_LUMINANCE8_ALPHA8:+ *pInternalFormat = GL_RG8;+ break;+ case GL_LUMINANCE12_ALPHA4:+ case GL_LUMINANCE12_ALPHA12:+ case GL_LUMINANCE16_ALPHA16:+ *pInternalFormat = GL_RG16;+ break;+#if 0+ // XXX Must avoid setting TEXTURE_SWIZZLE in these cases+ // XXX Must manually swizzle.+ case GL_SLUMINANCE_ALPHA:+ case GL_SLUMINANCE8_ALPHA8:+ *pInternalFormat = GL_SRGB8_ALPHA8;+ break;+#endif+ }+ break;+ }+ case GL_INTENSITY:+ {+ GLint swizzle[] = {GL_RED, GL_RED, GL_RED, GL_RED};+ *pFormat = GL_RED;+ glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);+ switch (*pInternalFormat) {+ case GL_INTENSITY:+ case GL_INTENSITY4:+ case GL_INTENSITY8:+ *pInternalFormat = GL_R8;+ break;+ case GL_INTENSITY12:+ case GL_INTENSITY16:+ *pInternalFormat = GL_R16;+ break;+ }+ break;+ }+ default:+ break;+ }+}+#endif /* SUPPORT_LEGACY_FORMAT_CONVERSION */+++/*+ * @~English+ * @brief Load a GL texture object from a ktxStream.+ *+ * This function will unpack compressed GL_ETC1_RGB8_OES and GL_ETC2_* format+ * textures in software when the format is not supported by the GL context,+ * provided the library has been compiled with SUPPORT_SOFTWARE_ETC_UNPACK+ * defined as 1.+ *+ * It will also convert textures with legacy formats to their modern equivalents+ * when the format is not supported by the GL context, provided that the library+ * has been compiled with SUPPORT_LEGACY_FORMAT_CONVERSION defined as 1.+ *+ * @param [in] stream pointer to the ktxStream from which to load.+ * @param [in,out] pTexture name of the GL texture to load. If NULL or if+ * <tt>*pTexture == 0</tt> the function will generate+ * a texture name. The function binds either the+ * generated name or the name given in @p *pTexture+ * to the texture target returned in @p *pTarget,+ * before loading the texture data. If @p pTexture+ * is not NULL and a name was generated, the generated+ * name will be returned in *pTexture.+ * @param [out] pTarget @p *pTarget is set to the texture target used. The+ * target is chosen based on the file contents.+ * @param [out] pDimensions If @p pDimensions is not NULL, the width, height and+ * depth of the texture's base level are returned in the+ * fields of the KTX_dimensions structure to which it points.+ * @param [out] pIsMipmapped+ * If @p pIsMipmapped is not NULL, @p *pIsMipmapped is set+ * to GL_TRUE if the KTX texture is mipmapped, GL_FALSE+ * otherwise.+ * @param [out] pGlerror @p *pGlerror is set to the value returned by+ * glGetError when this function returns the error+ * KTX_GL_ERROR. glerror can be NULL.+ * @param [in,out] pKvdLen If not NULL, @p *pKvdLen is set to the number of bytes+ * of key-value data pointed at by @p *ppKvd. Must not be+ * NULL, if @p ppKvd is not NULL.+ * @param [in,out] ppKvd If not NULL, @p *ppKvd is set to the point to a block of+ * memory containing key-value data read from the file.+ * The application is responsible for freeing the memory.+ *+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p target is @c NULL or the size of a mip+ * level is greater than the size of the+ * preceding level.+ * @exception KTX_INVALID_OPERATION @p ppKvd is not NULL but pKvdLen is NULL.+ * @exception KTX_UNEXPECTED_END_OF_FILE the file does not contain the+ * expected amount of data.+ * @exception KTX_OUT_OF_MEMORY Sufficient memory could not be allocated to store+ * the requested key-value data.+ * @exception KTX_GL_ERROR A GL error was raised by glBindTexture,+ * glGenTextures or gl*TexImage*. The GL error+ * will be returned in @p *glerror, if glerror+ * is not @c NULL.+ */+static+KTX_error_code+ktxLoadTextureS(struct ktxStream* stream, GLuint* pTexture, GLenum* pTarget,+ KTX_dimensions* pDimensions, GLboolean* pIsMipmapped,+ GLenum* pGlerror,+ unsigned int* pKvdLen, unsigned char** ppKvd)+{+ GLint previousUnpackAlignment;+ KTX_header header;+ KTX_texinfo texinfo;+ void* data = NULL;+ khronos_uint32_t dataSize = 0;+ GLuint texname;+ int texnameUser;+ khronos_uint32_t faceLodSize;+ khronos_uint32_t faceLodSizeRounded;+ khronos_uint32_t level;+ khronos_uint32_t face;+ GLenum glFormat, glInternalFormat;+ KTX_error_code errorCode = KTX_SUCCESS;+ GLenum errorTmp;++ if (pGlerror)+ *pGlerror = GL_NO_ERROR;++ if (ppKvd) {+ *ppKvd = NULL;+ }++ if (!stream || !stream->read || !stream->skip) {+ return KTX_INVALID_VALUE;+ }++ if (!pTarget) {+ return KTX_INVALID_VALUE;+ }++ errorCode = stream->read(&header, KTX_HEADER_SIZE, stream->src);+ if (errorCode != KTX_SUCCESS)+ return errorCode;++ errorCode = _ktxCheckHeader(&header, &texinfo);+ if (errorCode != KTX_SUCCESS)+ return errorCode;++ if (ppKvd) {+ if (pKvdLen == NULL)+ return KTX_INVALID_OPERATION;+ *pKvdLen = header.bytesOfKeyValueData;+ if (*pKvdLen) {+ *ppKvd = (unsigned char*)malloc(*pKvdLen);+ if (*ppKvd == NULL)+ return KTX_OUT_OF_MEMORY;+ errorCode = stream->read(*ppKvd, *pKvdLen, stream->src);+ if (errorCode != KTX_SUCCESS)+ {+ free(*ppKvd);+ *ppKvd = NULL;++ return errorCode;+ }+ }+ } else {+ /* skip key/value metadata */+ errorCode = stream->skip((long)header.bytesOfKeyValueData, stream->src);+ if (errorCode != KTX_SUCCESS) {+ return errorCode;+ }+ }++ if (contextProfile == 0)+ discoverContextCapabilities();++ /* KTX files require an unpack alignment of 4 */+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousUnpackAlignment);+ if (previousUnpackAlignment != KTX_GL_UNPACK_ALIGNMENT) {+ glPixelStorei(GL_UNPACK_ALIGNMENT, KTX_GL_UNPACK_ALIGNMENT);+ }++ texnameUser = pTexture && *pTexture;+ if (texnameUser) {+ texname = *pTexture;+ } else {+ glGenTextures(1, &texname);+ }+ glBindTexture(texinfo.glTarget, texname);++ // Prefer glGenerateMipmaps over GL_GENERATE_MIPMAP+ if (texinfo.generateMipmaps && (glGenerateMipmap == NULL)) {+ glTexParameteri(texinfo.glTarget, GL_GENERATE_MIPMAP, GL_TRUE);+ }++ if (texinfo.glTarget == GL_TEXTURE_CUBE_MAP) {+ texinfo.glTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;+ }++ glInternalFormat = header.glInternalFormat;+ glFormat = header.glFormat;+ if (!texinfo.compressed) {+#if SUPPORT_LEGACY_FORMAT_CONVERSION+ // If sized legacy formats are supported there is no need to convert.+ // If only unsized formats are supported, there is no point in converting+ // as the modern formats aren't supported either.+ if (sizedFormats == _NON_LEGACY_FORMATS && supportsSwizzle) {+ convertFormat(texinfo.glTarget, &glFormat, &glInternalFormat);+ errorTmp = glGetError();+ } else if (sizedFormats == _NO_SIZED_FORMATS)+ glInternalFormat = header.glBaseInternalFormat;+#else+ // When no sized formats are supported, or legacy sized formats are not+ // supported, must change internal format.+ if (sizedFormats == _NO_SIZED_FORMATS+ || (!(sizedFormats & _LEGACY_FORMATS) &&+ (header.glBaseInternalFormat == GL_ALPHA+ || header.glBaseInternalFormat == GL_LUMINANCE+ || header.glBaseInternalFormat == GL_LUMINANCE_ALPHA+ || header.glBaseInternalFormat == GL_INTENSITY))) {+ glInternalFormat = header.glBaseInternalFormat;+ }+#endif+ }++ for (level = 0; level < header.numberOfMipmapLevels; ++level)+ {+ GLsizei pixelWidth = MAX(1, header.pixelWidth >> level);+ GLsizei pixelHeight = MAX(1, header.pixelHeight >> level);+ GLsizei pixelDepth = MAX(1, header.pixelDepth >> level);++ errorCode = stream->read(&faceLodSize, sizeof(khronos_uint32_t), stream->src);+ if (errorCode != KTX_SUCCESS) {+ goto cleanup;+ }+ if (header.endianness == KTX_ENDIAN_REF_REV) {+ _ktxSwapEndian32(&faceLodSize, 1);+ }+ faceLodSizeRounded = (faceLodSize + 3) & ~(khronos_uint32_t)3;+ if (!data) {+ /* allocate memory sufficient for the first level */+ data = malloc(faceLodSizeRounded);+ if (!data) {+ errorCode = KTX_OUT_OF_MEMORY;+ goto cleanup;+ }+ dataSize = faceLodSizeRounded;+ }+ else if (dataSize < faceLodSizeRounded) {+ /* subsequent levels cannot be larger than the first level */+ errorCode = KTX_INVALID_VALUE;+ goto cleanup;+ }++ for (face = 0; face < header.numberOfFaces; ++face)+ {+ errorCode = stream->read(data, faceLodSizeRounded, stream->src);+ if (errorCode != KTX_SUCCESS) {+ goto cleanup;+ }++ /* Perform endianness conversion on texture data */+ if (header.endianness == KTX_ENDIAN_REF_REV && header.glTypeSize == 2) {+ _ktxSwapEndian16((khronos_uint16_t*)data, faceLodSize / 2);+ }+ else if (header.endianness == KTX_ENDIAN_REF_REV && header.glTypeSize == 4) {+ _ktxSwapEndian32((khronos_uint32_t*)data, faceLodSize / 4);+ }++ if (texinfo.textureDimensions == 1) {+ if (texinfo.compressed) {+ glCompressedTexImage1D(texinfo.glTarget + face, level,+ glInternalFormat, pixelWidth, 0,+ faceLodSize, data);+ } else {+ glTexImage1D(texinfo.glTarget + face, level,+ glInternalFormat, pixelWidth, 0,+ glFormat, header.glType, data);+ }+ } else if (texinfo.textureDimensions == 2) {+ if (header.numberOfArrayElements) {+ pixelHeight = header.numberOfArrayElements;+ }+ if (texinfo.compressed) {+ // It is simpler to just attempt to load the format, rather than divine which+ // formats are supported by the implementation. In the event of an error,+ // software unpacking can be attempted.+ glCompressedTexImage2D(texinfo.glTarget + face, level,+ glInternalFormat, pixelWidth, pixelHeight, 0,+ faceLodSize, data);+ } else {+ glTexImage2D(texinfo.glTarget + face, level,+ glInternalFormat, pixelWidth, pixelHeight, 0,+ glFormat, header.glType, data);+ }+ } else if (texinfo.textureDimensions == 3) {+ if (header.numberOfArrayElements) {+ pixelDepth = header.numberOfArrayElements;+ }+ if (texinfo.compressed) {+ glCompressedTexImage3D(texinfo.glTarget + face, level,+ glInternalFormat, pixelWidth, pixelHeight, pixelDepth, 0,+ faceLodSize, data);+ } else {+ glTexImage3D(texinfo.glTarget + face, level,+ glInternalFormat, pixelWidth, pixelHeight, pixelDepth, 0,+ glFormat, header.glType, data);+ }+ }++ errorTmp = glGetError();+#if SUPPORT_SOFTWARE_ETC_UNPACK+ // Renderion is returning INVALID_VALUE. Oops!!+ if ((errorTmp == GL_INVALID_ENUM || errorTmp == GL_INVALID_VALUE)+ && texinfo.compressed+ && texinfo.textureDimensions == 2+ && (glInternalFormat == GL_ETC1_RGB8_OES || (glInternalFormat >= GL_COMPRESSED_R11_EAC && glInternalFormat <= GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC)))+ {+ GLubyte* unpacked;+ GLenum format, internalFormat, type;++ errorCode = _ktxUnpackETC((GLubyte*)data, glInternalFormat, pixelWidth, pixelHeight,+ &unpacked, &format, &internalFormat, &type,+ R16Formats, supportsSRGB);+ if (errorCode != KTX_SUCCESS) {+ goto cleanup;+ }+ if (!sizedFormats & _NON_LEGACY_FORMATS) {+ if (internalFormat == GL_RGB8)+ internalFormat = GL_RGB;+ else if (internalFormat == GL_RGBA8)+ internalFormat = GL_RGBA;+ }+ glTexImage2D(texinfo.glTarget + face, level,+ internalFormat, pixelWidth, pixelHeight, 0,+ format, type, unpacked);++ free(unpacked);+ errorTmp = glGetError();+ }+#endif+ if (errorTmp != GL_NO_ERROR) {+ if (pGlerror)+ *pGlerror = errorTmp;+ errorCode = KTX_GL_ERROR;+ goto cleanup;+ }+ }+ }++cleanup:+ free(data);++ /* restore previous GL state */+ if (previousUnpackAlignment != KTX_GL_UNPACK_ALIGNMENT) {+ glPixelStorei(GL_UNPACK_ALIGNMENT, previousUnpackAlignment);+ }++ if (errorCode == KTX_SUCCESS)+ {+ if (texinfo.generateMipmaps && glGenerateMipmap) {+ glGenerateMipmap(texinfo.glTarget);+ }+ *pTarget = texinfo.glTarget;+ if (pTexture) {+ *pTexture = texname;+ }+ if (pDimensions) {+ pDimensions->width = header.pixelWidth;+ pDimensions->height = header.pixelHeight;+ pDimensions->depth = header.pixelDepth;+ }+ if (pIsMipmapped) {+ if (texinfo.generateMipmaps || header.numberOfMipmapLevels > 1)+ *pIsMipmapped = GL_TRUE;+ else+ *pIsMipmapped = GL_FALSE;+ }+ if (!texinfo.generateMipmaps) {+ glTexParameteri(texinfo.glTarget, GL_TEXTURE_MAX_LEVEL, header.numberOfMipmapLevels - 1);+ }+ } else {+ if (ppKvd && *ppKvd)+ {+ free(*ppKvd);+ *ppKvd = NULL;+ }++ if (!texnameUser) {+ glDeleteTextures(1, &texname);+ }+ }+ return errorCode;+}++/**+ * @~English+ * @brief Load a GL texture object from a stdio FILE stream.+ *+ * This function will unpack compressed GL_ETC1_RGB8_OES and GL_ETC2_* format+ * textures in software when the format is not supported by the GL context,+ * provided the library has been compiled with SUPPORT_SOFTWARE_ETC_UNPACK+ * defined as 1.+ *+ * It will also convert texture with legacy formats to their modern equivalents+ * when the format is not supported by the GL context, provided that the library+ * has been compiled with SUPPORT_LEGACY_FORMAT_CONVERSION defined as 1.+ *+ * @param [in] file pointer to the stdio FILE stream from which to+ * load.+ * @param [in,out] pTexture name of the GL texture to load. If NULL or if+ * <tt>*pTexture == 0</tt> the function will generate+ * a texture name. The function binds either the+ * generated name or the name given in @p *pTexture+ * to the texture target returned in @p *pTarget,+ * before loading the texture data. If @p pTexture+ * is not NULL and a name was generated, the generated+ * name will be returned in *pTexture.+ * @param [out] pTarget @p *pTarget is set to the texture target used. The+ * target is chosen based on the file contents.+ * @param [out] pDimensions If @p pDimensions is not NULL, the width, height and+ * depth of the texture's base level are returned in the+ * fields of the KTX_dimensions structure to which it points.+ * @param [out] pIsMipmapped+ * If @p pIsMipmapped is not NULL, @p *pIsMipmapped is set+ * to GL_TRUE if the KTX texture is mipmapped, GL_FALSE+ * otherwise.+ * @param [out] pGlerror @p *pGlerror is set to the value returned by+ * glGetError when this function returns the error+ * KTX_GL_ERROR. glerror can be NULL.+ * @param [in,out] pKvdLen If not NULL, @p *pKvdLen is set to the number of bytes+ * of key-value data pointed at by @p *ppKvd. Must not be+ * NULL, if @p ppKvd is not NULL.+ * @param [in,out] ppKvd If not NULL, @p *ppKvd is set to the point to a block of+ * memory containing key-value data read from the file.+ * The application is responsible for freeing the memory.+ *+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p target is @c NULL or the size of a mip+ * level is greater than the size of the+ * preceding level.+ * @exception KTX_INVALID_OPERATION @p ppKvd is not NULL but pKvdLen is NULL.+ * @exception KTX_UNEXPECTED_END_OF_FILE the file does not contain the+ * expected amount of data.+ * @exception KTX_OUT_OF_MEMORY Sufficient memory could not be allocated to store+ * the requested key-value data.+ * @exception KTX_GL_ERROR A GL error was raised by glBindTexture,+ * glGenTextures or gl*TexImage*. The GL error+ * will be returned in @p *glerror, if glerror+ * is not @c NULL.+ */+KTX_error_code+ktxLoadTextureF(FILE* file, GLuint* pTexture, GLenum* pTarget,+ KTX_dimensions* pDimensions, GLboolean* pIsMipmapped,+ GLenum* pGlerror,+ unsigned int* pKvdLen, unsigned char** ppKvd)+{+ struct ktxStream stream;+ KTX_error_code errorCode = KTX_SUCCESS;++ errorCode = ktxFileInit(&stream, file);+ if (errorCode != KTX_SUCCESS)+ return errorCode;++ return ktxLoadTextureS(&stream, pTexture, pTarget, pDimensions, pIsMipmapped, pGlerror, pKvdLen, ppKvd);+}++/**+ * @~English+ * @brief Load a GL texture object from a named file on disk.+ *+ * @param [in] filename pointer to a C string that contains the path of+ * the file to load.+ * @param [in,out] pTexture name of the GL texture to load. See+ * ktxLoadTextureF() for details.+ * @param [out] pTarget @p *pTarget is set to the texture target used. See+ * ktxLoadTextureF() for details.+ * @param [out] pDimensions @p the texture's base level width depth and height+ * are returned in structure to which this points.+ * See ktxLoadTextureF() for details.+ * @param [out] pIsMipmapped @p pIsMipMapped is set to indicate if the loaded+ * texture is mipmapped. See ktxLoadTextureF() for+ * details.+ * @param [out] pGlerror @p *pGlerror is set to the value returned by+ * glGetError when this function returns the error+ * KTX_GL_ERROR. glerror can be NULL.+ * @param [in,out] pKvdLen If not NULL, @p *pKvdLen is set to the number of bytes+ * of key-value data pointed at by @p *ppKvd. Must not be+ * NULL, if @p ppKvd is not NULL.+ * @param [in,out] ppKvd If not NULL, @p *ppKvd is set to the point to a block of+ * memory containing key-value data read from the file.+ * The application is responsible for freeing the memory.*+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_FILE_OPEN_FAILED The specified file could not be opened.+ * @exception KTX_INVALID_VALUE See ktxLoadTextureF() for causes.+ * @exception KTX_INVALID_OPERATION See ktxLoadTextureF() for causes.+ * @exception KTX_UNEXPECTED_END_OF_FILE See ktxLoadTextureF() for causes.+ *+ * @exception KTX_GL_ERROR See ktxLoadTextureF() for causes.+ */+KTX_error_code+ktxLoadTextureN(const char* const filename, GLuint* pTexture, GLenum* pTarget,+ KTX_dimensions* pDimensions, GLboolean* pIsMipmapped,+ GLenum* pGlerror,+ unsigned int* pKvdLen, unsigned char** ppKvd)+{+ KTX_error_code errorCode;+ FILE* file = fopen(filename, "rb");++ if (file) {+ errorCode = ktxLoadTextureF(file, pTexture, pTarget, pDimensions,+ pIsMipmapped, pGlerror, pKvdLen, ppKvd);+ fclose(file);+ } else+ errorCode = KTX_FILE_OPEN_FAILED;++ return errorCode;+}++/**+ * @~English+ * @brief Load a GL texture object from KTX formatted data in memory.+ *+ * @param [in] bytes pointer to the array of bytes containing+ * the KTX format data to load.+ * @param [in] size size of the memory array containing the+ * KTX format data.+ * @param [in,out] pTexture name of the GL texture to load. See+ * ktxLoadTextureF() for details.+ * @param [out] pTarget @p *pTarget is set to the texture target used. See+ * ktxLoadTextureF() for details.+ * @param [out] pDimensions @p the texture's base level width depth and height+ * are returned in structure to which this points.+ * See ktxLoadTextureF() for details.+ * @param [out] pIsMipmapped @p *pIsMipMapped is set to indicate if the loaded+ * texture is mipmapped. See ktxLoadTextureF() for+ * details.+ * @param [out] pGlerror @p *pGlerror is set to the value returned by+ * glGetError when this function returns the error+ * KTX_GL_ERROR. glerror can be NULL.+ * @param [in,out] pKvdLen If not NULL, @p *pKvdLen is set to the number of bytes+ * of key-value data pointed at by @p *ppKvd. Must not be+ * NULL, if @p ppKvd is not NULL.+ * @param [in,out] ppKvd If not NULL, @p *ppKvd is set to the point to a block of+ * memory containing key-value data read from the file.+ * The application is responsible for freeing the memory.*+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_FILE_OPEN_FAILED The specified memory could not be opened as a file.+ * @exception KTX_INVALID_VALUE See ktxLoadTextureF() for causes.+ * @exception KTX_INVALID_OPERATION See ktxLoadTextureF() for causes.+ * @exception KTX_UNEXPECTED_END_OF_FILE See ktxLoadTextureF() for causes.+ *+ * @exception KTX_GL_ERROR See ktxLoadTextureF() for causes.+ */+KTX_error_code+ktxLoadTextureM(const void* bytes, GLsizei size, GLuint* pTexture, GLenum* pTarget,+ KTX_dimensions* pDimensions, GLboolean* pIsMipmapped,+ GLenum* pGlerror,+ unsigned int* pKvdLen, unsigned char** ppKvd)+{+ struct ktxMem mem;+ struct ktxStream stream;+ KTX_error_code errorCode = KTX_SUCCESS;++ errorCode = ktxMemInit(&stream, &mem, bytes, size);+ if (errorCode != KTX_SUCCESS)+ return errorCode;++ return ktxLoadTextureS(&stream, pTexture, pTarget, pDimensions, pIsMipmapped, pGlerror, pKvdLen, ppKvd);+}++
+ KTX/lib/swap.c view
@@ -0,0 +1,65 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: 2319952fa702d4c9a8e3c02868541b1d7cff9aa0 $ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group."++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++#include "KHR/khrplatform.h"++/*+ * SwapEndian16: Swaps endianness in an array of 16-bit values+ */+void+_ktxSwapEndian16(khronos_uint16_t* pData16, int count)+{+ int i;+ for (i = 0; i < count; ++i)+ {+ khronos_uint16_t x = *pData16;+ *pData16++ = (x << 8) | (x >> 8);+ }+}++/*+ * SwapEndian32: Swaps endianness in an array of 32-bit values+ */+void +_ktxSwapEndian32(khronos_uint32_t* pData32, int count)+{+ int i;+ for (i = 0; i < count; ++i)+ {+ khronos_uint32_t x = *pData32;+ *pData32++ = (x << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | (x >> 24);+ }+}++
+ KTX/lib/uthash.h view
@@ -0,0 +1,960 @@+/*+Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+*/++#ifndef UTHASH_H+#define UTHASH_H ++#include <string.h> /* memcmp,strlen */+#include <stddef.h> /* ptrdiff_t */++/* These macros use decltype or the earlier __typeof GNU extension.+ As decltype is only available in newer compilers (VS2010 or gcc 4.3++ when compiling c++ source) this code uses whatever method is needed+ or, for VS2008 where neither is available, uses casting workarounds. */+#ifdef _MSC_VER /* MS compiler */+#if _MSC_VER >= 1600 && __cplusplus /* VS2010 or newer in C++ mode */+#define DECLTYPE(x) (decltype(x))+#else /* VS2008 or older (or VS2010 in C mode) */+#define NO_DECLTYPE+#define DECLTYPE(x)+#endif+#else /* GNU, Sun and other compilers */+#define DECLTYPE(x) (__typeof(x))+#endif++#ifdef NO_DECLTYPE+#define DECLTYPE_ASSIGN(dst,src) \+do { \+ char **_da_dst = (char**)(&(dst)); \+ *_da_dst = (char*)(src); \+} while(0)+#else +#define DECLTYPE_ASSIGN(dst,src) \+do { \+ (dst) = DECLTYPE(dst)(src); \+} while(0)+#endif++/* a number of the hash function use uint32_t which isn't defined on win32 */+#ifdef _MSC_VER+typedef unsigned int uint32_t;+#else+#include <inttypes.h> /* uint32_t */+#endif++#define UTHASH_VERSION 1.9.1++#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */+#define uthash_malloc(sz) malloc(sz) /* malloc fcn */+#define uthash_free(ptr) free(ptr) /* free fcn */++#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */+#define uthash_expand_fyi(tbl) /* can be defined to log expands */++/* initial number of buckets */+#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */+#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */++/* calculate the element whose hash handle address is hhe */+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))++#define HASH_FIND(hh,head,keyptr,keylen,out) \+do { \+ unsigned _hf_bkt,_hf_hashv; \+ out=NULL; \+ if (head) { \+ HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \+ if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \+ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \+ keyptr,keylen,out); \+ } \+ } \+} while (0)++#ifdef HASH_BLOOM+#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)+#define HASH_BLOOM_MAKE(tbl) \+do { \+ (tbl)->bloom_nbits = HASH_BLOOM; \+ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \+ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \+ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \+ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \+} while (0);++#define HASH_BLOOM_FREE(tbl) \+do { \+ uthash_free((tbl)->bloom_bv); \+} while (0);++#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))++#define HASH_BLOOM_ADD(tbl,hashv) \+ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))++#define HASH_BLOOM_TEST(tbl,hashv) \+ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))++#else+#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1)+#endif++#define HASH_MAKE_TABLE(hh,head) \+do { \+ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \+ sizeof(UT_hash_table)); \+ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \+ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \+ (head)->hh.tbl->tail = &((head)->hh); \+ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \+ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \+ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \+ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \+ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \+ memset((head)->hh.tbl->buckets, 0, \+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \+ HASH_BLOOM_MAKE((head)->hh.tbl); \+ (head)->hh.tbl->signature = HASH_SIGNATURE; \+} while(0)++#define HASH_ADD(hh,head,fieldname,keylen_in,add) \+ HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add)+ +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \+do { \+ unsigned _ha_bkt; \+ (add)->hh.next = NULL; \+ (add)->hh.key = (char*)keyptr; \+ (add)->hh.keylen = keylen_in; \+ if (!(head)) { \+ head = (add); \+ (head)->hh.prev = NULL; \+ HASH_MAKE_TABLE(hh,head); \+ } else { \+ (head)->hh.tbl->tail->next = (add); \+ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \+ (head)->hh.tbl->tail = &((add)->hh); \+ } \+ (head)->hh.tbl->num_items++; \+ (add)->hh.tbl = (head)->hh.tbl; \+ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \+ (add)->hh.hashv, _ha_bkt); \+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \+ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \+ HASH_FSCK(hh,head); \+} while(0)++#define HASH_TO_BKT( hashv, num_bkts, bkt ) \+do { \+ bkt = ((hashv) & ((num_bkts) - 1)); \+} while(0)++/* delete "delptr" from the hash table.+ * "the usual" patch-up process for the app-order doubly-linked-list.+ * The use of _hd_hh_del below deserves special explanation.+ * These used to be expressed using (delptr) but that led to a bug+ * if someone used the same symbol for the head and deletee, like+ * HASH_DELETE(hh,users,users);+ * We want that to work, but by changing the head (users) below+ * we were forfeiting our ability to further refer to the deletee (users)+ * in the patch-up process. Solution: use scratch space to+ * copy the deletee pointer, then the latter references are via that+ * scratch pointer rather than through the repointed (users) symbol.+ */+#define HASH_DELETE(hh,head,delptr) \+do { \+ unsigned _hd_bkt; \+ struct UT_hash_handle *_hd_hh_del; \+ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \+ uthash_free((head)->hh.tbl->buckets ); \+ HASH_BLOOM_FREE((head)->hh.tbl); \+ uthash_free((head)->hh.tbl); \+ head = NULL; \+ } else { \+ _hd_hh_del = &((delptr)->hh); \+ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \+ (head)->hh.tbl->tail = \+ (UT_hash_handle*)((char*)((delptr)->hh.prev) + \+ (head)->hh.tbl->hho); \+ } \+ if ((delptr)->hh.prev) { \+ ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \+ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \+ } else { \+ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \+ } \+ if (_hd_hh_del->next) { \+ ((UT_hash_handle*)((char*)_hd_hh_del->next + \+ (head)->hh.tbl->hho))->prev = \+ _hd_hh_del->prev; \+ } \+ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \+ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \+ (head)->hh.tbl->num_items--; \+ } \+ HASH_FSCK(hh,head); \+} while (0)+++/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */+#define HASH_FIND_STR(head,findstr,out) \+ HASH_FIND(hh,head,findstr,strlen(findstr),out)+#define HASH_ADD_STR(head,strfield,add) \+ HASH_ADD(hh,head,strfield,strlen(add->strfield),add)+#define HASH_FIND_INT(head,findint,out) \+ HASH_FIND(hh,head,findint,sizeof(int),out)+#define HASH_ADD_INT(head,intfield,add) \+ HASH_ADD(hh,head,intfield,sizeof(int),add)+#define HASH_FIND_PTR(head,findptr,out) \+ HASH_FIND(hh,head,findptr,sizeof(void *),out)+#define HASH_ADD_PTR(head,ptrfield,add) \+ HASH_ADD(hh,head,ptrfield,sizeof(void *),add)+#define HASH_DEL(head,delptr) \+ HASH_DELETE(hh,head,delptr)++/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.+ */+#ifdef HASH_DEBUG+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)+#define HASH_FSCK(hh,head) \+do { \+ unsigned _bkt_i; \+ unsigned _count, _bkt_count; \+ char *_prev; \+ struct UT_hash_handle *_thh; \+ if (head) { \+ _count = 0; \+ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \+ _bkt_count = 0; \+ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \+ _prev = NULL; \+ while (_thh) { \+ if (_prev != (char*)(_thh->hh_prev)) { \+ HASH_OOPS("invalid hh_prev %p, actual %p\n", \+ _thh->hh_prev, _prev ); \+ } \+ _bkt_count++; \+ _prev = (char*)(_thh); \+ _thh = _thh->hh_next; \+ } \+ _count += _bkt_count; \+ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \+ HASH_OOPS("invalid bucket count %d, actual %d\n", \+ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \+ } \+ } \+ if (_count != (head)->hh.tbl->num_items) { \+ HASH_OOPS("invalid hh item count %d, actual %d\n", \+ (head)->hh.tbl->num_items, _count ); \+ } \+ /* traverse hh in app order; check next/prev integrity, count */ \+ _count = 0; \+ _prev = NULL; \+ _thh = &(head)->hh; \+ while (_thh) { \+ _count++; \+ if (_prev !=(char*)(_thh->prev)) { \+ HASH_OOPS("invalid prev %p, actual %p\n", \+ _thh->prev, _prev ); \+ } \+ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \+ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \+ (head)->hh.tbl->hho) : NULL ); \+ } \+ if (_count != (head)->hh.tbl->num_items) { \+ HASH_OOPS("invalid app item count %d, actual %d\n", \+ (head)->hh.tbl->num_items, _count ); \+ } \+ } \+} while (0)+#else+#define HASH_FSCK(hh,head) +#endif++/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function.+ * The app can #include <unistd.h> to get the prototype for write(2). */+#ifdef HASH_EMIT_KEYS+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \+do { \+ unsigned _klen = fieldlen; \+ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \+ write(HASH_EMIT_KEYS, keyptr, fieldlen); \+} while (0)+#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif++/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */+#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION+#else+#define HASH_FCN HASH_JEN+#endif++/* The Bernstein hash function, used in Perl prior to v5.6 */+#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \+do { \+ unsigned _hb_keylen=keylen; \+ char *_hb_key=(char*)key; \+ (hashv) = 0; \+ while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \+ bkt = (hashv) & (num_bkts-1); \+} while (0)+++/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */+#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \+do { \+ unsigned _sx_i; \+ char *_hs_key=(char*)key; \+ hashv = 0; \+ for(_sx_i=0; _sx_i < keylen; _sx_i++) \+ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \+ bkt = hashv & (num_bkts-1); \+} while (0)++#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \+do { \+ unsigned _fn_i; \+ char *_hf_key=(char*)key; \+ hashv = 2166136261UL; \+ for(_fn_i=0; _fn_i < keylen; _fn_i++) \+ hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \+ bkt = hashv & (num_bkts-1); \+} while(0);+ +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \+do { \+ unsigned _ho_i; \+ char *_ho_key=(char*)key; \+ hashv = 0; \+ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \+ hashv += _ho_key[_ho_i]; \+ hashv += (hashv << 10); \+ hashv ^= (hashv >> 6); \+ } \+ hashv += (hashv << 3); \+ hashv ^= (hashv >> 11); \+ hashv += (hashv << 15); \+ bkt = hashv & (num_bkts-1); \+} while(0)++#define HASH_JEN_MIX(a,b,c) \+do { \+ a -= b; a -= c; a ^= ( c >> 13 ); \+ b -= c; b -= a; b ^= ( a << 8 ); \+ c -= a; c -= b; c ^= ( b >> 13 ); \+ a -= b; a -= c; a ^= ( c >> 12 ); \+ b -= c; b -= a; b ^= ( a << 16 ); \+ c -= a; c -= b; c ^= ( b >> 5 ); \+ a -= b; a -= c; a ^= ( c >> 3 ); \+ b -= c; b -= a; b ^= ( a << 10 ); \+ c -= a; c -= b; c ^= ( b >> 15 ); \+} while (0)++#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \+do { \+ unsigned _hj_i,_hj_j,_hj_k; \+ char *_hj_key=(char*)key; \+ hashv = 0xfeedbeef; \+ _hj_i = _hj_j = 0x9e3779b9; \+ _hj_k = keylen; \+ while (_hj_k >= 12) { \+ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \+ + ( (unsigned)_hj_key[2] << 16 ) \+ + ( (unsigned)_hj_key[3] << 24 ) ); \+ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \+ + ( (unsigned)_hj_key[6] << 16 ) \+ + ( (unsigned)_hj_key[7] << 24 ) ); \+ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \+ + ( (unsigned)_hj_key[10] << 16 ) \+ + ( (unsigned)_hj_key[11] << 24 ) ); \+ \+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \+ \+ _hj_key += 12; \+ _hj_k -= 12; \+ } \+ hashv += keylen; \+ switch ( _hj_k ) { \+ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \+ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \+ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \+ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \+ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \+ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \+ case 5: _hj_j += _hj_key[4]; \+ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \+ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \+ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \+ case 1: _hj_i += _hj_key[0]; \+ } \+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \+ bkt = hashv & (num_bkts-1); \+} while(0)++/* The Paul Hsieh hash function */+#undef get16bits+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)+#define get16bits(d) (*((const uint16_t *) (d)))+#endif++#if !defined (get16bits)+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \+ +(uint32_t)(((const uint8_t *)(d))[0]) )+#endif+#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \+do { \+ char *_sfh_key=(char*)key; \+ uint32_t _sfh_tmp, _sfh_len = keylen; \+ \+ int _sfh_rem = _sfh_len & 3; \+ _sfh_len >>= 2; \+ hashv = 0xcafebabe; \+ \+ /* Main loop */ \+ for (;_sfh_len > 0; _sfh_len--) { \+ hashv += get16bits (_sfh_key); \+ _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \+ hashv = (hashv << 16) ^ _sfh_tmp; \+ _sfh_key += 2*sizeof (uint16_t); \+ hashv += hashv >> 11; \+ } \+ \+ /* Handle end cases */ \+ switch (_sfh_rem) { \+ case 3: hashv += get16bits (_sfh_key); \+ hashv ^= hashv << 16; \+ hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \+ hashv += hashv >> 11; \+ break; \+ case 2: hashv += get16bits (_sfh_key); \+ hashv ^= hashv << 11; \+ hashv += hashv >> 17; \+ break; \+ case 1: hashv += *_sfh_key; \+ hashv ^= hashv << 10; \+ hashv += hashv >> 1; \+ } \+ \+ /* Force "avalanching" of final 127 bits */ \+ hashv ^= hashv << 3; \+ hashv += hashv >> 5; \+ hashv ^= hashv << 4; \+ hashv += hashv >> 17; \+ hashv ^= hashv << 25; \+ hashv += hashv >> 6; \+ bkt = hashv & (num_bkts-1); \+} while(0);++#ifdef HASH_USING_NO_STRICT_ALIASING+/* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads.+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.+ * So MurmurHash comes in two versions, the faster unaligned one and the slower+ * aligned one. We only use the faster one on CPU's where we know it's safe. + *+ * Note the preprocessor built-in defines can be emitted using:+ *+ * gcc -m64 -dM -E - < /dev/null (on gcc)+ * cc -## a.c (where a.c is a simple test file) (Sun Studio)+ */+#if (defined(__i386__) || defined(__x86_64__)) +#define HASH_MUR HASH_MUR_UNALIGNED+#else+#define HASH_MUR HASH_MUR_ALIGNED+#endif++/* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */+#define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \+do { \+ const unsigned int _mur_m = 0x5bd1e995; \+ const int _mur_r = 24; \+ hashv = 0xcafebabe ^ keylen; \+ char *_mur_key = (char *)key; \+ uint32_t _mur_tmp, _mur_len = keylen; \+ \+ for (;_mur_len >= 4; _mur_len-=4) { \+ _mur_tmp = *(uint32_t *)_mur_key; \+ _mur_tmp *= _mur_m; \+ _mur_tmp ^= _mur_tmp >> _mur_r; \+ _mur_tmp *= _mur_m; \+ hashv *= _mur_m; \+ hashv ^= _mur_tmp; \+ _mur_key += 4; \+ } \+ \+ switch(_mur_len) \+ { \+ case 3: hashv ^= _mur_key[2] << 16; \+ case 2: hashv ^= _mur_key[1] << 8; \+ case 1: hashv ^= _mur_key[0]; \+ hashv *= _mur_m; \+ }; \+ \+ hashv ^= hashv >> 13; \+ hashv *= _mur_m; \+ hashv ^= hashv >> 15; \+ \+ bkt = hashv & (num_bkts-1); \+} while(0)++/* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */+#define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \+do { \+ const unsigned int _mur_m = 0x5bd1e995; \+ const int _mur_r = 24; \+ hashv = 0xcafebabe ^ keylen; \+ char *_mur_key = (char *)key; \+ uint32_t _mur_len = keylen; \+ int _mur_align = (int)_mur_key & 3; \+ \+ if (_mur_align && (_mur_len >= 4)) { \+ unsigned _mur_t = 0, _mur_d = 0; \+ switch(_mur_align) { \+ case 1: _mur_t |= _mur_key[2] << 16; \+ case 2: _mur_t |= _mur_key[1] << 8; \+ case 3: _mur_t |= _mur_key[0]; \+ } \+ _mur_t <<= (8 * _mur_align); \+ _mur_key += 4-_mur_align; \+ _mur_len -= 4-_mur_align; \+ int _mur_sl = 8 * (4-_mur_align); \+ int _mur_sr = 8 * _mur_align; \+ \+ for (;_mur_len >= 4; _mur_len-=4) { \+ _mur_d = *(unsigned *)_mur_key; \+ _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \+ unsigned _mur_k = _mur_t; \+ _mur_k *= _mur_m; \+ _mur_k ^= _mur_k >> _mur_r; \+ _mur_k *= _mur_m; \+ hashv *= _mur_m; \+ hashv ^= _mur_k; \+ _mur_t = _mur_d; \+ _mur_key += 4; \+ } \+ _mur_d = 0; \+ if(_mur_len >= _mur_align) { \+ switch(_mur_align) { \+ case 3: _mur_d |= _mur_key[2] << 16; \+ case 2: _mur_d |= _mur_key[1] << 8; \+ case 1: _mur_d |= _mur_key[0]; \+ } \+ unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \+ _mur_k *= _mur_m; \+ _mur_k ^= _mur_k >> _mur_r; \+ _mur_k *= _mur_m; \+ hashv *= _mur_m; \+ hashv ^= _mur_k; \+ _mur_k += _mur_align; \+ _mur_len -= _mur_align; \+ \+ switch(_mur_len) \+ { \+ case 3: hashv ^= _mur_key[2] << 16; \+ case 2: hashv ^= _mur_key[1] << 8; \+ case 1: hashv ^= _mur_key[0]; \+ hashv *= _mur_m; \+ } \+ } else { \+ switch(_mur_len) \+ { \+ case 3: _mur_d ^= _mur_key[2] << 16; \+ case 2: _mur_d ^= _mur_key[1] << 8; \+ case 1: _mur_d ^= _mur_key[0]; \+ case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \+ hashv *= _mur_m; \+ } \+ } \+ \+ hashv ^= hashv >> 13; \+ hashv *= _mur_m; \+ hashv ^= hashv >> 15; \+ } else { \+ for (;_mur_len >= 4; _mur_len-=4) { \+ unsigned _mur_k = *(unsigned*)_mur_key; \+ _mur_k *= _mur_m; \+ _mur_k ^= _mur_k >> _mur_r; \+ _mur_k *= _mur_m; \+ hashv *= _mur_m; \+ hashv ^= _mur_k; \+ _mur_key += 4; \+ } \+ switch(_mur_len) \+ { \+ case 3: hashv ^= _mur_key[2] << 16; \+ case 2: hashv ^= _mur_key[1] << 8; \+ case 1: hashv ^= _mur_key[0]; \+ hashv *= _mur_m; \+ } \+ \+ hashv ^= hashv >> 13; \+ hashv *= _mur_m; \+ hashv ^= hashv >> 15; \+ } \+ bkt = hashv & (num_bkts-1); \+} while(0)+#endif /* HASH_USING_NO_STRICT_ALIASING */++/* key comparison function; return 0 if keys equal */+#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) ++/* iterate over items in a known bucket to find desired item */+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \+do { \+ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \+ else out=NULL; \+ while (out) { \+ if (out->hh.keylen == keylen_in) { \+ if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \+ } \+ if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \+ else out = NULL; \+ } \+} while(0)++/* add an item to a bucket */+#define HASH_ADD_TO_BKT(head,addhh) \+do { \+ head.count++; \+ (addhh)->hh_next = head.hh_head; \+ (addhh)->hh_prev = NULL; \+ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \+ (head).hh_head=addhh; \+ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \+ && (addhh)->tbl->noexpand != 1) { \+ HASH_EXPAND_BUCKETS((addhh)->tbl); \+ } \+} while(0)++/* remove an item from a given bucket */+#define HASH_DEL_IN_BKT(hh,head,hh_del) \+ (head).count--; \+ if ((head).hh_head == hh_del) { \+ (head).hh_head = hh_del->hh_next; \+ } \+ if (hh_del->hh_prev) { \+ hh_del->hh_prev->hh_next = hh_del->hh_next; \+ } \+ if (hh_del->hh_next) { \+ hh_del->hh_next->hh_prev = hh_del->hh_prev; \+ } ++/* Bucket expansion has the effect of doubling the number of buckets+ * and redistributing the items into the new buckets. Ideally the+ * items will distribute more or less evenly into the new buckets+ * (the extent to which this is true is a measure of the quality of+ * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length+ * (item count) in each bucket is reduced. Thus by expanding buckets+ * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup.+ * + * The calculation of tbl->ideal_chain_maxlen below deserves some+ * explanation. First, keep in mind that we're calculating the ideal+ * maximum chain length based on the *new* (doubled) bucket count.+ * In fractions this is just n/b (n=number of items,b=new num buckets).+ * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this+ * hash, so to calculate ceil(n/b) with integers we could write+ * + * ceil(n/b) = (n/b) + ((n%b)?1:0)+ * + * and in fact a previous version of this hash did just that.+ * But now we have improved things a bit by recognizing that b is+ * always a power of two. We keep its base 2 log handy (call it lb),+ * so now we can write this with a bit shift and logical AND:+ * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)+ * + */+#define HASH_EXPAND_BUCKETS(tbl) \+do { \+ unsigned _he_bkt; \+ unsigned _he_bkt_i; \+ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \+ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \+ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \+ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \+ if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \+ memset(_he_new_buckets, 0, \+ 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \+ tbl->ideal_chain_maxlen = \+ (tbl->num_items >> (tbl->log2_num_buckets+1)) + \+ ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \+ tbl->nonideal_items = 0; \+ for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \+ { \+ _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \+ while (_he_thh) { \+ _he_hh_nxt = _he_thh->hh_next; \+ HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \+ _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \+ if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \+ tbl->nonideal_items++; \+ _he_newbkt->expand_mult = _he_newbkt->count / \+ tbl->ideal_chain_maxlen; \+ } \+ _he_thh->hh_prev = NULL; \+ _he_thh->hh_next = _he_newbkt->hh_head; \+ if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \+ _he_thh; \+ _he_newbkt->hh_head = _he_thh; \+ _he_thh = _he_hh_nxt; \+ } \+ } \+ tbl->num_buckets *= 2; \+ tbl->log2_num_buckets++; \+ uthash_free( tbl->buckets ); \+ tbl->buckets = _he_new_buckets; \+ tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \+ (tbl->ineff_expands+1) : 0; \+ if (tbl->ineff_expands > 1) { \+ tbl->noexpand=1; \+ uthash_noexpand_fyi(tbl); \+ } \+ uthash_expand_fyi(tbl); \+} while(0)+++/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */+/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)+#define HASH_SRT(hh,head,cmpfcn) \+do { \+ unsigned _hs_i; \+ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \+ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \+ if (head) { \+ _hs_insize = 1; \+ _hs_looping = 1; \+ _hs_list = &((head)->hh); \+ while (_hs_looping) { \+ _hs_p = _hs_list; \+ _hs_list = NULL; \+ _hs_tail = NULL; \+ _hs_nmerges = 0; \+ while (_hs_p) { \+ _hs_nmerges++; \+ _hs_q = _hs_p; \+ _hs_psize = 0; \+ for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \+ _hs_psize++; \+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \+ ((void*)((char*)(_hs_q->next) + \+ (head)->hh.tbl->hho)) : NULL); \+ if (! (_hs_q) ) break; \+ } \+ _hs_qsize = _hs_insize; \+ while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \+ if (_hs_psize == 0) { \+ _hs_e = _hs_q; \+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \+ ((void*)((char*)(_hs_q->next) + \+ (head)->hh.tbl->hho)) : NULL); \+ _hs_qsize--; \+ } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \+ _hs_e = _hs_p; \+ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \+ ((void*)((char*)(_hs_p->next) + \+ (head)->hh.tbl->hho)) : NULL); \+ _hs_psize--; \+ } else if (( \+ cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \+ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \+ ) <= 0) { \+ _hs_e = _hs_p; \+ _hs_p = (UT_hash_handle*)((_hs_p->next) ? \+ ((void*)((char*)(_hs_p->next) + \+ (head)->hh.tbl->hho)) : NULL); \+ _hs_psize--; \+ } else { \+ _hs_e = _hs_q; \+ _hs_q = (UT_hash_handle*)((_hs_q->next) ? \+ ((void*)((char*)(_hs_q->next) + \+ (head)->hh.tbl->hho)) : NULL); \+ _hs_qsize--; \+ } \+ if ( _hs_tail ) { \+ _hs_tail->next = ((_hs_e) ? \+ ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \+ } else { \+ _hs_list = _hs_e; \+ } \+ _hs_e->prev = ((_hs_tail) ? \+ ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \+ _hs_tail = _hs_e; \+ } \+ _hs_p = _hs_q; \+ } \+ _hs_tail->next = NULL; \+ if ( _hs_nmerges <= 1 ) { \+ _hs_looping=0; \+ (head)->hh.tbl->tail = _hs_tail; \+ DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \+ } \+ _hs_insize *= 2; \+ } \+ HASH_FSCK(hh,head); \+ } \+} while (0)++/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \+do { \+ unsigned _src_bkt, _dst_bkt; \+ void *_last_elt=NULL, *_elt; \+ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \+ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \+ if (src) { \+ for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \+ for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \+ _src_hh; \+ _src_hh = _src_hh->hh_next) { \+ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \+ if (cond(_elt)) { \+ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \+ _dst_hh->key = _src_hh->key; \+ _dst_hh->keylen = _src_hh->keylen; \+ _dst_hh->hashv = _src_hh->hashv; \+ _dst_hh->prev = _last_elt; \+ _dst_hh->next = NULL; \+ if (_last_elt_hh) { _last_elt_hh->next = _elt; } \+ if (!dst) { \+ DECLTYPE_ASSIGN(dst,_elt); \+ HASH_MAKE_TABLE(hh_dst,dst); \+ } else { \+ _dst_hh->tbl = (dst)->hh_dst.tbl; \+ } \+ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \+ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \+ (dst)->hh_dst.tbl->num_items++; \+ _last_elt = _elt; \+ _last_elt_hh = _dst_hh; \+ } \+ } \+ } \+ } \+ HASH_FSCK(hh_dst,dst); \+} while (0)++#define HASH_CLEAR(hh,head) \+do { \+ if (head) { \+ uthash_free((head)->hh.tbl->buckets ); \+ uthash_free((head)->hh.tbl); \+ (head)=NULL; \+ } \+} while(0)++/* obtain a count of items in the hash */+#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) (head?(head->hh.tbl->num_items):0)++typedef struct UT_hash_bucket {+ struct UT_hash_handle *hh_head;+ unsigned count;++ /* expand_mult is normally set to 0. In this situation, the max chain length+ * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If+ * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion+ * (that would be triggered by additions to this particular bucket)+ * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.+ * (The multiplier is simply expand_mult+1). The whole idea of this+ * multiplier is to reduce bucket expansions, since they are expensive, in+ * situations where we know that a particular bucket tends to be overused.+ * It is better to let its chain length grow to a longer yet-still-bounded+ * value, than to do an O(n) bucket expansion too often. + */+ unsigned expand_mult;++} UT_hash_bucket;++/* random signature used only to find hash tables in external analysis */+#define HASH_SIGNATURE 0xa0111fe1+#define HASH_BLOOM_SIGNATURE 0xb12220f2++typedef struct UT_hash_table {+ UT_hash_bucket *buckets;+ unsigned num_buckets, log2_num_buckets;+ unsigned num_items;+ struct UT_hash_handle *tail; /* tail hh in app order, for fast append */+ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */++ /* in an ideal situation (all buckets used equally), no bucket would have+ * more than ceil(#items/#buckets) items. that's the ideal chain length. */+ unsigned ideal_chain_maxlen;++ /* nonideal_items is the number of items in the hash whose chain position+ * exceeds the ideal chain maxlen. these items pay the penalty for an uneven+ * hash distribution; reaching them in a chain traversal takes >ideal steps */+ unsigned nonideal_items;++ /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain+ * positions. If this happens on two consecutive expansions we inhibit any+ * further expansion, as it's not helping; this happens when the hash+ * function isn't a good fit for the key domain. When expansion is inhibited+ * the hash will still work, albeit no longer in constant time. */+ unsigned ineff_expands, noexpand;++ uint32_t signature; /* used only to find hash tables in external analysis */+#ifdef HASH_BLOOM+ uint32_t bloom_sig; /* used only to test bloom exists in external analysis */+ uint8_t *bloom_bv;+ char bloom_nbits;+#endif++} UT_hash_table;++typedef struct UT_hash_handle {+ struct UT_hash_table *tbl;+ void *prev; /* prev element in app order */+ void *next; /* next element in app order */+ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */+ struct UT_hash_handle *hh_next; /* next hh in bucket order */+ void *key; /* ptr to enclosing struct's key */+ unsigned keylen; /* enclosing struct's key len */+ unsigned hashv; /* result of hash-fcn(key) */+} UT_hash_handle;++#endif /* UTHASH_H */
+ KTX/lib/writer.c view
@@ -0,0 +1,735 @@+/* -*- tab-width: 4; -*- */+/* vi: set sw=2 ts=4: */++/* $Id: b2ab7bcfcab83b13e5c65b45c006154fe0c68062 $ */++/**+ * @file writer.c+ * @~English+ *+ * @brief Functions for creating KTX-format files from a set of images.+ *+ * @author Mark Callow, HI Corporation+ */++/*+Copyright (c) 2010 The Khronos Group Inc.++Permission is hereby granted, free of charge, to any person obtaining a+copy of this software and/or associated documentation files (the+"Materials"), to deal in the Materials without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Materials, and to+permit persons to whom the Materials are furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+unaltered in all copies or substantial portions of the Materials.+Any additions, deletions, or changes to the original source files+must be clearly indicated in accompanying documentation.++If only executable code is distributed, then the accompanying+documentation must state that "this software is based in part on the+work of the Khronos Group".++THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.+*/++#include <stdio.h>+#include <stdlib.h>+#include <assert.h>++#include "ktx.h"+#include "ktxint.h"+#include "ktxstream.h"+#include "ktxfilestream.h"+#include "ktxmemstream.h"++static KTX_error_code validateTypeAndFormat(GLenum format, GLenum type);+static KTX_error_code sizeofGroupAndElement(GLenum format, GLenum type,+ GLuint* groupBytes, GLuint* elementBytes,+ GLboolean* packed);+static KTX_error_code sizeofGLtype(GLenum type, GLuint* size, GLboolean* packed);+++/**+ * @~English+ * @brief Write image(s) in a KTX-format to a ktxStream.+ *+ * @param [in] stream pointer to the ktxStream from which to load.+ * @param [in] textureInfo pointer to a KTX_image_info structure providing+ * information about the images to be included in+ * the KTX file.+ * @param [in] bytesOfKeyValueData+ * specifies the number of bytes of key-value data.+ * @param [in] keyValueData a pointer to the keyValue data.+ * @param [in] numImages number of images in the following array+ * @param [in] images array of KTX_image_info providing image size and+ * data.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p dst or @p target are @c NULL+ * @exception KTX_INVALID_VALUE @c glTypeSize in @p textureInfo is not 1, 2, or 4 or+ * is different from the size of the type specified+ * in @c glType.+ * @exception KTX_INVALID_VALUE @c pixelWidth in @p textureInfo is 0 or pixelDepth != 0+ * && pixelHeight == 0.+ * @exception KTX_INVALID_VALUE @c numberOfFaces != 1 || numberOfFaces != 6 or+ * numberOfArrayElements or numberOfMipmapLevels are < 0.+ * @exception KTX_INVALID_VALUE @c glType in @p textureInfo is an unrecognized type.+ * @exception KTX_INVALID_OPERATION+ * numberOfFaces == 6 and images are either not 2D or+ * are not square.+ * @exception KTX_INVALID_OPERATION+ * number of images is insufficient for the specified+ * number of mipmap levels and faces.+ * @exception KTX_INVALID_OPERATION+ * the size of a provided image is different than that+ * required for the specified width, height or depth+ * or for the mipmap level being processed.+ * @exception KTX_INVALID_OPERATION+ * @c glType and @c glFormat in @p textureInfo are mismatched.+ * See OpenGL 4.4 specification section 8.4.4 and+ * table 8.5.+ * @exception KTX_FILE_WRITE_ERROR a system error occurred while writing the file.+ * @exception KTX_OUT_OF_MEMORY system failed to allocate sufficient memory.+ */+static+KTX_error_code+ktxWriteKTXS(struct ktxStream *stream, const KTX_texture_info* textureInfo,+ GLsizei bytesOfKeyValueData, const void* keyValueData,+ GLuint numImages, KTX_image_info images[])+{+ KTX_header header = KTX_IDENTIFIER_REF;+ GLuint i, level, dimension, cubemap = 0;+ GLuint numMipmapLevels, numArrayElements;+ GLbyte pad[4] = { 0, 0, 0, 0 };+ KTX_error_code errorCode = KTX_SUCCESS;+ GLboolean compressed = GL_FALSE;+ GLuint groupBytes, elementBytes;++ if (!stream) {+ return KTX_INVALID_VALUE;+ }++ //endianess int.. if this comes out reversed, all of the other ints will too.+ header.endianness = KTX_ENDIAN_REF;+ header.glType = textureInfo->glType;+ header.glTypeSize = textureInfo->glTypeSize;+ header.glFormat = textureInfo->glFormat;+ header.glInternalFormat = textureInfo->glInternalFormat;+ header.glBaseInternalFormat = textureInfo->glBaseInternalFormat;+ header.pixelWidth = textureInfo->pixelWidth;+ header.pixelHeight = textureInfo->pixelHeight;+ header.pixelDepth = textureInfo->pixelDepth;+ header.numberOfArrayElements = textureInfo->numberOfArrayElements;+ header.numberOfFaces = textureInfo->numberOfFaces;+ header.numberOfMipmapLevels = textureInfo->numberOfMipmapLevels;+ header.bytesOfKeyValueData = bytesOfKeyValueData;++ /* Do some sanity checking */+ if (header.glTypeSize != 1 &&+ header.glTypeSize != 2 &&+ header.glTypeSize != 4)+ {+ /* Only 8, 16, and 32-bit types are supported for byte-swapping.+ * See UNPACK_SWAP_BYTES & table 8.4 in the OpenGL 4.4 spec.+ */+ return KTX_INVALID_VALUE;+ }++ if (header.glType == 0 || header.glFormat == 0)+ {+ if (header.glType + header.glFormat != 0) {+ /* either both or neither of glType & glFormat must be zero */+ return KTX_INVALID_VALUE;+ } else+ compressed = GL_TRUE;+ }+ else+ {+ GLboolean packed;++ /* Get size of group and element */+ if ((errorCode = sizeofGroupAndElement(header.glFormat, header.glType,+ &groupBytes, &elementBytes, &packed)) != KTX_SUCCESS)+ {+ return errorCode;+ }++ /* Check validity of type/format combination for packed types */+ if (packed && (errorCode = validateTypeAndFormat(header.glFormat, header.glType)) != KTX_SUCCESS)+ {+ return errorCode;+ }++ if (header.glTypeSize != elementBytes)+ {+#if defined(GL_FLOAT_32_UNSIGNED_INT_24_8_REV)+ if (header.glType != GL_FLOAT_32_UNSIGNED_INT_24_8_REV || header.glTypeSize != 1)+#endif+ return KTX_INVALID_VALUE;+ }+ }+++ /* Check texture dimensions. KTX files can store 8 types of textures:+ * 1D, 2D, 3D, cube, and array variants of these. There is currently+ * no GL extension that would accept 3D array or cube array textures+ * but we'll let such files be created.+ */+ if ((header.pixelWidth == 0) ||+ (header.pixelDepth > 0 && header.pixelHeight == 0))+ {+ /* texture must have width */+ /* texture must have height if it has depth */+ return KTX_INVALID_VALUE;+ }+ if (header.pixelHeight > 0 && header.pixelDepth > 0)+ dimension = 3;+ else if (header.pixelHeight > 0)+ dimension = 2;+ else+ dimension = 1;++ if (header.numberOfFaces == 6)+ {+ if (dimension != 2)+ {+ /* cube map needs 2D faces */+ return KTX_INVALID_OPERATION;+ }+ if (header.pixelWidth != header.pixelHeight)+ {+ /* cube maps require square images */+ return KTX_INVALID_OPERATION;+ }+ }+ else if (header.numberOfFaces != 1)+ {+ /* numberOfFaces must be either 1 or 6 */+ return KTX_INVALID_VALUE;+ }++ if (header.numberOfArrayElements == 0)+ {+ numArrayElements = 1;+ if (header.numberOfFaces == 6)+ cubemap = 1;+ }+ else+ numArrayElements = header.numberOfArrayElements;++ /* Check number of mipmap levels */+ if (header.numberOfMipmapLevels == 0)+ {+ numMipmapLevels = 1;+ }+ else+ numMipmapLevels = header.numberOfMipmapLevels;+ if (numMipmapLevels > 1) {+ GLuint max_dim = MAX(MAX(header.pixelWidth, header.pixelHeight), header.pixelDepth);+ if (max_dim < ((GLuint)1 << (header.numberOfMipmapLevels - 1)))+ {+ /* Can't have more mip levels than 1 + log2(max(width, height, depth)) */+ return KTX_INVALID_VALUE;+ }+ }++ if (numImages < numMipmapLevels * header.numberOfFaces)+ {+ /* Not enough images */+ return KTX_INVALID_OPERATION;+ }++ //write header+ errorCode = stream->write(&header, sizeof(KTX_header), 1, stream->src);+ if (errorCode != KTX_SUCCESS)+ return errorCode;++ //write keyValueData+ if (bytesOfKeyValueData != 0) {+ if (keyValueData == NULL)+ return KTX_INVALID_OPERATION;++ errorCode = stream->write(keyValueData, 1, bytesOfKeyValueData, stream->src);+ if (errorCode != KTX_SUCCESS)+ return errorCode;+ }++ /* Write the image data */+ for (level = 0, i = 0; level < numMipmapLevels; ++level)+ {+ GLsizei expectedFaceSize;+ GLuint face, faceLodSize, faceLodRounding;+ GLuint pixelWidth, pixelHeight, pixelDepth;+ GLuint packedRowBytes, rowBytes, rowRounding;++ pixelWidth = MAX(1, header.pixelWidth >> level);+ pixelHeight = MAX(1, header.pixelHeight >> level);+ pixelDepth = MAX(1, header.pixelDepth >> level);++ /* Calculate face sizes for this LoD based on glType, glFormat, width & height */+ expectedFaceSize = groupBytes+ * pixelWidth+ * pixelHeight+ * pixelDepth+ * numArrayElements;++ rowRounding = 0;+ packedRowBytes = groupBytes * pixelWidth;+ /* KTX format specifies UNPACK_ALIGNMENT==4 */+ /* GL spec: rows are not to be padded when elementBytes != 1, 2, 4 or 8.+ * As GL currently has no such elements, no test is necessary.+ */+ if (!compressed && elementBytes < KTX_GL_UNPACK_ALIGNMENT) {+ // Equivalent to UNPACK_ALIGNMENT * ceil((groupSize * pixelWidth) / UNPACK_ALIGNMENT)+ rowRounding = 3 - ((packedRowBytes + KTX_GL_UNPACK_ALIGNMENT-1) % KTX_GL_UNPACK_ALIGNMENT);+ rowBytes = packedRowBytes + rowRounding;+ }++ if (rowRounding == 0) {+ faceLodSize = images[i].size;+ } else {+ /* Need to pad the rows to meet the required UNPACK_ALIGNMENT */+ faceLodSize = rowBytes * pixelHeight * pixelDepth * numArrayElements;+ }+ faceLodRounding = 3 - ((faceLodSize + 3) % 4);++ errorCode = stream->write(&faceLodSize, sizeof(faceLodSize), 1, stream->src);+ if (errorCode != KTX_SUCCESS)+ goto cleanup;++ for (face = 0; face < header.numberOfFaces; ++face, ++i) {+ if (!compressed) {+ /* Sanity check. */+ if (images[i].size != expectedFaceSize) {+ errorCode = KTX_INVALID_OPERATION;+ goto cleanup;+ }+ }+ if (rowRounding == 0) {+ /* Can write whole face at once */+ errorCode = stream->write(images[i].data, faceLodSize, 1, stream->src);+ if (errorCode != KTX_SUCCESS)+ goto cleanup;+ } else {+ /* Write the rows individually, padding each one */+ GLuint row;+ GLuint numRows = pixelHeight+ * pixelDepth+ * numArrayElements;+ for (row = 0; row < numRows; row++) {+ errorCode = stream->write(&images[i].data[row*packedRowBytes], packedRowBytes, 1, stream->src);+ if (errorCode != KTX_SUCCESS)+ goto cleanup;++ errorCode = stream->write(pad, sizeof(GLbyte), rowRounding, stream->src);+ if (errorCode != KTX_SUCCESS)+ goto cleanup;+ }+ }+ if (faceLodRounding) {+ errorCode = stream->write(pad, sizeof(GLbyte), faceLodRounding, stream->src);+ if (errorCode != KTX_SUCCESS)+ goto cleanup;+ }+ }+ }++cleanup:+ return errorCode;+}++/**+ * @~English+ * @brief Write image(s) in a KTX-formatted stdio FILE stream.+ *+ * @param [in] file pointer to the FILE stream to write to.+ * @param [in] textureInfo pointer to a KTX_image_info structure providing+ * information about the images to be included in+ * the KTX file.+ * @param [in] bytesOfKeyValueData+ * specifies the number of bytes of key-value data.+ * @param [in] keyValueData a pointer to the keyValue data.+ * @param [in] numImages number of images in the following array+ * @param [in] images array of KTX_image_info providing image size and+ * data.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_INVALID_VALUE @p dst or @p target are @c NULL+ * @exception KTX_INVALID_VALUE @c glTypeSize in @p textureInfo is not 1, 2, or 4 or+ * is different from the size of the type specified+ * in @c glType.+ * @exception KTX_INVALID_VALUE @c pixelWidth in @p textureInfo is 0 or pixelDepth != 0+ * && pixelHeight == 0.+ * @exception KTX_INVALID_VALUE @c numberOfFaces != 1 || numberOfFaces != 6 or+ * numberOfArrayElements or numberOfMipmapLevels are < 0.+ * @exception KTX_INVALID_VALUE @c glType in @p textureInfo is an unrecognized type.+ * @exception KTX_INVALID_OPERATION+ * numberOfFaces == 6 and images are either not 2D or+ * are not square.+ * @exception KTX_INVALID_OPERATION+ * number of images is insufficient for the specified+ * number of mipmap levels and faces.+ * @exception KTX_INVALID_OPERATION+ * the size of a provided image is different than that+ * required for the specified width, height or depth+ * or for the mipmap level being processed.+ * @exception KTX_INVALID_OPERATION+ * @c glType and @c glFormat in @p textureInfo are mismatched.+ * See OpenGL 4.4 specification section 8.4.4 and+ * table 8.5.+ * @exception KTX_FILE_WRITE_ERROR a system error occurred while writing the file.+ */+KTX_error_code+ktxWriteKTXF(FILE *file, const KTX_texture_info* textureInfo,+ GLsizei bytesOfKeyValueData, const void* keyValueData,+ GLuint numImages, KTX_image_info images[])+{+ struct ktxStream stream;+ KTX_error_code errorCode = KTX_SUCCESS;++ errorCode = ktxFileInit(&stream, file);+ if (errorCode != KTX_SUCCESS)+ return errorCode;++ return ktxWriteKTXS(&stream, textureInfo, bytesOfKeyValueData, keyValueData, numImages, images);+}++/**+ * @~English+ * @brief Write image(s) to a KTX file on disk.+ *+ * @param [in] dstname pointer to a C string that contains the path of+ * the file to load.+ * @param [in] textureInfo pointer to a KTX_image_info structure providing+ * information about the images to be included in+ * the KTX file.+ * @param [in] bytesOfKeyValueData+ * specifies the number of bytes of key-value data.+ * @param [in] keyValueData a pointer to the keyValue data.+ * @param [in] numImages number of images in the following array.+ * @param [in] images array of KTX_image_info providing image size and+ * data.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ * @exception KTX_FILE_OPEN_FAILED unable to open the specified file for+ * writing.+ *+ * For other exceptions, see ktxWriteKTXF().+ */+KTX_error_code+ktxWriteKTXN(const char* dstname, const KTX_texture_info* textureInfo,+ GLsizei bytesOfKeyValueData, const void* keyValueData,+ GLuint numImages, KTX_image_info images[])+{+ KTX_error_code errorCode;+ FILE* dst = fopen(dstname, "wb");++ if (dst) {+ errorCode = ktxWriteKTXF(dst, textureInfo, bytesOfKeyValueData, keyValueData,+ numImages, images);+ fclose(dst);+ } else+ errorCode = KTX_FILE_OPEN_FAILED;++ return errorCode;+}++/**+ * @~English+ * @brief Write image(s) in KTX format to memory.+ *+ * @param [out] bytes pointer to the output with KTX data. Application+ is responsible for freeing that memory.+ * @param [out] size pointer to store size of the memory written.+ * @param [in] textureInfo pointer to a KTX_image_info structure providing+ * information about the images to be included in+ * the KTX file.+ * @param [in] bytesOfKeyValueData+ * specifies the number of bytes of key-value data.+ * @param [in] keyValueData a pointer to the keyValue data.+ * @param [in] numImages number of images in the following array.+ * @param [in] images array of KTX_image_info providing image size and+ * data.+ *+ * @return KTX_SUCCESS on success, other KTX_* enum values on error.+ *+ */+KTX_error_code+ktxWriteKTXM(unsigned char** bytes, GLsizei* size, const KTX_texture_info* textureInfo,+ GLsizei bytesOfKeyValueData, const void* keyValueData,+ GLuint numImages, KTX_image_info images[])+{+ struct ktxMem mem;+ struct ktxStream stream;+ KTX_error_code rc;++ *bytes = NULL;++ rc = ktxMemInit(&stream, &mem, NULL, 0);+ if (rc != KTX_SUCCESS)+ return rc;++ rc = ktxWriteKTXS(&stream, textureInfo, bytesOfKeyValueData, keyValueData, numImages, images);+ if(rc != KTX_SUCCESS)+ {+ if(mem.bytes)+ {+ free(mem.bytes);+ }+ return rc;+ }++ *bytes = mem.bytes;+ *size = mem.used_size;+ return KTX_SUCCESS;+}++/*+ * @brief Check format and type matching as required by OpenGL.+ *+ * @param [in] format the format of the image data+ * @param [in] type the type of the image data+ *+ * @return KTX_SUCCESS if matched, KTX_INVALID_OPERATION, if mismatched+ * or KTX_INVALID_VALUE if @p type is invalid.+ */+static KTX_error_code+validateTypeAndFormat(GLenum format, GLenum type)+{+ KTX_error_code retVal = KTX_SUCCESS;++ if ((format >= GL_RED_INTEGER && format <= GL_BGRA_INTEGER) && (type == GL_FLOAT || type == GL_HALF_FLOAT))+ {+ retVal = KTX_INVALID_OPERATION; // Note: OpenGL 4.4 says GL_INVALID_VALUE but we'll mirror the others.+ }++ switch (type)+ {+ case GL_UNSIGNED_BYTE_3_3_2:+ case GL_UNSIGNED_BYTE_2_3_3_REV:+ if (format != GL_RGB && format != GL_RGB_INTEGER)+ retVal = KTX_INVALID_OPERATION; // Matches OpenGL 4.4+ break;++ case GL_UNSIGNED_SHORT_5_6_5:+ case GL_UNSIGNED_SHORT_5_6_5_REV:+ if (format != GL_RGB && format != GL_RGB_INTEGER)+ retVal = KTX_INVALID_OPERATION;+ break;++ case GL_UNSIGNED_SHORT_4_4_4_4:+ case GL_UNSIGNED_SHORT_5_5_5_1:+ case GL_UNSIGNED_SHORT_4_4_4_4_REV:+ case GL_UNSIGNED_SHORT_1_5_5_5_REV:+ if (format != GL_RGBA && format != GL_BGRA+ && format != GL_RGBA_INTEGER && format != GL_BGRA_INTEGER)+ {+ retVal = KTX_INVALID_OPERATION;+ }+ break;++ case GL_UNSIGNED_INT_8_8_8_8:+ case GL_UNSIGNED_INT_8_8_8_8_REV:+ case GL_UNSIGNED_INT_10_10_10_2:+ case GL_UNSIGNED_INT_2_10_10_10_REV:+ if (format != GL_RGBA && format != GL_BGRA+ && format != GL_RGBA_INTEGER && format != GL_BGRA_INTEGER)+ {+ retVal = KTX_INVALID_OPERATION;+ }+ break;++ case GL_UNSIGNED_INT_24_8:+ if (format != GL_DEPTH_STENCIL)+ retVal = KTX_INVALID_OPERATION;+ break;++ case GL_UNSIGNED_INT_10F_11F_11F_REV:+ case GL_UNSIGNED_INT_5_9_9_9_REV:+ if (format != GL_RGB && format != GL_BGR)+ retVal = KTX_INVALID_OPERATION;+ break;++ case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:+ // Note: OpenGL 4.4 says GL_INVALID_VALUE in one place,+ // GL_INVALID_OPERATION in another. The latter is more logical.+ retVal = KTX_INVALID_OPERATION;++ default:+ retVal = KTX_INVALID_VALUE;+ }++ return retVal;+}+++/*+ * @brief Get the size of the group of elements constituting a pixel in+ * the given @p type and @p format and the size of an element.+ *+ * Sizes are returned in basic machine units (bytes). The function also+ * indicates if @type is a packed pixel format.+ *+ * @param [in] format the format of the image data+ * @param [in] type the type of the image data+ * @param [out] groupBytes pointer to location where to write the size of a group+ * @param [out] size pointer to location where to write the size of an element+ * @param [out] packed pointer to location where to write flag indicating+ * if the type is a packed type.+ *+ * @return KTX_INVALID_VALUE if the @p type or @p format is invalid.+ */+static KTX_error_code+sizeofGroupAndElement(GLenum format, GLenum type, GLuint* groupBytes,+ GLuint* elementBytes, GLboolean* packed)+{+ KTX_error_code retVal;++ if ((retVal = sizeofGLtype(type, elementBytes, packed)) != KTX_SUCCESS)+ {+ return retVal;+ }++ if (*packed)+ {+ *groupBytes = *elementBytes;+ return retVal;+ }++ switch (format) {+ case GL_ALPHA:+ case GL_RED:+ case GL_GREEN:+ case GL_BLUE:+ case GL_LUMINANCE: /* deprecated but needed for ES 1 & 2 */+ case GL_ALPHA_INTEGER:+ case GL_RED_INTEGER:+ case GL_GREEN_INTEGER:+ case GL_BLUE_INTEGER:+ /* case GL_LUMINANCE_INTEGER: deprecated */+ *groupBytes = *elementBytes;+ break;+ case GL_LUMINANCE_ALPHA:+ case GL_RG:+ /* case GL_LUMINANCE_ALPHA_INTEGER: deprecated */+ case GL_RG_INTEGER:+ *groupBytes = *elementBytes * 2;+ break;+ case GL_RGB:+ case GL_BGR:+ case GL_RGB_INTEGER:+ case GL_BGR_INTEGER:+ *groupBytes = *elementBytes * 3;+ break;+ case GL_RGBA:+ case GL_BGRA:+ case GL_RGBA_INTEGER:+ case GL_BGRA_INTEGER:+ *groupBytes = *elementBytes * 4;+ break;+ default:+ retVal = KTX_INVALID_VALUE;+ }++ return retVal;+}++/*+ * @brief Get the size of a GL type in basic machine units+ * and indicate whether or not it is a packed type.+ *+ * @param [in] type the type whose size is to be returned.+ * @param [out] size pointer to location where to write the size+ * @param [out] packed pointer to location where to write flag indicating+ * if the type is a packed type.+ *+ * @return KTX_INVALID_VALUE if the @p type is unrecognized.+ */+static KTX_error_code+sizeofGLtype(GLenum type, GLuint* size, GLboolean* packed)+{+ assert(packed && size);+ *packed = GL_FALSE;++ switch (type) {+ case GL_BYTE:+ *size = sizeof(GLbyte);+ break;++ case GL_UNSIGNED_BYTE:+ *size = sizeof(GLubyte);+ break;++ case GL_UNSIGNED_BYTE_3_3_2:+ case GL_UNSIGNED_BYTE_2_3_3_REV:+ *packed = GL_TRUE;+ *size = sizeof(GLubyte);+ break;++ case GL_SHORT:+ *size = sizeof(GLshort);+ break;++ case GL_UNSIGNED_SHORT:+ *size = sizeof(GLushort);+ break;++ case GL_UNSIGNED_SHORT_5_6_5:+ case GL_UNSIGNED_SHORT_4_4_4_4:+ case GL_UNSIGNED_SHORT_5_5_5_1:+ case GL_UNSIGNED_SHORT_5_6_5_REV:+ case GL_UNSIGNED_SHORT_4_4_4_4_REV:+ case GL_UNSIGNED_SHORT_1_5_5_5_REV:+ *packed = GL_TRUE;+ *size = sizeof(GLushort);+ break;++ case GL_INT:+ *size = sizeof(GLint);+ break;++ case GL_UNSIGNED_INT:+ *size = sizeof(GLuint);+ break;++ case GL_UNSIGNED_INT_8_8_8_8:+ case GL_UNSIGNED_INT_8_8_8_8_REV:+ case GL_UNSIGNED_INT_10_10_10_2:+ case GL_UNSIGNED_INT_2_10_10_10_REV:+ case GL_UNSIGNED_INT_24_8:+ case GL_UNSIGNED_INT_10F_11F_11F_REV:+ case GL_UNSIGNED_INT_5_9_9_9_REV:+ *packed = GL_TRUE;+ *size = sizeof(GLuint);+ break;++ case GL_HALF_FLOAT:+ *size = sizeof(GLhalf);+ break;++ case GL_FLOAT:+ *size = sizeof(GLfloat);+ break;++ case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:+ *packed = GL_TRUE;+ *size = sizeof(GLfloat) + sizeof(GLint);+ break;++ default:+ return KTX_INVALID_VALUE;+ }+ return KTX_SUCCESS;+}
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) [year] [fullname]++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ ktx.cabal view
@@ -0,0 +1,68 @@+name: ktx+version: 0.1+cabal-version: >= 1.10+build-type: Simple+license: MIT+license-file: LICENSE+copyright: 2015 David McFarland+author: David McFarland <corngood@gmail.com>+maintainer: David McFarland <corngood@gmail.com>+stability: alpha+homepage: https://github.com/corngood/ktx+bug-reports: https://github.com/corngood/ktx/issues+synopsis: A binding for libktx from Khronos+description:+ Allows ktx format textures to be loaded into an OpenGL context.++ libktx is included as a submodule and compiled with 'c-sources'.+category: Graphics+extra-source-files:+ KTX/LICENSING.md+ KTX/include/*.h+ KTX/lib/*.h++source-repository head+ type: git+ location: https://github.com/corngood/ktx.git++flag dev+ manual: True+ default: False++library+ exposed-modules:+ Graphics.Rendering.KTX+ hs-source-dirs:+ src+ default-language:+ Haskell2010+ build-depends:+ base >= 3 && < 5,+ OpenGL >= 2.9 && < 3+ ghc-options:+ -Wall+ -fno-warn-unused-do-bind+ -fno-warn-name-shadowing+ if flag(dev)+ ghc-options: -Werror+ c-sources:+ KTX/lib/checkheader.c+ KTX/lib/errstr.c+ KTX/lib/hashtable.c+ KTX/lib/ktxfilestream.c+ KTX/lib/ktxmemstream.c+ KTX/lib/loader.c+ KTX/lib/swap.c+ KTX/lib/writer.c+ KTX/lib/etcdec.cxx+ KTX/lib/etcunpack.cxx+ pkgconfig-depends:+ glew,+ egl+ include-dirs:+ KTX/include+ cc-options:+ -fPIC+ -DKTX_OPENGL=1+ -DKTX_USE_GETPROC=1+ -Wno-unused-result
+ src/Graphics/Rendering/KTX.hsc view
@@ -0,0 +1,64 @@+{-# Language DeriveDataTypeable #-}++module Graphics.Rendering.KTX+ ( ErrorCode+ , Dimensions(..)+ , initContext+ , loadTextureN+ ) where++import Control.Exception (Exception, throwIO)+import Data.Typeable (Typeable)+import Data.Word (Word32)+-- constructors were not exported until here+#if MIN_VERSION_base(4,5,0)+import Foreign.C.Types (CUInt(CUInt))+#else+import Foreign.C.Types (CUInt)+#endif+import Foreign.C.Types (CUChar)+import Foreign.C.String (CString, withCString)+import Foreign.Storable (peek)+import Foreign.Marshal.Utils (with)+import Foreign.Ptr (Ptr, nullPtr)+import Graphics.Rendering.OpenGL (GLsizei, GLenum, GLuint, GLboolean, TextureObject(TextureObject))++#include <ktx.h>++type ErrorCode = (#type KTX_error_code)+data Dimensions = Dimensions GLsizei GLsizei GLsizei++foreign import ccall "GL/glew.h glewInit" glewInit :: IO GLenum++foreign import ccall "ktx.h ktxLoadTextureN" ktxLoadTextureN+ :: CString+ -> Ptr GLuint+ -> Ptr GLenum+ -> Ptr Dimensions+ -> Ptr GLboolean+ -> Ptr GLenum+ -> Ptr CUInt+ -> Ptr (Ptr CUChar)+ -> IO ErrorCode++data GLEWException = GLEWException GLenum deriving (Eq, Ord, Typeable, Show)+instance Exception GLEWException++data KTXException = KTXException ErrorCode deriving (Eq, Ord, Typeable, Show)+instance Exception KTXException++initContext :: IO ()+initContext = do+ e <- glewInit+ case e of+ 0 -> return ()+ _ -> throwIO (GLEWException e)++loadTextureN :: FilePath -> IO TextureObject+loadTextureN path = withCString path $ \pathStr -> do+ with 0 $ \texPtr -> with 0 $ \bindingPtr -> do+ e <- ktxLoadTextureN pathStr texPtr bindingPtr nullPtr nullPtr nullPtr nullPtr nullPtr+ t <- peek texPtr+ case e of+ 0 -> return $ TextureObject t+ _ -> throwIO $ KTXException e