Apply the Apache 2.0 license.

Change-Id: I4a7aeefedcd2d891093520d5a10ebefadcddb5be
Reviewed-on: https://swiftshader-review.googlesource.com/5320
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/Renderer/ETC_Decoder.cpp b/src/Renderer/ETC_Decoder.cpp
index 6d98aa2..8e109f3 100644
--- a/src/Renderer/ETC_Decoder.cpp
+++ b/src/Renderer/ETC_Decoder.cpp
@@ -1,709 +1,712 @@
-// SwiftShader Software Renderer

-//

-// Copyright(c) 2015 Google Inc.

-//

-// All rights reserved. No part of this software may be copied, distributed, transmitted,

-// transcribed, stored in a retrieval system, translated into any human or computer

-// language by any means, or disclosed to third parties without the explicit written

-// agreement of Google Inc. Without such an agreement, no rights or licenses, express

-// or implied, including but not limited to any patent rights, are granted to you.

-//

-

-#include "ETC_Decoder.hpp"

-

-namespace

-{

-	inline int clampByte(int value)

-	{

-		return (value < 0) ? 0 : ((value > 255) ? 255 : value);

-	}

-

-	inline int clampSByte(int value)

-	{

-		return (value < -128) ? -128 : ((value > 127) ? 127 : value);

-	}

-

-	struct bgra8

-	{

-		unsigned char b;

-		unsigned char g;

-		unsigned char r;

-		unsigned char a;

-

-		inline bgra8()

-		{

-		}

-

-		inline void set(int red, int green, int blue)

-		{

-			r = static_cast<unsigned char>(clampByte(red));

-			g = static_cast<unsigned char>(clampByte(green));

-			b = static_cast<unsigned char>(clampByte(blue));

-		}

-

-		inline void set(int red, int green, int blue, int alpha)

-		{

-			r = static_cast<unsigned char>(clampByte(red));

-			g = static_cast<unsigned char>(clampByte(green));

-			b = static_cast<unsigned char>(clampByte(blue));

-			a = static_cast<unsigned char>(clampByte(alpha));

-		}

-

-		const bgra8& addA(int alpha)

-		{

-			a = alpha;

-			return *this;

-		}

-	};

-

-	inline int extend_4to8bits(int x)

-	{

-		return (x << 4) | x;

-	}

-

-	inline int extend_5to8bits(int x)

-	{

-		return (x << 3) | (x >> 2);

-	}

-

-	inline int extend_6to8bits(int x)

-	{

-		return (x << 2) | (x >> 4);

-	}

-

-	inline int extend_7to8bits(int x)

-	{

-		return (x << 1) | (x >> 6);

-	}

-

-	struct ETC2

-	{

-		// Decodes unsigned single or dual channel block to bytes

-		static void DecodeBlock(const ETC2** sources, unsigned char *dest, int nbChannels, int x, int y, int w, int h, int pitch, bool isSigned)

-		{

-			if(isSigned)

-			{

-				signed char* sDst = reinterpret_cast<signed char*>(dest);

-				for(int j = 0; j < 4 && (y + j) < h; j++)

-				{

-					for(int i = 0; i < 4 && (x + i) < w; i++)

-					{

-						for(int c = nbChannels - 1; c >= 0; c--)

-						{

-							sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned));

-						}

-					}

-					sDst += pitch;

-				}

-			}

-			else

-			{

-				for(int j = 0; j < 4 && (y + j) < h; j++)

-				{

-					for(int i = 0; i < 4 && (x + i) < w; i++)

-					{

-						for(int c = nbChannels - 1; c >= 0; c--)

-						{

-							dest[i * nbChannels + c] = clampByte(sources[c]->getSingleChannel(i, j, isSigned));

-						}

-					}

-					dest += pitch;

-				}

-			}

-		}

-

-		// Decodes RGB block to bgra8

-		void decodeBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool punchThroughAlpha) const

-		{

-			bool opaqueBit = diffbit;

-			bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;

-

-			// Select mode

-			if(diffbit || punchThroughAlpha)

-			{

-				int r = (R + dR);

-				int g = (G + dG);

-				int b = (B + dB);

-				if(r < 0 || r > 31)

-				{

-					decodeTBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);

-				}

-				else if(g < 0 || g > 31)

-				{

-					decodeHBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);

-				}

-				else if(b < 0 || b > 31)

-				{

-					decodePlanarBlock(dest, x, y, w, h, pitch, alphaValues);

-				}

-				else

-				{

-					decodeDifferentialBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);

-				}

-			}

-			else

-			{

-				decodeIndividualBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);

-			}

-		}

-

-	private:

-		struct

