packages feed

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 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 &copy; & &trade; 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&reg; and OpenGL&reg; 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&ouml;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