Browse Source

Add ETC2 texture support.

sssooonnnggg 6 years ago
parent
commit
7831480e8d

+ 2 - 0
Source/Urho3D/Graphics/Graphics.h

@@ -679,6 +679,8 @@ private:
     bool dxtTextureSupport_{};
     /// ETC1 format support flag.
     bool etcTextureSupport_{};
+    /// ETC2 format support flag.
+    bool etc2TextureSupport_{};
     /// PVRTC formats support flag.
     bool pvrtcTextureSupport_{};
     /// Hardware shadow map depth compare support flag.

+ 8 - 0
Source/Urho3D/Graphics/OpenGL/OGLGraphics.cpp

@@ -2106,6 +2106,12 @@ unsigned Graphics::GetFormat(CompressedFormat format) const
     case CF_ETC1:
         return etcTextureSupport_ ? GL_ETC1_RGB8_OES : 0;
 
+    case CF_ETC2_RGB:
+        return etc2TextureSupport_ ? GL_ETC2_RGB8_OES : 0;
+
+    case CF_ETC2_RGBA:
+        return etc2TextureSupport_ ? GL_ETC2_RGBA8_OES : 0;
+
     case CF_PVRTC_RGB_2BPP:
         return pvrtcTextureSupport_ ? COMPRESSED_RGB_PVRTC_2BPPV1_IMG : 0;
 