-		{

-			union

-			{

-				// Individual, differential, H and T modes

-				struct

-				{

-					union

-					{

-						// Individual and differential modes

-						struct

-						{

-							union

-							{

-								struct   // Individual colors

-								{

-									unsigned char R2 : 4;

-									unsigned char R1 : 4;

-									unsigned char G2 : 4;

-									unsigned char G1 : 4;

-									unsigned char B2 : 4;

-									unsigned char B1 : 4;

-								};

-

-								struct   // Differential colors

-								{

-									signed char dR : 3;

-									unsigned char R : 5;

-									signed char dG : 3;

-									unsigned char G : 5;

-									signed char dB : 3;

-									unsigned char B : 5;

-								};

-							};

-

-							bool flipbit : 1;

-							bool diffbit : 1;

-							unsigned char cw2 : 3;

-							unsigned char cw1 : 3;

-						};

-

-						// T mode

-						struct

-						{

-							// Byte 1

-							unsigned char TR1b : 2;

-							unsigned char TdummyB : 1;

-							unsigned char TR1a : 2;

-							unsigned char TdummyA : 3;

-

-							// Byte 2

-							unsigned char TB1 : 4;

-							unsigned char TG1 : 4;

-

-							// Byte 3

-							unsigned char TG2 : 4;

-							unsigned char TR2 : 4;

-

-							// Byte 4

-							unsigned char Tdb : 1;

-							bool Tflipbit : 1;

-							unsigned char Tda : 2;

-							unsigned char TB2 : 4;

-						};

-

-						// H mode

-						struct

-						{

-							// Byte 1

-							unsigned char HG1a : 3;

-							unsigned char HR1 : 4;

-							unsigned char HdummyA : 1;

-

-							// Byte 2

-							unsigned char HB1b : 2;

-							unsigned char HdummyC : 1;

-							unsigned char HB1a : 1;

-							unsigned char HG1b : 1;

-							unsigned char HdummyB : 3;

-

-							// Byte 3

-							unsigned char HG2a : 3;

-							unsigned char HR2 : 4;

-							unsigned char HB1c : 1;

-

-							// Byte 4

-							unsigned char Hdb : 1;

-							bool Hflipbit : 1;

-							unsigned char Hda : 1;

-							unsigned char HB2 : 4;

-							unsigned char HG2b : 1;

-						};

-					};

-

-					unsigned char pixelIndexMSB[2];

-					unsigned char pixelIndexLSB[2];

-				};

-

-				// planar mode

-				struct

-				{

-					// Byte 1

-					unsigned char GO1 : 1;

-					unsigned char RO : 6;

-					unsigned char PdummyA : 1;

-

-					// Byte 2

-					unsigned char BO1 : 1;

-					unsigned char GO2 : 6;

-					unsigned char PdummyB : 1;

-

-					// Byte 3

-					unsigned char BO3a : 2;

-					unsigned char PdummyD : 1;

-					unsigned char BO2 : 2;

-					unsigned char PdummyC : 3;

-

-					// Byte 4

-					unsigned char RH2 : 1;

-					bool Pflipbit : 1;

-					unsigned char RH1 : 5;

-					unsigned char BO3b : 1;

-

-					// Byte 5

-					unsigned char BHa : 1;

-					unsigned char GH : 7;

-

-					// Byte 6

-					unsigned char RVa : 3;

-					unsigned char BHb : 5;

-

-					// Byte 7

-					unsigned char GVa : 5;

-					unsigned char RVb : 3;

-

-					// Byte 8

-					unsigned char BV : 6;

-					unsigned char GVb : 2;

-				};

-

-				// Single channel block

-				struct

-				{

-					union

-					{

-						unsigned char base_codeword;

-						signed char signed_base_codeword;

-					};

-

-					unsigned char table_index : 4;

-					unsigned char multiplier : 4;

-

-					unsigned char mc1 : 2;

-					unsigned char mb : 3;

-					unsigned char ma : 3;

-

-					unsigned char mf1 : 1;

-					unsigned char me : 3;

-					unsigned char md : 3;

-					unsigned char mc2 : 1;

-

-					unsigned char mh : 3;

-					unsigned char mg : 3;

-					unsigned char mf2 : 2;

-

-					unsigned char mk1 : 2;

-					unsigned char mj : 3;

-					unsigned char mi : 3;

-

-					unsigned char mn1 : 1;

-					unsigned char mm : 3;

-					unsigned char ml : 3;

-					unsigned char mk2 : 1;

-

-					unsigned char mp : 3;

-					unsigned char mo : 3;

-					unsigned char mn2 : 2;

-				};

-			};

-		};

-

-		void decodeIndividualBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const

-		{

-			int r1 = extend_4to8bits(R1);

-			int g1 = extend_4to8bits(G1);

-			int b1 = extend_4to8bits(B1);

-

-			int r2 = extend_4to8bits(R2);

-			int g2 = extend_4to8bits(G2);

-			int b2 = extend_4to8bits(B2);

-

-			decodeIndividualOrDifferentialBlock(dest, x, y, w, h, pitch, r1, g1, b1, r2, g2, b2, alphaValues, nonOpaquePunchThroughAlpha);

-		}

-

-		void decodeDifferentialBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const

-		{

-			int b1 = extend_5to8bits(B);

-			int g1 = extend_5to8bits(G);

-			int r1 = extend_5to8bits(R);

-

-			int r2 = extend_5to8bits(R + dR);

-			int g2 = extend_5to8bits(G + dG);

-			int b2 = extend_5to8bits(B + dB);

-

-			decodeIndividualOrDifferentialBlock(dest, x, y, w, h, pitch, r1, g1, b1, r2, g2, b2, alphaValues, nonOpaquePunchThroughAlpha);

-		}

-

-		void decodeIndividualOrDifferentialBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, int r1, int g1, int b1, int r2, int g2, int b2, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const

