|  | // 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); | 
|  | } | 
|  |  | 
|  | inline int clampEAC(int value, bool isSigned) | 
|  | { | 
|  | int min = isSigned ? -1023 : 0; | 
|  | int max = isSigned ? 1023 : 2047; | 
|  | return (value < min) ? min : ((value > max) ? max : 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, bool isEAC) | 
|  | { | 
|  | if(isEAC) | 
|  | { | 
|  | for(int j = 0; j < 4 && (y + j) < h; j++) | 
|  | { | 
|  | int* sDst = reinterpret_cast<int*>(dest); | 
|  | for(int i = 0; i < 4 && (x + i) < w; i++) | 
|  | { | 
|  | for(int c = nbChannels - 1; c >= 0; c--) | 
|  | { | 
|  | sDst[i * nbChannels + c] = clampEAC(sources[c]->getSingleChannel(i, j, isSigned, true), isSigned); | 
|  | } | 
|  | } | 
|  | dest += pitch; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | 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, false)); | 
|  | } | 
|  | } | 
|  | 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, false)); | 
|  | } | 
|  | } | 
|  | 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, bool isEAC) const | 
|  | { | 
|  | int codeword = isSigned ? signed_base_codeword : base_codeword; | 
|  | return isEAC ? | 
|  | ((multiplier == 0) ? | 
|  | (codeword * 8 + 4 + getSingleChannelModifier(x, y)) : | 
|  | (codeword * 8 + 4 + getSingleChannelModifier(x, y) * multiplier * 8)) : | 
|  | 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, true); | 
|  | } | 
|  | } | 
|  | 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, true); | 
|  | } | 
|  | } | 
|  | 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, 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; | 
|  | } |