@@ -2790,12 +2796,14 @@ void Graphics::CheckFeatureSupport()
     dxtTextureSupport_ = CheckExtension("WEBGL_compressed_texture_s3tc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
     etcTextureSupport_ = CheckExtension("WEBGL_compressed_texture_etc1"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/
     pvrtcTextureSupport_ = CheckExtension("WEBGL_compressed_texture_pvrtc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/
+    etc2TextureSupport_ = gl3Support || CheckExtension("WEBGL_compressed_texture_etc"); // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc/
     // Instancing is in core in WebGL 2, so the extension may not be present anymore. In WebGL 1, find https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
     // TODO: In the distant future, this may break if WebGL 3 is introduced, so either improve the GL_VERSION parsing here, or keep track of which WebGL version we attempted to initialize.
     instancingSupport_ = (strstr((const char *)glGetString(GL_VERSION), "WebGL 2.") != 0) || CheckExtension("ANGLE_instanced_arrays");
 #else
     dxtTextureSupport_ = CheckExtension("EXT_texture_compression_dxt1");
     etcTextureSupport_ = CheckExtension("OES_compressed_ETC1_RGB8_texture");
+    etc2TextureSupport_ = gl3Support || CheckExtension("OES_compressed_ETC2_RGBA8_texture");
     pvrtcTextureSupport_ = CheckExtension("IMG_texture_compression_pvrtc");
 #endif
 

+ 6 - 0
Source/Urho3D/Graphics/OpenGL/OGLGraphicsImpl.h

@@ -51,6 +51,12 @@
 #ifndef GL_ETC1_RGB8_OES
 #define GL_ETC1_RGB8_OES 0x8d64
 #endif
+#ifndef GL_ETC2_RGB8_OES
+#define GL_ETC2_RGB8_OES 0x9274
+#endif
+#ifndef GL_ETC2_RGBA8_OES
+#define GL_ETC2_RGBA8_OES 0x9278
+#endif
 #ifndef COMPRESSED_RGB_PVRTC_4BPPV1_IMG
 #define COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8c00
 #endif

+ 5 - 0
Source/Urho3D/Graphics/OpenGL/OGLTexture.cpp

@@ -182,6 +182,7 @@ bool Texture::IsCompressed() const
 {
     return format_ == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format_ == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
            format_ == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT || format_ == GL_ETC1_RGB8_OES ||
+           format_ == GL_ETC2_RGB8_OES || format_ == GL_ETC2_RGBA8_OES ||
            format_ == COMPRESSED_RGB_PVRTC_4BPPV1_IMG || format_ == COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ||
            format_ == COMPRESSED_RGB_PVRTC_2BPPV1_IMG || format_ == COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
 }
@@ -233,8 +234,12 @@ unsigned Texture::GetRowDataSize(int width) const
         return ((unsigned)(width + 3) >> 2u) * 16;
 
     case GL_ETC1_RGB8_OES:
+    case GL_ETC2_RGB8_OES:
         return ((unsigned)(width + 3) >> 2u) * 8;
 
+    case GL_ETC2_RGBA8_OES:
+        return ((unsigned)(width + 3) >> 2u) * 16;
+
     case COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
     case COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
         return ((unsigned)(width + 3) >> 2u) * 8;

+ 36 - 0
Source/Urho3D/Resource/Decompress.cpp

@@ -23,6 +23,7 @@
 #include "../Precompiled.h"
 
 #include "../Resource/Decompress.h"
+#include "../Resource/DecompressETC2.h"
 
 // DXT decompression based on the Squish library, modified for Urho3D
 
@@ -1071,4 +1072,39 @@ void FlipBlockHorizontal(unsigned char* dest, const unsigned char* src, Compress
     }
 }
 
+// ETC2 decompress
+// references : https://raw.githubusercontent.com/KhronosGroup/KTX-Software/dbfc3ed538cbe0839039fceb09d6c2be8aede67b/lib/etcunpack.cxx
+
+static void readBigEndian4byteWord(uint32_t* pBlock, const unsigned char *s)
+{
+    *pBlock = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+}
+
+void DecompressImageETC2(unsigned char* dstImage, const void* blocks, int width, int height, bool hasAlpha)
+{
+    const int channelCount = hasAlpha ? 4 : 3;
+    unsigned char* src = (unsigned char*)blocks;
+    unsigned int blockPart1, blockPart2;
+
+    memset(dstImage, 0xFF, width * height * 4);
+
+    for (int y = 0; y < height / 4; ++y) 
+    {
+        for (int x = 0; x < width / 4; ++x) 
+        {
+            if (hasAlpha)
+            {
+                decompressBlockAlphaC(src, dstImage + 3, width, height, 4 * x, 4 * y, channelCount);
+                src += 8;
+            }
+
+            readBigEndian4byteWord(&blockPart1, src);
+            src += 4;
+            readBigEndian4byteWord(&blockPart2, src);
+            src += 4;
+            decompressBlockETC2c(blockPart1, blockPart2, dstImage, width, height, 4 * x, 4 * y, 4);
+        }
+    }
+}
+
 }

+ 2 - 0
Source/Urho3D/Resource/Decompress.h

@@ -32,6 +32,8 @@ URHO3D_API void
     DecompressImageDXT(unsigned char* rgba, const void* blocks, int width, int height, int depth, CompressedFormat format);
 /// Decompress an ETC1 compressed image to RGBA.
 URHO3D_API void DecompressImageETC(unsigned char* rgba, const void* blocks, int width, int height);
+/// Decompress an ETC2 compressed image to RGBA.
+URHO3D_API void DecompressImageETC2(unsigned char* dstImage, const void* blocks, int width, int height, bool hasAlpha);
 /// Decompress a PVRTC compressed image to RGBA.
 URHO3D_API void DecompressImagePVRTC(unsigned char* rgba, const void* blocks, int width, int height, CompressedFormat format);
 /// Flip a compressed block vertically.

+ 1876 - 0
Source/Urho3D/Resource/DecompressETC2.cpp

@@ -0,0 +1,1876 @@
+//
+// Copyright (c) 2008-2019 the Urho3D project.
+//
+// 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.
+//
+
+/*
+
+@~English
+@page license License
+
+@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>
+
+#include "DecompressETC2.h"
+
+namespace Urho3D
+{
+
+// 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;
+	// This is to silence -Wunused-result from GCC 4.8+.
+	size_t numitems;
+
+	numitems = fread(&bytes[0], 1, 1, f);
+	numitems = 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;
+	// This is to silence -Wunused-result from GCC 4.8+.
+	size_t numitems;
+
+	numitems = fread(&bytes[0], 1, 1, f);
+	numitems = fread(&bytes[1], 1, 1, f);
+	numitems = fread(&bytes[2], 1, 1, f);
+	numitems = 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)
+{
+	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);
+}
+
+}

+ 40 - 0
Source/Urho3D/Resource/DecompressETC2.h

@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2008-2019 the Urho3D project.
+//
+// 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.
+//
+
+#pragma once
+
+namespace Urho3D
+{
+
+typedef unsigned int uint;
+typedef unsigned char uint8;
+
+void decompressBlockETC2c(uint block_part1, uint block_part2, uint8* img,
+	int width, int height, int startx, int starty, int channels);
+void decompressBlockETC21BitAlphaC(uint block_part1, uint block_part2, uint8* img, uint8* alphaimg,
+	int width, int height, int startx, int starty, int channels);
+void decompressBlockAlphaC(uint8* data, uint8* img,
+	int width, int height, int startx, int starty, int channels);
+void decompressBlockAlpha16bitC(uint8* data, uint8* img,
+	int width, int height, int startx, int starty, int channels);
+
+}

+ 32 - 1
Source/Urho3D/Resource/Image.cpp

@@ -53,6 +53,10 @@
 #define FOURCC_DXT5 (MAKEFOURCC('D','X','T','5'))
 #define FOURCC_DX10 (MAKEFOURCC('D','X','1','0'))
 
+#define FOURCC_ETC1 (MAKEFOURCC('E','T','C','1'))
+#define FOURCC_ETC2 (MAKEFOURCC('E','T','C','2'))
+#define FOURCC_ETC2A (MAKEFOURCC('E','T','2','A'))
+
 static const unsigned DDSCAPS_COMPLEX = 0x00000008U;
 static const unsigned DDSCAPS_TEXTURE = 0x00001000U;
 static const unsigned DDSCAPS_MIPMAP = 0x00400000U;
@@ -229,6 +233,13 @@ bool CompressedLevel::Decompress(unsigned char* dest)
         DecompressImageETC(dest, data_, width_, height_);
         return true;
 
+    case CF_ETC2_RGB:
+        DecompressImageETC2(dest, data_, width_, height_, false);
+        return true;
+    case CF_ETC2_RGBA:
+        DecompressImageETC2(dest, data_, width_, height_, true);
+        return true;
+
     case CF_PVRTC_RGB_2BPP:
     case CF_PVRTC_RGBA_2BPP:
     case CF_PVRTC_RGB_4BPP:
@@ -578,6 +589,16 @@ bool Image::BeginLoad(Deserializer& source)
             components_ = 3;
             break;
 
+        case 0x9274:
+            compressedFormat_ = CF_ETC2_RGB;
+            components_ = 3;
+            break;
+
+        case 0x9278:
+            compressedFormat_ = CF_ETC2_RGBA;
+            components_ = 4;
+            break;
+
         case 0x8c00:
             compressedFormat_ = CF_PVRTC_RGB_4BPP;
             components_ = 3;
@@ -704,6 +725,16 @@ bool Image::BeginLoad(Deserializer& source)
             components_ = 4;
             break;
 
+        case 22:
+            compressedFormat_ = CF_ETC2_RGB;
+            components_ = 3;
+            break;
+
+        case 23:
+            compressedFormat_ = CF_ETC2_RGBA;
+            components_ = 4;
+            break;
+
         default:
             compressedFormat_ = CF_NONE;
             break;
@@ -1989,7 +2020,7 @@ CompressedLevel Image::GetCompressedLevel(unsigned index) const
     }
     else if (compressedFormat_ < CF_PVRTC_RGB_2BPP)
     {
-        level.blockSize_ = (compressedFormat_ == CF_DXT1 || compressedFormat_ == CF_ETC1) ? 8 : 16;
+        level.blockSize_ = (compressedFormat_ == CF_DXT1 || compressedFormat_ == CF_ETC1 || compressedFormat_ == CF_ETC2_RGB) ? 8 : 16;
         unsigned i = 0;
         unsigned offset = 0;
 

+ 2 - 0
Source/Urho3D/Resource/Image.h

@@ -43,6 +43,8 @@ enum CompressedFormat
     CF_DXT3,
     CF_DXT5,
     CF_ETC1,
+    CF_ETC2_RGB,
+    CF_ETC2_RGBA,
     CF_PVRTC_RGB_2BPP,
     CF_PVRTC_RGBA_2BPP,
     CF_PVRTC_RGB_4BPP,