-		{

-			// Table 3.17.2 sorted according to table 3.17.3

-			static const int intensityModifierDefault[8][4] =

-			{

-				{ 2, 8, -2, -8 },

-				{ 5, 17, -5, -17 },

-				{ 9, 29, -9, -29 },

-				{ 13, 42, -13, -42 },

-				{ 18, 60, -18, -60 },

-				{ 24, 80, -24, -80 },

-				{ 33, 106, -33, -106 },

-				{ 47, 183, -47, -183 }

-			};

-

-			// Table C.12, intensity modifier for non opaque punchthrough alpha

-			static const int intensityModifierNonOpaque[8][4] =

-			{

-				{ 0, 8, 0, -8 },

-				{ 0, 17, 0, -17 },

-				{ 0, 29, 0, -29 },

-				{ 0, 42, 0, -42 },

-				{ 0, 60, 0, -60 },

-				{ 0, 80, 0, -80 },

-				{ 0, 106, 0, -106 },

-				{ 0, 183, 0, -183 }

-			};

-

-			const int(&intensityModifier)[8][4] = nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;

-

-			bgra8 subblockColors0[4];

-			bgra8 subblockColors1[4];

-

-			const int i10 = intensityModifier[cw1][0];

-			const int i11 = intensityModifier[cw1][1];

-			const int i12 = intensityModifier[cw1][2];

-			const int i13 = intensityModifier[cw1][3];

-

-			subblockColors0[0].set(r1 + i10, g1 + i10, b1 + i10);

-			subblockColors0[1].set(r1 + i11, g1 + i11, b1 + i11);

-			subblockColors0[2].set(r1 + i12, g1 + i12, b1 + i12);

-			subblockColors0[3].set(r1 + i13, g1 + i13, b1 + i13);

-

-			const int i20 = intensityModifier[cw2][0];

-			const int i21 = intensityModifier[cw2][1];

-			const int i22 = intensityModifier[cw2][2];

-			const int i23 = intensityModifier[cw2][3];

-

-			subblockColors1[0].set(r2 + i20, g2 + i20, b2 + i20);

-			subblockColors1[1].set(r2 + i21, g2 + i21, b2 + i21);

-			subblockColors1[2].set(r2 + i22, g2 + i22, b2 + i22);

-			subblockColors1[3].set(r2 + i23, g2 + i23, b2 + i23);

-

-			unsigned char* destStart = dest;

-

-			if(flipbit)

-			{

-				for(int j = 0; j < 2 && (y + j) < h; j++)

-				{

-					bgra8* color = (bgra8*)dest;

-					if((x + 0) < w) color[0] = subblockColors0[getIndex(0, j)].addA(alphaValues[j][0]);

-					if((x + 1) < w) color[1] = subblockColors0[getIndex(1, j)].addA(alphaValues[j][1]);

-					if((x + 2) < w) color[2] = subblockColors0[getIndex(2, j)].addA(alphaValues[j][2]);

-					if((x + 3) < w) color[3] = subblockColors0[getIndex(3, j)].addA(alphaValues[j][3]);

-					dest += pitch;

-				}

-

-				for(int j = 2; j < 4 && (y + j) < h; j++)

-				{

-					bgra8* color = (bgra8*)dest;

-					if((x + 0) < w) color[0] = subblockColors1[getIndex(0, j)].addA(alphaValues[j][0]);

-					if((x + 1) < w) color[1] = subblockColors1[getIndex(1, j)].addA(alphaValues[j][1]);

-					if((x + 2) < w) color[2] = subblockColors1[getIndex(2, j)].addA(alphaValues[j][2]);

-					if((x + 3) < w) color[3] = subblockColors1[getIndex(3, j)].addA(alphaValues[j][3]);

-					dest += pitch;

-				}

-			}

-			else

-			{

-				for(int j = 0; j < 4 && (y + j) < h; j++)

-				{

-					bgra8* color = (bgra8*)dest;

-					if((x + 0) < w) color[0] = subblockColors0[getIndex(0, j)].addA(alphaValues[j][0]);

-					if((x + 1) < w) color[1] = subblockColors0[getIndex(1, j)].addA(alphaValues[j][1]);

-					if((x + 2) < w) color[2] = subblockColors1[getIndex(2, j)].addA(alphaValues[j][2]);

-					if((x + 3) < w) color[3] = subblockColors1[getIndex(3, j)].addA(alphaValues[j][3]);

-					dest += pitch;

-				}

-			}

-

-			if(nonOpaquePunchThroughAlpha)

-			{

-				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);

-			}

-		}

-

-		void decodeTBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const

-		{

-			// Table C.8, distance index fot T and H modes

-			static const int distance[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };

-

-			bgra8 paintColors[4];

-

-			int r1 = extend_4to8bits(TR1a << 2 | TR1b);

-			int g1 = extend_4to8bits(TG1);

-			int b1 = extend_4to8bits(TB1);

-

-			int r2 = extend_4to8bits(TR2);

-			int g2 = extend_4to8bits(TG2);

-			int b2 = extend_4to8bits(TB2);

-

-			const int d = distance[Tda << 1 | Tdb];

-

-			paintColors[0].set(r1, g1, b1);

-			paintColors[1].set(r2 + d, g2 + d, b2 + d);

-			paintColors[2].set(r2, g2, b2);

-			paintColors[3].set(r2 - d, g2 - d, b2 - d);

-

-			unsigned char* destStart = dest;

-

-			for(int j = 0; j < 4 && (y + j) < h; j++)

-			{

-				bgra8* color = (bgra8*)dest;

-				if((x + 0) < w) color[0] = paintColors[getIndex(0, j)].addA(alphaValues[j][0]);

-				if((x + 1) < w) color[1] = paintColors[getIndex(1, j)].addA(alphaValues[j][1]);

-				if((x + 2) < w) color[2] = paintColors[getIndex(2, j)].addA(alphaValues[j][2]);

-				if((x + 3) < w) color[3] = paintColors[getIndex(3, j)].addA(alphaValues[j][3]);

-				dest += pitch;

-			}

-

-			if(nonOpaquePunchThroughAlpha)

-			{

-				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);

-			}

-		}

-

-		void decodeHBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const

-		{

-			// Table C.8, distance index fot T and H modes

-			static const int distance[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };

-

-			bgra8 paintColors[4];

-

-			int r1 = extend_4to8bits(HR1);

-			int g1 = extend_4to8bits(HG1a << 1 | HG1b);

-			int b1 = extend_4to8bits(HB1a << 3 | HB1b << 1 | HB1c);

-

-			int r2 = extend_4to8bits(HR2);

-			int g2 = extend_4to8bits(HG2a << 1 | HG2b);

-			int b2 = extend_4to8bits(HB2);

-

-			const int d = distance[(Hda << 2) | (Hdb << 1) | ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0)];

-

-			paintColors[0].set(r1 + d, g1 + d, b1 + d);

-			paintColors[1].set(r1 - d, g1 - d, b1 - d);

-			paintColors[2].set(r2 + d, g2 + d, b2 + d);

-			paintColors[3].set(r2 - d, g2 - d, b2 - d);

-

-			unsigned char* destStart = dest;

-

-			for(int j = 0; j < 4 && (y + j) < h; j++)

-			{

-				bgra8* color = (bgra8*)dest;

-				if((x + 0) < w) color[0] = paintColors[getIndex(0, j)].addA(alphaValues[j][0]);

-				if((x + 1) < w) color[1] = paintColors[getIndex(1, j)].addA(alphaValues[j][1]);

-				if((x + 2) < w) color[2] = paintColors[getIndex(2, j)].addA(alphaValues[j][2]);

-				if((x + 3) < w) color[3] = paintColors[getIndex(3, j)].addA(alphaValues[j][3]);

-				dest += pitch;

-			}

-

-			if(nonOpaquePunchThroughAlpha)

-			{

-				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);

-			}

-		}

-

-		void decodePlanarBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4]) const

