1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "ETC_Decoder.hpp"
16
17namespace
18{
19	inline int clampByte(int value)
20	{
21		return (value < 0) ? 0 : ((value > 255) ? 255 : value);
22	}
23
24	inline int clampSByte(int value)
25	{
26		return (value < -128) ? -128 : ((value > 127) ? 127 : value);
27	}
28
29	inline int clampEAC(int value, bool isSigned)
30	{
31		int min = isSigned ? -1023 : 0;
32		int max = isSigned ? 1023 : 2047;
33		return (value < min) ? min : ((value > max) ? max : value);
34	}
35
36	struct bgra8
37	{
38		unsigned char b;
39		unsigned char g;
40		unsigned char r;
41		unsigned char a;
42
43		inline bgra8()
44		{
45		}
46
47		inline void set(int red, int green, int blue)
48		{
49			r = static_cast<unsigned char>(clampByte(red));
50			g = static_cast<unsigned char>(clampByte(green));
51			b = static_cast<unsigned char>(clampByte(blue));
52		}
53
54		inline void set(int red, int green, int blue, int alpha)
55		{
56			r = static_cast<unsigned char>(clampByte(red));
57			g = static_cast<unsigned char>(clampByte(green));
58			b = static_cast<unsigned char>(clampByte(blue));
59			a = static_cast<unsigned char>(clampByte(alpha));
60		}
61
62		const bgra8& addA(int alpha)
63		{
64			a = alpha;
65			return *this;
66		}
67	};
68
69	inline int extend_4to8bits(int x)
70	{
71		return (x << 4) | x;
72	}
73
74	inline int extend_5to8bits(int x)
75	{
76		return (x << 3) | (x >> 2);
77	}
78
79	inline int extend_6to8bits(int x)
80	{
81		return (x << 2) | (x >> 4);
82	}
83
84	inline int extend_7to8bits(int x)
85	{
86		return (x << 1) | (x >> 6);
87	}
88
89	struct ETC2
90	{
91		// Decodes unsigned single or dual channel block to bytes
92		static void DecodeBlock(const ETC2** sources, unsigned char *dest, int nbChannels, int x, int y, int w, int h, int pitch, bool isSigned, bool isEAC)
93		{
94			if(isEAC)
95			{
96				for(int j = 0; j < 4 && (y + j) < h; j++)
97				{
98					int* sDst = reinterpret_cast<int*>(dest);
99					for(int i = 0; i < 4 && (x + i) < w; i++)
100					{
101						for(int c = nbChannels - 1; c >= 0; c--)
102						{
103							sDst[i * nbChannels + c] = clampEAC(sources[c]->getSingleChannel(i, j, isSigned, true), isSigned);
104						}
105					}
106					dest += pitch;
107				}
108			}
109			else
110			{
111				if(isSigned)
112				{
113					signed char* sDst = reinterpret_cast<signed char*>(dest);
114					for(int j = 0; j < 4 && (y + j) < h; j++)
115					{
116						for(int i = 0; i < 4 && (x + i) < w; i++)
117						{
118							for(int c = nbChannels - 1; c >= 0; c--)
119							{
120								sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned, false));
121							}
122						}
123						sDst += pitch;
124					}
125				}
126				else
127				{
128					for(int j = 0; j < 4 && (y + j) < h; j++)
129					{
130						for(int i = 0; i < 4 && (x + i) < w; i++)
131						{
132							for(int c = nbChannels - 1; c >= 0; c--)
133							{
134								dest[i * nbChannels + c] = clampByte(sources[c]->getSingleChannel(i, j, isSigned, false));
135							}
136						}
137						dest += pitch;
138					}
139				}
140			}
141		}
142
143		// Decodes RGB block to bgra8
144		void decodeBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool punchThroughAlpha) const
145		{
146			bool opaqueBit = diffbit;
147			bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit;
148
149			// Select mode
150			if(diffbit || punchThroughAlpha)
151			{
152				int r = (R + dR);
153				int g = (G + dG);
154				int b = (B + dB);
155				if(r < 0 || r > 31)
156				{
157					decodeTBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);
158				}
159				else if(g < 0 || g > 31)
160				{
161					decodeHBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);
162				}
163				else if(b < 0 || b > 31)
164				{
165					decodePlanarBlock(dest, x, y, w, h, pitch, alphaValues);
166				}
167				else
168				{
169					decodeDifferentialBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);
170				}
171			}
172			else
173			{
174				decodeIndividualBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha);
175			}
176		}
177
178	private:
179		struct
180		{
181			union
182			{
183				// Individual, differential, H and T modes
184				struct
185				{
186					union
187					{
188						// Individual and differential modes
189						struct
190						{
191							union
192							{
193								struct   // Individual colors
194								{
195									unsigned char R2 : 4;
196									unsigned char R1 : 4;
197									unsigned char G2 : 4;
198									unsigned char G1 : 4;
199									unsigned char B2 : 4;
200									unsigned char B1 : 4;
201								};
202
203								struct   // Differential colors
204								{
205									signed char dR : 3;
206									unsigned char R : 5;
207									signed char dG : 3;
208									unsigned char G : 5;
209									signed char dB : 3;
210									unsigned char B : 5;
211								};
212							};
213
214							bool flipbit : 1;
215							bool diffbit : 1;
216							unsigned char cw2 : 3;
217							unsigned char cw1 : 3;
218						};
219
220						// T mode
221						struct
222						{
223							// Byte 1
224							unsigned char TR1b : 2;
225							unsigned char TdummyB : 1;
226							unsigned char TR1a : 2;
227							unsigned char TdummyA : 3;
228
229							// Byte 2
230							unsigned char TB1 : 4;
231							unsigned char TG1 : 4;
232
233							// Byte 3
234							unsigned char TG2 : 4;
235							unsigned char TR2 : 4;
236
237							// Byte 4
238							unsigned char Tdb : 1;
239							bool Tflipbit : 1;
240							unsigned char Tda : 2;
241							unsigned char TB2 : 4;
242						};
243
244						// H mode
245						struct
246						{
247							// Byte 1
248							unsigned char HG1a : 3;
249							unsigned char HR1 : 4;
250							unsigned char HdummyA : 1;
251
252							// Byte 2
253							unsigned char HB1b : 2;
254							unsigned char HdummyC : 1;
255							unsigned char HB1a : 1;
256							unsigned char HG1b : 1;
257							unsigned char HdummyB : 3;
258
259							// Byte 3
260							unsigned char HG2a : 3;
261							unsigned char HR2 : 4;
262							unsigned char HB1c : 1;
263
264							// Byte 4
265							unsigned char Hdb : 1;
266							bool Hflipbit : 1;
267							unsigned char Hda : 1;
268							unsigned char HB2 : 4;
269							unsigned char HG2b : 1;
270						};
271					};
272
273					unsigned char pixelIndexMSB[2];
274					unsigned char pixelIndexLSB[2];
275				};
276
277				// planar mode
278				struct
279				{
280					// Byte 1
281					unsigned char GO1 : 1;
282					unsigned char RO : 6;
283					unsigned char PdummyA : 1;
284
285					// Byte 2
286					unsigned char BO1 : 1;
287					unsigned char GO2 : 6;
288					unsigned char PdummyB : 1;
289
290					// Byte 3
291					unsigned char BO3a : 2;
292					unsigned char PdummyD : 1;
293					unsigned char BO2 : 2;
294					unsigned char PdummyC : 3;
295
296					// Byte 4
297					unsigned char RH2 : 1;
298					bool Pflipbit : 1;
299					unsigned char RH1 : 5;
300					unsigned char BO3b : 1;
301
302					// Byte 5
303					unsigned char BHa : 1;
304					unsigned char GH : 7;
305
306					// Byte 6
307					unsigned char RVa : 3;
308					unsigned char BHb : 5;
309
310					// Byte 7
311					unsigned char GVa : 5;
312					unsigned char RVb : 3;
313
314					// Byte 8
315					unsigned char BV : 6;
316					unsigned char GVb : 2;
317				};
318
319				// Single channel block
320				struct
321				{
322					union
323					{
324						unsigned char base_codeword;
325						signed char signed_base_codeword;
326					};
327
328					unsigned char table_index : 4;
329					unsigned char multiplier : 4;
330
331					unsigned char mc1 : 2;
332					unsigned char mb : 3;
333					unsigned char ma : 3;
334
335					unsigned char mf1 : 1;
336					unsigned char me : 3;
337					unsigned char md : 3;
338					unsigned char mc2 : 1;
339
340					unsigned char mh : 3;
341					unsigned char mg : 3;
342					unsigned char mf2 : 2;
343
344					unsigned char mk1 : 2;
345					unsigned char mj : 3;
346					unsigned char mi : 3;
347
348					unsigned char mn1 : 1;
349					unsigned char mm : 3;
350					unsigned char ml : 3;
351					unsigned char mk2 : 1;
352
353					unsigned char mp : 3;
354					unsigned char mo : 3;
355					unsigned char mn2 : 2;
356				};
357			};
358		};
359
360		void decodeIndividualBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
361		{
362			int r1 = extend_4to8bits(R1);
363			int g1 = extend_4to8bits(G1);
364			int b1 = extend_4to8bits(B1);
365
366			int r2 = extend_4to8bits(R2);
367			int g2 = extend_4to8bits(G2);
368			int b2 = extend_4to8bits(B2);
369
370			decodeIndividualOrDifferentialBlock(dest, x, y, w, h, pitch, r1, g1, b1, r2, g2, b2, alphaValues, nonOpaquePunchThroughAlpha);
371		}
372
373		void decodeDifferentialBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
374		{
375			int b1 = extend_5to8bits(B);
376			int g1 = extend_5to8bits(G);
377			int r1 = extend_5to8bits(R);
378
379			int r2 = extend_5to8bits(R + dR);
380			int g2 = extend_5to8bits(G + dG);
381			int b2 = extend_5to8bits(B + dB);
382
383			decodeIndividualOrDifferentialBlock(dest, x, y, w, h, pitch, r1, g1, b1, r2, g2, b2, alphaValues, nonOpaquePunchThroughAlpha);
384		}
385
386		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
387		{
388			// Table 3.17.2 sorted according to table 3.17.3
389			static const int intensityModifierDefault[8][4] =
390			{
391				{ 2, 8, -2, -8 },
392				{ 5, 17, -5, -17 },
393				{ 9, 29, -9, -29 },
394				{ 13, 42, -13, -42 },
395				{ 18, 60, -18, -60 },
396				{ 24, 80, -24, -80 },
397				{ 33, 106, -33, -106 },
398				{ 47, 183, -47, -183 }
399			};
400
401			// Table C.12, intensity modifier for non opaque punchthrough alpha
402			static const int intensityModifierNonOpaque[8][4] =
403			{
404				{ 0, 8, 0, -8 },
405				{ 0, 17, 0, -17 },
406				{ 0, 29, 0, -29 },
407				{ 0, 42, 0, -42 },
408				{ 0, 60, 0, -60 },
409				{ 0, 80, 0, -80 },
410				{ 0, 106, 0, -106 },
411				{ 0, 183, 0, -183 }
412			};
413
414			const int(&intensityModifier)[8][4] = nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault;
415
416			bgra8 subblockColors0[4];
417			bgra8 subblockColors1[4];
418
419			const int i10 = intensityModifier[cw1][0];
420			const int i11 = intensityModifier[cw1][1];
421			const int i12 = intensityModifier[cw1][2];
422			const int i13 = intensityModifier[cw1][3];
423
424			subblockColors0[0].set(r1 + i10, g1 + i10, b1 + i10);
425			subblockColors0[1].set(r1 + i11, g1 + i11, b1 + i11);
426			subblockColors0[2].set(r1 + i12, g1 + i12, b1 + i12);
427			subblockColors0[3].set(r1 + i13, g1 + i13, b1 + i13);
428
429			const int i20 = intensityModifier[cw2][0];
430			const int i21 = intensityModifier[cw2][1];
431			const int i22 = intensityModifier[cw2][2];
432			const int i23 = intensityModifier[cw2][3];
433
434			subblockColors1[0].set(r2 + i20, g2 + i20, b2 + i20);
435			subblockColors1[1].set(r2 + i21, g2 + i21, b2 + i21);
436			subblockColors1[2].set(r2 + i22, g2 + i22, b2 + i22);
437			subblockColors1[3].set(r2 + i23, g2 + i23, b2 + i23);
438
439			unsigned char* destStart = dest;
440
441			if(flipbit)
442			{
443				for(int j = 0; j < 2 && (y + j) < h; j++)
444				{
445					bgra8* color = (bgra8*)dest;
446					if((x + 0) < w) color[0] = subblockColors0[getIndex(0, j)].addA(alphaValues[j][0]);
447					if((x + 1) < w) color[1] = subblockColors0[getIndex(1, j)].addA(alphaValues[j][1]);
448					if((x + 2) < w) color[2] = subblockColors0[getIndex(2, j)].addA(alphaValues[j][2]);
449					if((x + 3) < w) color[3] = subblockColors0[getIndex(3, j)].addA(alphaValues[j][3]);
450					dest += pitch;
451				}
452
453				for(int j = 2; j < 4 && (y + j) < h; j++)
454				{
455					bgra8* color = (bgra8*)dest;
456					if((x + 0) < w) color[0] = subblockColors1[getIndex(0, j)].addA(alphaValues[j][0]);
457					if((x + 1) < w) color[1] = subblockColors1[getIndex(1, j)].addA(alphaValues[j][1]);
458					if((x + 2) < w) color[2] = subblockColors1[getIndex(2, j)].addA(alphaValues[j][2]);
459					if((x + 3) < w) color[3] = subblockColors1[getIndex(3, j)].addA(alphaValues[j][3]);
460					dest += pitch;
461				}
462			}
463			else
464			{
465				for(int j = 0; j < 4 && (y + j) < h; j++)
466				{
467					bgra8* color = (bgra8*)dest;
468					if((x + 0) < w) color[0] = subblockColors0[getIndex(0, j)].addA(alphaValues[j][0]);
469					if((x + 1) < w) color[1] = subblockColors0[getIndex(1, j)].addA(alphaValues[j][1]);
470					if((x + 2) < w) color[2] = subblockColors1[getIndex(2, j)].addA(alphaValues[j][2]);
471					if((x + 3) < w) color[3] = subblockColors1[getIndex(3, j)].addA(alphaValues[j][3]);
472					dest += pitch;
473				}
474			}
475
476			if(nonOpaquePunchThroughAlpha)
477			{
478				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);
479			}
480		}
481
482		void decodeTBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
483		{
484			// Table C.8, distance index fot T and H modes
485			static const int distance[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
486
487			bgra8 paintColors[4];
488
489			int r1 = extend_4to8bits(TR1a << 2 | TR1b);
490			int g1 = extend_4to8bits(TG1);
491			int b1 = extend_4to8bits(TB1);
492
493			int r2 = extend_4to8bits(TR2);
494			int g2 = extend_4to8bits(TG2);
495			int b2 = extend_4to8bits(TB2);
496
497			const int d = distance[Tda << 1 | Tdb];
498
499			paintColors[0].set(r1, g1, b1);
500			paintColors[1].set(r2 + d, g2 + d, b2 + d);
501			paintColors[2].set(r2, g2, b2);
502			paintColors[3].set(r2 - d, g2 - d, b2 - d);
503
504			unsigned char* destStart = dest;
505
506			for(int j = 0; j < 4 && (y + j) < h; j++)
507			{
508				bgra8* color = (bgra8*)dest;
509				if((x + 0) < w) color[0] = paintColors[getIndex(0, j)].addA(alphaValues[j][0]);
510				if((x + 1) < w) color[1] = paintColors[getIndex(1, j)].addA(alphaValues[j][1]);
511				if((x + 2) < w) color[2] = paintColors[getIndex(2, j)].addA(alphaValues[j][2]);
512				if((x + 3) < w) color[3] = paintColors[getIndex(3, j)].addA(alphaValues[j][3]);
513				dest += pitch;
514			}
515
516			if(nonOpaquePunchThroughAlpha)
517			{
518				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);
519			}
520		}
521
522		void decodeHBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const
523		{
524			// Table C.8, distance index fot T and H modes
525			static const int distance[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
526
527			bgra8 paintColors[4];
528
529			int r1 = extend_4to8bits(HR1);
530			int g1 = extend_4to8bits(HG1a << 1 | HG1b);
531			int b1 = extend_4to8bits(HB1a << 3 | HB1b << 1 | HB1c);
532
533			int r2 = extend_4to8bits(HR2);
534			int g2 = extend_4to8bits(HG2a << 1 | HG2b);
535			int b2 = extend_4to8bits(HB2);
536
537			const int d = distance[(Hda << 2) | (Hdb << 1) | ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0)];
538
539			paintColors[0].set(r1 + d, g1 + d, b1 + d);
540			paintColors[1].set(r1 - d, g1 - d, b1 - d);
541			paintColors[2].set(r2 + d, g2 + d, b2 + d);
542			paintColors[3].set(r2 - d, g2 - d, b2 - d);
543
544			unsigned char* destStart = dest;
545
546			for(int j = 0; j < 4 && (y + j) < h; j++)
547			{
548				bgra8* color = (bgra8*)dest;
549				if((x + 0) < w) color[0] = paintColors[getIndex(0, j)].addA(alphaValues[j][0]);
550				if((x + 1) < w) color[1] = paintColors[getIndex(1, j)].addA(alphaValues[j][1]);
551				if((x + 2) < w) color[2] = paintColors[getIndex(2, j)].addA(alphaValues[j][2]);
552				if((x + 3) < w) color[3] = paintColors[getIndex(3, j)].addA(alphaValues[j][3]);
553				dest += pitch;
554			}
555
556			if(nonOpaquePunchThroughAlpha)
557			{
558				decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch);
559			}
560		}
561
562		void decodePlanarBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4]) const
563		{
564			int ro = extend_6to8bits(RO);
565			int go = extend_7to8bits(GO1 << 6 | GO2);
566			int bo = extend_6to8bits(BO1 << 5 | BO2 << 3 | BO3a << 1 | BO3b);
567
568			int rh = extend_6to8bits(RH1 << 1 | RH2);
569			int gh = extend_7to8bits(GH);
570			int bh = extend_6to8bits(BHa << 5 | BHb);
571
572			int rv = extend_6to8bits(RVa << 3 | RVb);
573			int gv = extend_7to8bits(GVa << 2 | GVb);
574			int bv = extend_6to8bits(BV);
575
576			for(int j = 0; j < 4 && (y + j) < h; j++)
577			{
578				int ry = j * (rv - ro) + 2;
579				int gy = j * (gv - go) + 2;
580				int by = j * (bv - bo) + 2;
581				for(int i = 0; i < 4 && (x + i) < w; i++)
582				{
583					((bgra8*)(dest))[i].set(((i * (rh - ro) + ry) >> 2) + ro,
584						((i * (gh - go) + gy) >> 2) + go,
585						((i * (bh - bo) + by) >> 2) + bo,
586						alphaValues[j][i]);
587				}
588				dest += pitch;
589			}
590		}
591
592		// Index for individual, differential, H and T modes
593		inline int getIndex(int x, int y) const
594		{
595			int bitIndex = x * 4 + y;
596			int bitOffset = bitIndex & 7;
597			int lsb = (pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
598			int msb = (pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1;
599
600			return (msb << 1) | lsb;
601		}
602
603		void decodePunchThroughAlphaBlock(unsigned char *dest, int x, int y, int w, int h, int pitch) const
604		{
605			for(int j = 0; j < 4 && (y + j) < h; j++)
606			{
607				for(int i = 0; i < 4 && (x + i) < w; i++)
608				{
609					if(getIndex(i, j) == 2) //  msb == 1 && lsb == 0
610					{
611						((bgra8*)dest)[i].set(0, 0, 0, 0);
612					}
613				}
614				dest += pitch;
615			}
616		}
617
618		// Single channel utility functions
619		inline int getSingleChannel(int x, int y, bool isSigned, bool isEAC) const
620		{
621			int codeword = isSigned ? signed_base_codeword : base_codeword;
622			return isEAC ?
623			       ((multiplier == 0) ?
624			        (codeword * 8 + 4 + getSingleChannelModifier(x, y)) :
625			        (codeword * 8 + 4 + getSingleChannelModifier(x, y) * multiplier * 8)) :
626			       codeword + getSingleChannelModifier(x, y) * multiplier;
627		}
628
629		inline int getSingleChannelIndex(int x, int y) const
630		{
631			switch(x * 4 + y)
632			{
633			case 0: return ma;
634			case 1: return mb;
635			case 2: return mc1 << 1 | mc2;
636			case 3: return md;
637			case 4: return me;
638			case 5: return mf1 << 2 | mf2;
639			case 6: return mg;
640			case 7: return mh;
641			case 8: return mi;
642			case 9: return mj;
643			case 10: return mk1 << 1 | mk2;
644			case 11: return ml;
645			case 12: return mm;
646			case 13: return mn1 << 2 | mn2;
647			case 14: return mo;
648			default: return mp; // 15
649			}
650		}
651
652		inline int getSingleChannelModifier(int x, int y) const
653		{
654			static const int modifierTable[16][8] = { { -3, -6, -9, -15, 2, 5, 8, 14 },
655			{ -3, -7, -10, -13, 2, 6, 9, 12 },
656			{ -2, -5, -8, -13, 1, 4, 7, 12 },
657			{ -2, -4, -6, -13, 1, 3, 5, 12 },
658			{ -3, -6, -8, -12, 2, 5, 7, 11 },
659			{ -3, -7, -9, -11, 2, 6, 8, 10 },
660			{ -4, -7, -8, -11, 3, 6, 7, 10 },
661			{ -3, -5, -8, -11, 2, 4, 7, 10 },
662			{ -2, -6, -8, -10, 1, 5, 7, 9 },
663			{ -2, -5, -8, -10, 1, 4, 7, 9 },
664			{ -2, -4, -8, -10, 1, 3, 7, 9 },
665			{ -2, -5, -7, -10, 1, 4, 6, 9 },
666			{ -3, -4, -7, -10, 2, 3, 6, 9 },
667			{ -1, -2, -3, -10, 0, 1, 2, 9 },
668			{ -4, -6, -8, -9, 3, 5, 7, 8 },
669			{ -3, -5, -7, -9, 2, 4, 6, 8 } };
670
671			return modifierTable[table_index][getSingleChannelIndex(x, y)];
672		}
673	};
674}
675
676// Decodes 1 to 4 channel images to 8 bit output
677bool ETC_Decoder::Decode(const unsigned char* src, unsigned char *dst, int w, int h, int dstW, int dstH, int dstPitch, int dstBpp, InputType inputType)
678{
679	const ETC2* sources[2];
680	sources[0] = (const ETC2*)src;
681
682	unsigned char alphaValues[4][4] = { { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } };
683
684	switch(inputType)
685	{
686	case ETC_R_SIGNED:
687	case ETC_R_UNSIGNED:
688		for(int y = 0; y < h; y += 4)
689		{
690			unsigned char *dstRow = dst + (y * dstPitch);
691			for(int x = 0; x < w; x += 4, sources[0]++)
692			{
693				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, dstW, dstH, dstPitch, inputType == ETC_R_SIGNED, true);
694			}
695		}
696		break;
697	case ETC_RG_SIGNED:
698	case ETC_RG_UNSIGNED:
699		sources[1] = sources[0] + 1;
700		for(int y = 0; y < h; y += 4)
701		{
702			unsigned char *dstRow = dst + (y * dstPitch);
703			for(int x = 0; x < w; x += 4, sources[0] += 2, sources[1] += 2)
704			{
705				ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, dstW, dstH, dstPitch, inputType == ETC_RG_SIGNED, true);
706			}
707		}
708		break;
709	case ETC_RGB:
710	case ETC_RGB_PUNCHTHROUGH_ALPHA:
711		for(int y = 0; y < h; y += 4)
712		{
713			unsigned char *dstRow = dst + (y * dstPitch);
714			for(int x = 0; x < w; x += 4, sources[0]++)
715			{
716				sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, inputType == ETC_RGB_PUNCHTHROUGH_ALPHA);
717			}
718		}
719		break;
720	case ETC_RGBA:
721		for(int y = 0; y < h; y += 4)
722		{
723			unsigned char *dstRow = dst + (y * dstPitch);
724			for(int x = 0; x < w; x += 4)
725			{
726				// Decode Alpha
727				ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, dstW, dstH, 4, false, false);
728				sources[0]++; // RGBA packets are 128 bits, so move on to the next 64 bit packet to decode the RGB color
729
730				// Decode RGB
731				sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, false);
732				sources[0]++;
733			}
734		}
735		break;
736	default:
737		return false;
738	}
739
740	return true;
741}
742