-		{

-			int ro = extend_6to8bits(RO);

-			int go = extend_7to8bits(GO1 << 6 | GO2);

-			int bo = extend_6to8bits(BO1 << 5 | BO2 << 3 | BO3a << 1 | BO3b);

-

-			int rh = extend_6to8bits(RH1 << 1 | RH2);

-			int gh = extend_7to8bits(GH);

-			int bh = extend_6to8bits(BHa << 5 | BHb);

-

-			int rv = extend_6to8bits(RVa << 3 | RVb);

-			int gv = extend_7to8bits(GVa << 2 | GVb);

-			int bv = extend_6to8bits(BV);

-

-			for(int j = 0; j < 4 && (y + j) < h; j++)

-			{

-				int ry = j * (rv - ro) + 2;

-				int gy = j * (gv - go) + 2;

-				int by = j * (bv - bo) + 2;

-				for(int i = 0; i < 4 && (x + i) < w; i++)

-				{

-					((bgra8*)(dest))[i].set(((i * (rh - ro) + ry) >> 2) + ro,

-						((i * (gh - go) + gy) >> 2) + go,

-						((i * (bh - bo) + by) >> 2) + bo,

-						alphaValues[j][i]);

-				}

-				dest += pitch;

-			}

-		}

-

-		// Index for individual, differential, H and T modes

-		inline int getIndex(int x, int y) const

-		{

-			int bitIndex = x * 4 + y;

-			int bitOffset = bitIndex & 7;

-			int lsb = (pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;

-			int msb = (pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;

-

-			return (msb << 1) | lsb;

-		}

-

-		void decodePunchThroughAlphaBlock(unsigned char *dest, int x, int y, int w, int h, int pitch) const

-		{

-			for(int j = 0; j < 4 && (y + j) < h; j++)

-			{

-				for(int i = 0; i < 4 && (x + i) < w; i++)

-				{

-					if(getIndex(i, j) == 2) //  msb == 1 && lsb == 0

-					{

-						((bgra8*)dest)[i].set(0, 0, 0, 0);

-					}

-				}

-				dest += pitch;

-			}

-		}

-

-		// Single channel utility functions

-		inline int getSingleChannel(int x, int y, bool isSigned) const

-		{

-			int codeword = isSigned ? signed_base_codeword : base_codeword;

-			return codeword + getSingleChannelModifier(x, y) * multiplier;

-		}

-

-		inline int getSingleChannelIndex(int x, int y) const

-		{

-			switch(x * 4 + y)

-			{

-			case 0: return ma;

-			case 1: return mb;

-			case 2: return mc1 << 1 | mc2;

-			case 3: return md;

-			case 4: return me;

-			case 5: return mf1 << 2 | mf2;

-			case 6: return mg;

-			case 7: return mh;

-			case 8: return mi;

-			case 9: return mj;

-			case 10: return mk1 << 1 | mk2;

-			case 11: return ml;

-			case 12: return mm;

-			case 13: return mn1 << 2 | mn2;

-			case 14: return mo;

-			default: return mp; // 15

-			}

-		}

-

-		inline int getSingleChannelModifier(int x, int y) const

-		{

-			static const int modifierTable[16][8] = { { -3, -6, -9, -15, 2, 5, 8, 14 },

-			{ -3, -7, -10, -13, 2, 6, 9, 12 },

-			{ -2, -5, -8, -13, 1, 4, 7, 12 },

-			{ -2, -4, -6, -13, 1, 3, 5, 12 },

-			{ -3, -6, -8, -12, 2, 5, 7, 11 },

-			{ -3, -7, -9, -11, 2, 6, 8, 10 },

-			{ -4, -7, -8, -11, 3, 6, 7, 10 },

-			{ -3, -5, -8, -11, 2, 4, 7, 10 },

-			{ -2, -6, -8, -10, 1, 5, 7, 9 },

-			{ -2, -5, -8, -10, 1, 4, 7, 9 },

-			{ -2, -4, -8, -10, 1, 3, 7, 9 },

-			{ -2, -5, -7, -10, 1, 4, 6, 9 },

-			{ -3, -4, -7, -10, 2, 3, 6, 9 },

-			{ -1, -2, -3, -10, 0, 1, 2, 9 },

-			{ -4, -6, -8, -9, 3, 5, 7, 8 },

-			{ -3, -5, -7, -9, 2, 4, 6, 8 } };

-

-			return modifierTable[table_index][getSingleChannelIndex(x, y)];

-		}

-	};

-}

-

-// Decodes 1 to 4 channel images to 8 bit output

-bool ETC_Decoder::Decode(const unsigned char* src, unsigned char *dst, int w, int h, int dstW, int dstH, int dstPitch, int dstBpp, InputType inputType)

-{

-	const ETC2* sources[2];

-	sources[0] = (const ETC2*)src;

-

-	unsigned char alphaValues[4][4] = { { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } };

-

-	switch(inputType)

-	{

-	case ETC_R_SIGNED:

-	case ETC_R_UNSIGNED:

-		for(int y = 0; y < h; y += 4)

-		{

-			unsigned char *dstRow = dst + (y * dstPitch);

-			for(int x = 0; x < w; x += 4, sources[0]++)

-			{

-				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, dstW, dstH, dstPitch, inputType == ETC_R_SIGNED);

-			}

-		}

-		break;

-	case ETC_RG_SIGNED:

-	case ETC_RG_UNSIGNED:

-		sources[1] = sources[0] + 1;

-		for(int y = 0; y < h; y += 4)

-		{

-			unsigned char *dstRow = dst + (y * dstPitch);

-			for(int x = 0; x < w; x += 4, sources[0] += 2, sources[1] += 2)

-			{

-				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, dstW, dstH, dstPitch, inputType == ETC_RG_SIGNED);

-			}

-		}

-		break;

-	case ETC_RGB:

-	case ETC_RGB_PUNCHTHROUGH_ALPHA:

-		for(int y = 0; y < h; y += 4)

-		{

-			unsigned char *dstRow = dst + (y * dstPitch);

-			for(int x = 0; x < w; x += 4, sources[0]++)

-			{

-				sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, inputType == ETC_RGB_PUNCHTHROUGH_ALPHA);

-			}

-		}

-		break;

-	case ETC_RGBA:

-		for(int y = 0; y < h; y += 4)

-		{

-			unsigned char *dstRow = dst + (y * dstPitch);

-			for(int x = 0; x < w; x += 4)

-			{

-				// Decode Alpha

-				ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, dstW, dstH, 4, false);

-				sources[0]++; // RGBA packets are 128 bits, so move on to the next 64 bit packet to decode the RGB color

-

-				// Decode RGB

-				sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, false);

-				sources[0]++;

-			}

-		}

-		break;

-	default:

-		return false;

-	}

-

-	return true;

-}

+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "ETC_Decoder.hpp"
+
+namespace
+{
+	inline int clampByte(int value)
+	{
+		return (value < 0) ? 0 : ((value > 255) ? 255 : value);
+	}
+
+	inline int clampSByte(int value)
+	{
+		return (value < -128) ? -128 : ((value > 127) ? 127 : value);
+	}
+
+	struct bgra8
+	{
+		unsigned char b;
+		unsigned char g;
+		unsigned char r;
+		unsigned char a;
+
+		inline bgra8()
+		{
+		}
+
+		inline void set(int red, int green, int blue)
+		{
+			r = static_cast<unsigned char>(clampByte(red));
+			g = static_cast<unsigned char>(clampByte(green));
+			b = static_cast<unsigned char>(clampByte(blue));
+		}
+
+		inline void set(int red, int green, int blue, int alpha)
+		{
+			r = static_cast<unsigned char>(clampByte(red));
+			g = static_cast<unsigned char>(clampByte(green));
+			b = static_cast<unsigned char>(clampByte(blue));
+			a = static_cast<unsigned char>(clampByte(alpha));
+		}
+
+		const bgra8& addA(int alpha)
+		{
+			a = alpha;
+			return *this;
+		}
+	};
+
+	inline int extend_4to8bits(int x)
+	{
+		return (x << 4) | x;
+	}
+
+	inline int extend_5to8bits(int x)
+	{
+		return (x << 3) | (x >> 2);
+	}
+
+	inline int extend_6to8bits(int x)
+	{
+		return (x << 2) | (x >> 4);
+	}
+
+	inline int extend_7to8bits(int x)
+	{
+		return (x << 1) | (x >> 6);
+	}
+
+	struct ETC2
+	{
+		// Decodes unsigned single or dual channel block to bytes
+		static void DecodeBlock(const ETC2** sources, unsigned char *dest, int nbChannels, int x, int y, int w, int h, int pitch, bool isSigned)
+		{
+			if(isSigned)
+			{
+				signed char* sDst = reinterpret_cast<signed char*>(dest);
+				for(int j = 0; j < 4 && (y + j) < h; j++)
+				{
+					for(int i = 0; i < 4 && (x + i) < w; i++)
+					{
+						for(int c = nbChannels - 1; c >= 0; c--)
+						{
+							sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned));
+						}
+					}
+					sDst += pitch;
+				}
+			}
+			else
+			{
+				for(int j = 0; j < 4 && (y + j) < h; j++)
+				{
+					for(int i = 0; i < 4 && (x + i) < w; i++)
+					{
+						for(int c = nbChannels - 1; c >= 0; c--)
+						{
+							dest[i * nbChannels + c] = clampByte(sources[c]->getSingleChannel(i, j, isSigned));
+						}
+					}
+					dest += pitch;
+				}
+			}
+		}
+
+		// Decodes RGB block to bgra8
+		void decodeBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool punchThroughAlpha) const
+		{
+			bool opaqueBit = diffbit;
+			bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
+
+			// Select mode
+			if(diffbit || punchThroughAlpha)
+			{
+				int r = (R + dR);
+				int g = (G + dG);
+				int b = (B + dB);
+				if(r < 0 || r > 31)
+				{
+					decodeTBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);
+				}
+				else if(g < 0 || g > 31)
+				{
+					decodeHBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);
+				}
+				else if(b < 0 || b > 31)
+				{
+					decodePlanarBlock(dest, x, y, w, h, pitch, alphaValues);
+				}
+				else
+				{
+					decodeDifferentialBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);
+				}
+			}
+			else
+			{
+				decodeIndividualBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);
+			}
+		}
+
+	private:
+		struct
+		{
+			union
+			{
+				// Individual, differential, H and T modes
+				struct
+				{
+					union
+					{
+						// Individual and differential modes
+						struct
+						{
+							union
+							{
+								struct   // Individual colors
+								{
+									unsigned char R2 : 4;
+									unsigned char R1 : 4;
+									unsigned char G2 : 4;
+									unsigned char G1 : 4;
+									unsigned char B2 : 4;
+									unsigned char B1 : 4;
+								};
+
+								struct   // Differential colors
+								{
+									signed char dR : 3;
+									unsigned char R : 5;
+									signed char dG : 3;
+									unsigned char G : 5;
+									signed char dB : 3;
+									unsigned char B : 5;
+								};
+							};
+
+							bool flipbit : 1;
+							bool diffbit : 1;
+							unsigned char cw2 : 3;
+							unsigned char cw1 : 3;
+						};
+
+						// T mode
+						struct
+						{
+							// Byte 1
+							unsigned char TR1b : 2;
+							unsigned char TdummyB : 1;
+							unsigned char TR1a : 2;
+							unsigned char TdummyA : 3;
+
+							// Byte 2
+							unsigned char TB1 : 4;
+							unsigned char TG1 : 4;
+
+							// Byte 3
+							unsigned char TG2 : 4;
+							unsigned char TR2 : 4;
+
+							// Byte 4
+							unsigned char Tdb : 1;
+							bool Tflipbit : 1;
+							unsigned char Tda : 2;
+							unsigned char TB2 : 4;
+						};
+
+						// H mode
+						struct
+						{
+							// Byte 1
+							unsigned char HG1a : 3;
+							unsigned char HR1 : 4;
+							unsigned char HdummyA : 1;
+
+							// Byte 2
+							unsigned char HB1b : 2;
+							unsigned char HdummyC : 1;
+							unsigned char HB1a : 1;
+							unsigned char HG1b : 1;
+							unsigned char HdummyB : 3;
+
+							// Byte 3
+							unsigned char HG2a : 3;
+							unsigned char HR2 : 4;
+							unsigned char HB1c : 1;
+
+							// Byte 4
+							unsigned char Hdb : 1;
+							bool Hflipbit : 1;
+							unsigned char Hda : 1;
+							unsigned char HB2 : 4;
+							unsigned char HG2b : 1;
+						};
+					};
+
+					unsigned char pixelIndexMSB[2];
+					unsigned char pixelIndexLSB[2];
+				};
+
+				// planar mode
+				struct
+				{
+					// Byte 1
+					unsigned char GO1 : 1;
+					unsigned char RO : 6;
+					unsigned char PdummyA : 1;
+
+					// Byte 2
+					unsigned char BO1 : 1;
+					unsigned char GO2 : 6;
+					unsigned char PdummyB : 1;
+
+					// Byte 3
+					unsigned char BO3a : 2;
+					unsigned char PdummyD : 1;
+					unsigned char BO2 : 2;
+					unsigned char PdummyC : 3;
+
+					// Byte 4
+					unsigned char RH2 : 1;
+					bool Pflipbit : 1;
+					unsigned char RH1 : 5;
+					unsigned char BO3b : 1;
+
+					// Byte 5
+					unsigned char BHa : 1;
+					unsigned char GH : 7;
+
+					// Byte 6
+					unsigned char RVa : 3;
+					unsigned char BHb : 5;
+
+					// Byte 7
+					unsigned char GVa : 5;
+					unsigned char RVb : 3;
+
+					// Byte 8
+					unsigned char BV : 6;
+					unsigned char GVb : 2;
+				};
+
+				// Single channel block
+				struct
+				{
+					union
+					{
+						unsigned char base_codeword;
+						signed char signed_base_codeword;
+					};
+
+					unsigned char table_index : 4;
+					unsigned char multiplier : 4;
+
+					unsigned char mc1 : 2;
+					unsigned char mb : 3;
+					unsigned char ma : 3;
+
+					unsigned char mf1 : 1;
+					unsigned char me : 3;
+					unsigned char md : 3;
+					unsigned char mc2 : 1;
+
+					unsigned char mh : 3;
+					unsigned char mg : 3;
+					unsigned char mf2 : 2;
+
+					unsigned char mk1 : 2;
+					unsigned char mj : 3;
+					unsigned char mi : 3;
+
+					unsigned char mn1 : 1;
+					unsigned char mm : 3;
+					unsigned char ml : 3;
+					unsigned char mk2 : 1;
+
+					unsigned char mp : 3;
+					unsigned char mo : 3;
+					unsigned char mn2 : 2;
+				};
+			};
+		};
+
+		void decodeIndividualBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
+		{
+			int r1 = extend_4to8bits(R1);
+			int g1 = extend_4to8bits(G1);
+			int b1 = extend_4to8bits(B1);
+
+			int r2 = extend_4to8bits(R2);
+			int g2 = extend_4to8bits(G2);
+			int b2 = extend_4to8bits(B2);
+
+			decodeIndividualOrDifferentialBlock(dest, x, y, w, h, pitch, r1, g1, b1, r2, g2, b2, alphaValues, nonOpaquePunchThroughAlpha);
+		}
+
+		void decodeDifferentialBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
+		{
+			int b1 = extend_5to8bits(B);
+			int g1 = extend_5to8bits(G);
+			int r1 = extend_5to8bits(R);
+
+			int r2 = extend_5to8bits(R + dR);
+			int g2 = extend_5to8bits(G + dG);
+			int b2 = extend_5to8bits(B + dB);
+
+			decodeIndividualOrDifferentialBlock(dest, x, y, w, h, pitch, r1, g1, b1, r2, g2, b2, alphaValues, nonOpaquePunchThroughAlpha);
+		}
+
+		void decodeIndividualOrDifferentialBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, int r1, int g1, int b1, int r2, int g2, int b2, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
+		{
+			// Table 3.17.2 sorted according to table 3.17.3
+			static const int intensityModifierDefault[8][4] =
+			{
+				{ 2, 8, -2, -8 },
+				{ 5, 17, -5, -17 },
+				{ 9, 29, -9, -29 },
+				{ 13, 42, -13, -42 },
+				{ 18, 60, -18, -60 },
+				{ 24, 80, -24, -80 },
+				{ 33, 106, -33, -106 },
+				{ 47, 183, -47, -183 }
+			};
+
+			// Table C.12, intensity modifier for non opaque punchthrough alpha
+			static const int intensityModifierNonOpaque[8][4] =
+			{
+				{ 0, 8, 0, -8 },
+				{ 0, 17, 0, -17 },
+				{ 0, 29, 0, -29 },
+				{ 0, 42, 0, -42 },
+				{ 0, 60, 0, -60 },
+				{ 0, 80, 0, -80 },
+				{ 0, 106, 0, -106 },
+				{ 0, 183, 0, -183 }
+			};
+
+			const int(&intensityModifier)[8][4] = nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
+
+			bgra8 subblockColors0[4];
+			bgra8 subblockColors1[4];
+
+			const int i10 = intensityModifier[cw1][0];
+			const int i11 = intensityModifier[cw1][1];
+			const int i12 = intensityModifier[cw1][2];
+			const int i13 = intensityModifier[cw1][3];
+
+			subblockColors0[0].set(r1 + i10, g1 + i10, b1 + i10);
+			subblockColors0[1].set(r1 + i11, g1 + i11, b1 + i11);
+			subblockColors0[2].set(r1 + i12, g1 + i12, b1 + i12);
+			subblockColors0[3].set(r1 + i13, g1 + i13, b1 + i13);
+
+			const int i20 = intensityModifier[cw2][0];
+			const int i21 = intensityModifier[cw2][1];
+			const int i22 = intensityModifier[cw2][2];
+			const int i23 = intensityModifier[cw2][3];
+
+			subblockColors1[0].set(r2 + i20, g2 + i20, b2 + i20);
+			subblockColors1[1].set(r2 + i21, g2 + i21, b2 + i21);
+			subblockColors1[2].set(r2 + i22, g2 + i22, b2 + i22);
+			subblockColors1[3].set(r2 + i23, g2 + i23, b2 + i23);
+
+			unsigned char* destStart = dest;
+
+			if(flipbit)
+			{
+				for(int j = 0; j < 2 && (y + j) < h; j++)
+				{
+					bgra8* color = (bgra8*)dest;
+					if((x + 0) < w) color[0] = subblockColors0[getIndex(0, j)].addA(alphaValues[j][0]);
+					if((x + 1) < w) color[1] = subblockColors0[getIndex(1, j)].addA(alphaValues[j][1]);
+					if((x + 2) < w) color[2] = subblockColors0[getIndex(2, j)].addA(alphaValues[j][2]);
+					if((x + 3) < w) color[3] = subblockColors0[getIndex(3, j)].addA(alphaValues[j][3]);
+					dest += pitch;
+				}
+
+				for(int j = 2; j < 4 && (y + j) < h; j++)
+				{
+					bgra8* color = (bgra8*)dest;
+					if((x + 0) < w) color[0] = subblockColors1[getIndex(0, j)].addA(alphaValues[j][0]);
+					if((x + 1) < w) color[1] = subblockColors1[getIndex(1, j)].addA(alphaValues[j][1]);
+					if((x + 2) < w) color[2] = subblockColors1[getIndex(2, j)].addA(alphaValues[j][2]);
+					if((x + 3) < w) color[3] = subblockColors1[getIndex(3, j)].addA(alphaValues[j][3]);
+					dest += pitch;
+				}
+			}
+			else
+			{
+				for(int j = 0; j < 4 && (y + j) < h; j++)
+				{
+					bgra8* color = (bgra8*)dest;
+					if((x + 0) < w) color[0] = subblockColors0[getIndex(0, j)].addA(alphaValues[j][0]);
+					if((x + 1) < w) color[1] = subblockColors0[getIndex(1, j)].addA(alphaValues[j][1]);
+					if((x + 2) < w) color[2] = subblockColors1[getIndex(2, j)].addA(alphaValues[j][2]);
+					if((x + 3) < w) color[3] = subblockColors1[getIndex(3, j)].addA(alphaValues[j][3]);
+					dest += pitch;
+				}
+			}
+
+			if(nonOpaquePunchThroughAlpha)
+			{
+				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);
+			}
+		}
+
+		void decodeTBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
+		{
+			// Table C.8, distance index fot T and H modes
+			static const int distance[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
+
+			bgra8 paintColors[4];
+
+			int r1 = extend_4to8bits(TR1a << 2 | TR1b);
+			int g1 = extend_4to8bits(TG1);
+			int b1 = extend_4to8bits(TB1);
+
+			int r2 = extend_4to8bits(TR2);
+			int g2 = extend_4to8bits(TG2);
+			int b2 = extend_4to8bits(TB2);
+
+			const int d = distance[Tda << 1 | Tdb];
+
+			paintColors[0].set(r1, g1, b1);
+			paintColors[1].set(r2 + d, g2 + d, b2 + d);
+			paintColors[2].set(r2, g2, b2);
+			paintColors[3].set(r2 - d, g2 - d, b2 - d);
+
+			unsigned char* destStart = dest;
+
+			for(int j = 0; j < 4 && (y + j) < h; j++)
+			{
+				bgra8* color = (bgra8*)dest;
+				if((x + 0) < w) color[0] = paintColors[getIndex(0, j)].addA(alphaValues[j][0]);
+				if((x + 1) < w) color[1] = paintColors[getIndex(1, j)].addA(alphaValues[j][1]);
+				if((x + 2) < w) color[2] = paintColors[getIndex(2, j)].addA(alphaValues[j][2]);
+				if((x + 3) < w) color[3] = paintColors[getIndex(3, j)].addA(alphaValues[j][3]);
+				dest += pitch;
+			}
+
+			if(nonOpaquePunchThroughAlpha)
+			{
+				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);
+			}
+		}
+
+		void decodeHBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
+		{
+			// Table C.8, distance index fot T and H modes
+			static const int distance[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
+
+			bgra8 paintColors[4];
+
+			int r1 = extend_4to8bits(HR1);
+			int g1 = extend_4to8bits(HG1a << 1 | HG1b);
+			int b1 = extend_4to8bits(HB1a << 3 | HB1b << 1 | HB1c);
+
+			int r2 = extend_4to8bits(HR2);
+			int g2 = extend_4to8bits(HG2a << 1 | HG2b);
+			int b2 = extend_4to8bits(HB2);
+
+			const int d = distance[(Hda << 2) | (Hdb << 1) | ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0)];
+
+			paintColors[0].set(r1 + d, g1 + d, b1 + d);
+			paintColors[1].set(r1 - d, g1 - d, b1 - d);
+			paintColors[2].set(r2 + d, g2 + d, b2 + d);
+			paintColors[3].set(r2 - d, g2 - d, b2 - d);
+
+			unsigned char* destStart = dest;
+
+			for(int j = 0; j < 4 && (y + j) < h; j++)
+			{
+				bgra8* color = (bgra8*)dest;
+				if((x + 0) < w) color[0] = paintColors[getIndex(0, j)].addA(alphaValues[j][0]);
+				if((x + 1) < w) color[1] = paintColors[getIndex(1, j)].addA(alphaValues[j][1]);
+				if((x + 2) < w) color[2] = paintColors[getIndex(2, j)].addA(alphaValues[j][2]);
+				if((x + 3) < w) color[3] = paintColors[getIndex(3, j)].addA(alphaValues[j][3]);
+				dest += pitch;
+			}
+
+			if(nonOpaquePunchThroughAlpha)
+			{
+				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);
+			}
+		}
+
+		void decodePlanarBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4]) const
+		{
+			int ro = extend_6to8bits(RO);
+			int go = extend_7to8bits(GO1 << 6 | GO2);
+			int bo = extend_6to8bits(BO1 << 5 | BO2 << 3 | BO3a << 1 | BO3b);
+
+			int rh = extend_6to8bits(RH1 << 1 | RH2);
+			int gh = extend_7to8bits(GH);
+			int bh = extend_6to8bits(BHa << 5 | BHb);
+
+			int rv = extend_6to8bits(RVa << 3 | RVb);
+			int gv = extend_7to8bits(GVa << 2 | GVb);
+			int bv = extend_6to8bits(BV);
+
+			for(int j = 0; j < 4 && (y + j) < h; j++)
+			{
+				int ry = j * (rv - ro) + 2;
+				int gy = j * (gv - go) + 2;
+				int by = j * (bv - bo) + 2;
+				for(int i = 0; i < 4 && (x + i) < w; i++)
+				{
+					((bgra8*)(dest))[i].set(((i * (rh - ro) + ry) >> 2) + ro,
+						((i * (gh - go) + gy) >> 2) + go,
+						((i * (bh - bo) + by) >> 2) + bo,
+						alphaValues[j][i]);
+				}
+				dest += pitch;
+			}
+		}
+
+		// Index for individual, differential, H and T modes
+		inline int getIndex(int x, int y) const
+		{
+			int bitIndex = x * 4 + y;
+			int bitOffset = bitIndex & 7;
+			int lsb = (pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
+			int msb = (pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
+
+			return (msb << 1) | lsb;
+		}
+
+		void decodePunchThroughAlphaBlock(unsigned char *dest, int x, int y, int w, int h, int pitch) const
+		{
+			for(int j = 0; j < 4 && (y + j) < h; j++)
+			{
+				for(int i = 0; i < 4 && (x + i) < w; i++)
+				{
+					if(getIndex(i, j) == 2) //  msb == 1 && lsb == 0
+					{
+						((bgra8*)dest)[i].set(0, 0, 0, 0);
+					}
+				}
+				dest += pitch;
+			}
+		}
+
+		// Single channel utility functions
+		inline int getSingleChannel(int x, int y, bool isSigned) const
+		{
+			int codeword = isSigned ? signed_base_codeword : base_codeword;
+			return codeword + getSingleChannelModifier(x, y) * multiplier;
+		}
+
+		inline int getSingleChannelIndex(int x, int y) const
+		{
+			switch(x * 4 + y)
+			{
+			case 0: return ma;
+			case 1: return mb;
+			case 2: return mc1 << 1 | mc2;
+			case 3: return md;
+			case 4: return me;
+			case 5: return mf1 << 2 | mf2;
+			case 6: return mg;
+			case 7: return mh;
+			case 8: return mi;
+			case 9: return mj;
+			case 10: return mk1 << 1 | mk2;
+			case 11: return ml;
+			case 12: return mm;
+			case 13: return mn1 << 2 | mn2;
+			case 14: return mo;
+			default: return mp; // 15
+			}
+		}
+
+		inline int getSingleChannelModifier(int x, int y) const
+		{
+			static const int modifierTable[16][8] = { { -3, -6, -9, -15, 2, 5, 8, 14 },
+			{ -3, -7, -10, -13, 2, 6, 9, 12 },
+			{ -2, -5, -8, -13, 1, 4, 7, 12 },
+			{ -2, -4, -6, -13, 1, 3, 5, 12 },
+			{ -3, -6, -8, -12, 2, 5, 7, 11 },
+			{ -3, -7, -9, -11, 2, 6, 8, 10 },
+			{ -4, -7, -8, -11, 3, 6, 7, 10 },
+			{ -3, -5, -8, -11, 2, 4, 7, 10 },
+			{ -2, -6, -8, -10, 1, 5, 7, 9 },
+			{ -2, -5, -8, -10, 1, 4, 7, 9 },
+			{ -2, -4, -8, -10, 1, 3, 7, 9 },
+			{ -2, -5, -7, -10, 1, 4, 6, 9 },
+			{ -3, -4, -7, -10, 2, 3, 6, 9 },
+			{ -1, -2, -3, -10, 0, 1, 2, 9 },
+			{ -4, -6, -8, -9, 3, 5, 7, 8 },
+			{ -3, -5, -7, -9, 2, 4, 6, 8 } };
+
+			return modifierTable[table_index][getSingleChannelIndex(x, y)];
+		}
+	};
+}
+
+// Decodes 1 to 4 channel images to 8 bit output
+bool ETC_Decoder::Decode(const unsigned char* src, unsigned char *dst, int w, int h, int dstW, int dstH, int dstPitch, int dstBpp, InputType inputType)
+{
+	const ETC2* sources[2];
+	sources[0] = (const ETC2*)src;
+
+	unsigned char alphaValues[4][4] = { { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } };
+
+	switch(inputType)
+	{
+	case ETC_R_SIGNED:
+	case ETC_R_UNSIGNED:
+		for(int y = 0; y < h; y += 4)
+		{
+			unsigned char *dstRow = dst + (y * dstPitch);
+			for(int x = 0; x < w; x += 4, sources[0]++)
+			{
+				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, dstW, dstH, dstPitch, inputType == ETC_R_SIGNED);
+			}
+		}
+		break;
+	case ETC_RG_SIGNED:
+	case ETC_RG_UNSIGNED:
+		sources[1] = sources[0] + 1;
+		for(int y = 0; y < h; y += 4)
+		{
+			unsigned char *dstRow = dst + (y * dstPitch);
+			for(int x = 0; x < w; x += 4, sources[0] += 2, sources[1] += 2)
+			{
+				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, dstW, dstH, dstPitch, inputType == ETC_RG_SIGNED);
+			}
+		}
+		break;
+	case ETC_RGB:
+	case ETC_RGB_PUNCHTHROUGH_ALPHA:
+		for(int y = 0; y < h; y += 4)
+		{
+			unsigned char *dstRow = dst + (y * dstPitch);
+			for(int x = 0; x < w; x += 4, sources[0]++)
+			{
+				sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, inputType == ETC_RGB_PUNCHTHROUGH_ALPHA);
+			}
+		}
+		break;
+	case ETC_RGBA:
+		for(int y = 0; y < h; y += 4)
+		{
+			unsigned char *dstRow = dst + (y * dstPitch);
+			for(int x = 0; x < w; x += 4)
+			{
+				// Decode Alpha
+				ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, dstW, dstH, 4, false);
+				sources[0]++; // RGBA packets are 128 bits, so move on to the next 64 bit packet to decode the RGB color
+
+				// Decode RGB
+				sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, false);
+				sources[0]++;
+			}
+		}
+		break;
+	default:
+		return false;
+	}
+
+	return true;
+}