// Project64 - A Nintendo 64 emulator // https://www.pj64-emu.com/ // Copyright(C) 2001-2021 Project64 // Copyright(C) 2007 Hiroshi Morii // Copyright(C) 2004 Daniel Borca // GNU/GPLv2 licensed: https://gnu.org/licenses/gpl-2.0.html #include #include #include #include #include #include "types.h" #include "internal.h" #include "dxtn.h" /* DXTn encoder The encoder was built by reversing the decoder, and is vaguely based on FXT1 codec. Note that this code is merely a proof of concept, since it is highly unoptimized! */ #define MAX_COMP 4 // Ever needed maximum number of components in texel #define MAX_VECT 4 // Ever needed maximum number of base vectors to find #define N_TEXELS 16 // Number of texels in a block (always 16) #define COLOR565(v) (word)((((v)[RCOMP] & 0xf8) << 8) | (((v)[GCOMP] & 0xfc) << 3) | ((v)[BCOMP] >> 3)) static const int dxtn_color_tlat[2][4] = { { 0, 2, 3, 1 }, { 0, 2, 1, 3 } }; static const int dxtn_alpha_tlat[2][8] = { { 0, 2, 3, 4, 5, 6, 7, 1 }, { 0, 2, 3, 4, 5, 1, 6, 7 } }; static void dxt1_rgb_quantize(dword *cc, const byte *lines[], int comps) { float b, iv[MAX_COMP]; // Interpolation vector dword hi; // High doubleword int color0, color1; int n_vect; const int n_comp = 3; int black = 0; #ifndef YUV int minSum = 2000; // Big enough #else int minSum = 2000000; #endif int maxSum = -1; // Small enough int minCol = 0; // phoudoin: Silent compiler! int maxCol = 0; // phoudoin: Silent compiler! byte input[N_TEXELS][MAX_COMP]; int i, k, l; // Make the whole block opaque // We will NEVER reference ACOMP of any pixel // 4 texels each line #ifndef ARGB for (l = 0; l < 4; l++) { for (k = 0; k < 4; k++) { for (i = 0; i < comps; i++) { input[k + l * 4][i] = *lines[l]++; } } } #else // H.Morii - Support for ARGB inputs for (l = 0; l < 4; l++) { for (k = 0; k < 4; k++) { input[k + l * 4][2] = *lines[l]++; input[k + l * 4][1] = *lines[l]++; input[k + l * 4][0] = *lines[l]++; if (comps == 4) input[k + l * 4][3] = *lines[l]++; } } #endif /* Our solution here is to find the darkest and brightest colors in the 4x4 tile and use those as the two representative colors. There are probably better algorithms to use (histogram-based). */ for (k = 0; k < N_TEXELS; k++) { int sum = 0; #ifndef YUV for (i = 0; i < n_comp; i++) { sum += input[k][i]; } #else /* RGB to YUV conversion according to CCIR 601 specs Y = 0.299R+0.587G+0.114B U = 0.713(R - Y) = 0.500R-0.419G-0.081B V = 0.564(B - Y) = -0.169R-0.331G+0.500B */ sum = 299 * input[k][RCOMP] + 587 * input[k][GCOMP] + 114 * input[k][BCOMP]; #endif if (minSum > sum) { minSum = sum; minCol = k; } if (maxSum < sum) { maxSum = sum; maxCol = k; } if (sum == 0) { black = 1; } } color0 = COLOR565(input[minCol]); color1 = COLOR565(input[maxCol]); if (color0 == color1) { // We'll use 3-vector cc[0] = color0 | (color1 << 16); hi = black ? -1 : 0; } else { if (black && ((color0 == 0) || (color1 == 0))) { // We still can use 4-vector black = 0; } if (black ^ (color0 <= color1)) { int aux; aux = color0; color0 = color1; color1 = aux; aux = minCol; minCol = maxCol; maxCol = aux; } n_vect = (color0 <= color1) ? 2 : 3; MAKEIVEC(n_vect, n_comp, iv, b, input[minCol], input[maxCol]); // Add in texels cc[0] = color0 | (color1 << 16); hi = 0; for (k = N_TEXELS - 1; k >= 0; k--) { int texel = 3; int sum = 0; if (black) { for (i = 0; i < n_comp; i++) { sum += input[k][i]; } } if (!black || sum) { // Interpolate color CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]); texel = dxtn_color_tlat[black][texel]; } // Add in texel hi <<= 2; hi |= texel; } } cc[1] = hi; } static void dxt1_rgba_quantize(dword *cc, const byte *lines[], int comps) { float b, iv[MAX_COMP]; // Interpolation vector dword hi; // High doubleword int color0, color1; int n_vect; const int n_comp = 3; int transparent = 0; #ifndef YUV int minSum = 2000; // Big enough #else int minSum = 2000000; #endif int maxSum = -1; // Small enough int minCol = 0; // phoudoin: Silent compiler! int maxCol = 0; // phoudoin: Silent compiler! byte input[N_TEXELS][MAX_COMP]; int i, k, l; if (comps == 3) { // Make the whole block opaque memset(input, -1, sizeof(input)); } // 4 texels each line #ifndef ARGB for (l = 0; l < 4; l++) { for (k = 0; k < 4; k++) { for (i = 0; i < comps; i++) { input[k + l * 4][i] = *lines[l]++; } } } #else // H.Morii - Support for ARGB inputs for (l = 0; l < 4; l++) { for (k = 0; k < 4; k++) { input[k + l * 4][2] = *lines[l]++; input[k + l * 4][1] = *lines[l]++; input[k + l * 4][0] = *lines[l]++; if (comps == 4) input[k + l * 4][3] = *lines[l]++; } } #endif /* Our solution here is to find the darkest and brightest colors in the 4x4 tile and use those as the two representative colors. There are probably better algorithms to use (histogram-based). */ for (k = 0; k < N_TEXELS; k++) { int sum = 0; #ifndef YUV for (i = 0; i < n_comp; i++) { sum += input[k][i]; } #else sum = 299 * input[k][RCOMP] + 587 * input[k][GCOMP] + 114 * input[k][BCOMP]; #endif if (minSum > sum) { minSum = sum; minCol = k; } if (maxSum < sum) { maxSum = sum; maxCol = k; } if (input[k][ACOMP] < 128) { transparent = 1; } } color0 = COLOR565(input[minCol]); color1 = COLOR565(input[maxCol]); if (color0 == color1) { // We'll use 3-vector cc[0] = color0 | (color1 << 16); hi = transparent ? -1 : 0; } else { if (transparent ^ (color0 <= color1)) { int aux; aux = color0; color0 = color1; color1 = aux; aux = minCol; minCol = maxCol; maxCol = aux; } n_vect = (color0 <= color1) ? 2 : 3; MAKEIVEC(n_vect, n_comp, iv, b, input[minCol], input[maxCol]); // Add in texels cc[0] = color0 | (color1 << 16); hi = 0; for (k = N_TEXELS - 1; k >= 0; k--) { int texel = 3; if (input[k][ACOMP] >= 128) { // Interpolate color CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]); texel = dxtn_color_tlat[transparent][texel]; } // Add in texel hi <<= 2; hi |= texel; } } cc[1] = hi; } static void dxt3_rgba_quantize(dword *cc, const byte *lines[], int comps) { float b, iv[MAX_COMP]; // Interpolation vector dword lolo, lohi; // Low quadword: lo DWORD, hi DWORD dword hihi; // High quadword: high DWORD int color0, color1; const int n_vect = 3; const int n_comp = 3; #ifndef YUV int minSum = 2000; // Big enough #else int minSum = 2000000; #endif int maxSum = -1; // Small enough int minCol = 0; // phoudoin: Silent compiler! int maxCol = 0; // phoudoin: Silent compiler! byte input[N_TEXELS][MAX_COMP]; int i, k, l; if (comps == 3) { // Make the whole block opaque memset(input, -1, sizeof(input)); } // 4 texels each line #ifndef ARGB for (l = 0; l < 4; l++) { for (k = 0; k < 4; k++) { for (i = 0; i < comps; i++) { input[k + l * 4][i] = *lines[l]++; } } } #else // H.Morii - Support for ARGB inputs for (l = 0; l < 4; l++) { for (k = 0; k < 4; k++) { input[k + l * 4][2] = *lines[l]++; input[k + l * 4][1] = *lines[l]++; input[k + l * 4][0] = *lines[l]++; if (comps == 4) input[k + l * 4][3] = *lines[l]++; } } #endif /* TODO: Our solution here is to find the darkest and brightest colors in the 4x4 tile and use those as the two representative colors. There are probably better algorithms to use (histogram-based). */ for (k = 0; k < N_TEXELS; k++) { int sum = 0; #ifndef YUV for (i = 0; i < n_comp; i++) { sum += input[k][i]; } #else sum = 299 * input[k][RCOMP] + 587 * input[k][GCOMP] + 114 * input[k][BCOMP]; #endif if (minSum > sum) { minSum = sum; minCol = k; } if (maxSum < sum) { maxSum = sum; maxCol = k; } } // Add in alphas lolo = lohi = 0; for (k = N_TEXELS - 1; k >= N_TEXELS / 2; k--) { // Add in alpha lohi <<= 4; lohi |= input[k][ACOMP] >> 4; } cc[1] = lohi; for (; k >= 0; k--) { // Add in alpha lolo <<= 4; lolo |= input[k][ACOMP] >> 4; } cc[0] = lolo; color0 = COLOR565(input[minCol]); color1 = COLOR565(input[maxCol]); #ifdef RADEON /* H.Morii - Workaround for ATI Radeon * According to the OpenGL EXT_texture_compression_s3tc specs, * the encoding of the RGB components for DXT3 and DXT5 formats * use the non-transparent encodings of DXT1 but treated as * though color0 > color1, regardless of the actual values of * color0 and color1. ATI Radeons however require the values to * be color0 > color1. */ if (color0 < color1) { int aux; aux = color0; color0 = color1; color1 = aux; aux = minCol; minCol = maxCol; maxCol = aux; } #endif cc[2] = color0 | (color1 << 16); hihi = 0; if (color0 != color1) { MAKEIVEC(n_vect, n_comp, iv, b, input[minCol], input[maxCol]); // Add in texels for (k = N_TEXELS - 1; k >= 0; k--) { int texel; // Interpolate color CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]); texel = dxtn_color_tlat[0][texel]; // Add in texel hihi <<= 2; hihi |= texel; } } cc[3] = hihi; } static void dxt5_rgba_quantize(dword *cc, const byte *lines[], int comps) { float b, iv[MAX_COMP]; // Interpolation vector qword lo; // Low quadword dword hihi; // High quadword: high DWORD int color0, color1; const int n_vect = 3; const int n_comp = 3; #ifndef YUV int minSum = 2000; // Big enough #else int minSum = 2000000; #endif int maxSum = -1; // Small enough int minCol = 0; // phoudoin: Silent compiler! int maxCol = 0; // phoudoin: Silent compiler! int alpha0 = 2000; // Big enough int alpha1 = -1; // Small enough int anyZero = 0, anyOne = 0; int a_vect; byte input[N_TEXELS][MAX_COMP]; int i, k, l; if (comps == 3) { // Make the whole block opaque memset(input, -1, sizeof(input)); } // 4 texels each line #ifndef ARGB for (l = 0; l < 4; l++) { for (k = 0; k < 4; k++) { for (i = 0; i < comps; i++) { input[k + l * 4][i] = *lines[l]++; } } } #else // H.Morii - Support for ARGB inputs for (l = 0; l < 4; l++) { for (k = 0; k < 4; k++) { input[k + l * 4][2] = *lines[l]++; input[k + l * 4][1] = *lines[l]++; input[k + l * 4][0] = *lines[l]++; if (comps == 4) input[k + l * 4][3] = *lines[l]++; } } #endif /* Our solution here is to find the darkest and brightest colors in the 4x4 tile and use those as the two representative colors. There are probably better algorithms to use (histogram-based). */ for (k = 0; k < N_TEXELS; k++) { int sum = 0; #ifndef YUV for (i = 0; i < n_comp; i++) { sum += input[k][i]; } #else sum = 299 * input[k][RCOMP] + 587 * input[k][GCOMP] + 114 * input[k][BCOMP]; #endif if (minSum > sum) { minSum = sum; minCol = k; } if (maxSum < sum) { maxSum = sum; maxCol = k; } if (alpha0 > input[k][ACOMP]) { alpha0 = input[k][ACOMP]; } if (alpha1 < input[k][ACOMP]) { alpha1 = input[k][ACOMP]; } if (input[k][ACOMP] == 0) { anyZero = 1; } if (input[k][ACOMP] == 255) { anyOne = 1; } } // Add in alphas if (alpha0 == alpha1) { // We'll use 6-vector cc[0] = alpha0 | (alpha1 << 8); cc[1] = 0; } else { if (anyZero && ((alpha0 == 0) || (alpha1 == 0))) { // We still might use 8-vector anyZero = 0; } if (anyOne && ((alpha0 == 255) || (alpha1 == 255))) { // We still might use 8-vector anyOne = 0; } if ((anyZero | anyOne) ^ (alpha0 <= alpha1)) { int aux; aux = alpha0; alpha0 = alpha1; alpha1 = aux; } a_vect = (alpha0 <= alpha1) ? 5 : 7; // Compute interpolation vector iv[ACOMP] = (float)a_vect / (alpha1 - alpha0); b = -iv[ACOMP] * alpha0 + 0.5F; // Add in alphas Q_MOV32(lo, 0); for (k = N_TEXELS - 1; k >= 0; k--) { int texel = -1; if (anyZero | anyOne) { if (input[k][ACOMP] == 0) { texel = 6; } else if (input[k][ACOMP] == 255) { texel = 7; } } // Interpolate alpha if (texel == -1) { float dot = input[k][ACOMP] * iv[ACOMP]; texel = (int)(dot + b); #if SAFECDOT if (texel < 0) { texel = 0; } else if (texel > a_vect) { texel = a_vect; } #endif texel = dxtn_alpha_tlat[anyZero | anyOne][texel]; } // Add in texel Q_SHL(lo, 3); Q_OR32(lo, texel); } Q_SHL(lo, 16); Q_OR32(lo, alpha0 | (alpha1 << 8)); ((qword *)cc)[0] = lo; } color0 = COLOR565(input[minCol]); color1 = COLOR565(input[maxCol]); #ifdef RADEON /* H.Morii - Workaround for ATI Radeon */ if (color0 < color1) { int aux; aux = color0; color0 = color1; color1 = aux; aux = minCol; minCol = maxCol; maxCol = aux; } #endif cc[2] = color0 | (color1 << 16); hihi = 0; if (color0 != color1) { MAKEIVEC(n_vect, n_comp, iv, b, input[minCol], input[maxCol]); // Add in texels for (k = N_TEXELS - 1; k >= 0; k--) { int texel; // Interpolate color CALCCDOT(texel, n_vect, n_comp, iv, b, input[k]); texel = dxtn_color_tlat[0][texel]; // Add in texel hihi <<= 2; hihi |= texel; } } cc[3] = hihi; } #define ENCODER(dxtn, n) \ int TAPIENTRY \ dxtn##_encode (int width, int height, int comps, \ const void *source, int srcRowStride, \ void *dest, int destRowStride) \ { \ int x, y; \ const byte *data; \ dword *encoded = (dword *)dest; \ void *newSource = NULL; \ \ /* Replicate image if width is not M4 or height is not M4 */ \ if ((width & 3) | (height & 3)) { \ int newWidth = (width + 3) & ~3; \ int newHeight = (height + 3) & ~3; \ newSource = malloc(comps * newWidth * newHeight * sizeof(byte *));\ _mesa_upscale_teximage2d(width, height, newWidth, newHeight, \ comps, (const byte *)source, \ srcRowStride, (byte *)newSource); \ source = newSource; \ width = newWidth; \ height = newHeight; \ srcRowStride = comps * newWidth; \ } \ \ data = (const byte *)source; \ destRowStride = (destRowStride - width * n) / 4; \ for (y = 0; y < height; y += 4) { \ unsigned int offs = 0 + (y + 0) * srcRowStride; \ for (x = 0; x < width; x += 4) { \ const byte *lines[4]; \ lines[0] = &data[offs]; \ lines[1] = lines[0] + srcRowStride; \ lines[2] = lines[1] + srcRowStride; \ lines[3] = lines[2] + srcRowStride; \ offs += 4 * comps; \ dxtn##_quantize(encoded, lines, comps); \ /* 4x4 block */ \ encoded += n; \ } \ encoded += destRowStride; \ } \ \ if (newSource != NULL) { \ free(newSource); \ } \ \ return 0; \ } ENCODER(dxt1_rgb, 2) ENCODER(dxt1_rgba, 2) ENCODER(dxt3_rgba, 4) ENCODER(dxt5_rgba, 4) /* DXTn decoder The decoder is based on GL_EXT_texture_compression_s3tc specification and serves as a concept for the encoder. */ // Lookup table for scaling 4-bit colors up to 8-bit static const byte _rgb_scale_4[] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255 }; // Lookup table for scaling 5-bit colors up to 8-bit static const byte _rgb_scale_5[] = { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255 }; // Lookup table for scaling 6-bit colors up to 8-bit static const byte _rgb_scale_6[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255 }; #define CC_SEL(cc, which) (((dword *)(cc))[(which) / 32] >> ((which) & 31)) #define UP4(c) _rgb_scale_4[(c) & 15] #define UP5(c) _rgb_scale_5[(c) & 31] #define UP6(c) _rgb_scale_6[(c) & 63] #define ZERO_4UBV(v) *((dword *)(v)) = 0 void TAPIENTRY dxt1_rgb_decode_1(const void *texture, int stride, int i, int j, byte *rgba) { const byte *src = (const byte *)texture + ((j / 4) * ((stride + 3) / 4) + i / 4) * 8; const int code = (src[4 + (j & 3)] >> ((i & 3) * 2)) & 0x3; if (code == 0) { rgba[RCOMP] = UP5(CC_SEL(src, 11)); rgba[GCOMP] = UP6(CC_SEL(src, 5)); rgba[BCOMP] = UP5(CC_SEL(src, 0)); } else if (code == 1) { rgba[RCOMP] = UP5(CC_SEL(src, 27)); rgba[GCOMP] = UP6(CC_SEL(src, 21)); rgba[BCOMP] = UP5(CC_SEL(src, 16)); } else { const word col0 = src[0] | (src[1] << 8); const word col1 = src[2] | (src[3] << 8); if (col0 > col1) { if (code == 2) { rgba[RCOMP] = (UP5(col0 >> 11) * 2 + UP5(col1 >> 11)) / 3; rgba[GCOMP] = (UP6(col0 >> 5) * 2 + UP6(col1 >> 5)) / 3; rgba[BCOMP] = (UP5(col0) * 2 + UP5(col1)) / 3; } else { rgba[RCOMP] = (UP5(col0 >> 11) + 2 * UP5(col1 >> 11)) / 3; rgba[GCOMP] = (UP6(col0 >> 5) + 2 * UP6(col1 >> 5)) / 3; rgba[BCOMP] = (UP5(col0) + 2 * UP5(col1)) / 3; } } else { if (code == 2) { rgba[RCOMP] = (UP5(col0 >> 11) + UP5(col1 >> 11)) / 2; rgba[GCOMP] = (UP6(col0 >> 5) + UP6(col1 >> 5)) / 2; rgba[BCOMP] = (UP5(col0) + UP5(col1)) / 2; } else { ZERO_4UBV(rgba); } } } rgba[ACOMP] = 255; } void TAPIENTRY dxt1_rgba_decode_1(const void *texture, int stride, int i, int j, byte *rgba) { // Same as rgb_dxt1 above, except alpha=0 if col0<=col1 and code=3. const byte *src = (const byte *)texture + ((j / 4) * ((stride + 3) / 4) + i / 4) * 8; const int code = (src[4 + (j & 3)] >> ((i & 3) * 2)) & 0x3; if (code == 0) { rgba[RCOMP] = UP5(CC_SEL(src, 11)); rgba[GCOMP] = UP6(CC_SEL(src, 5)); rgba[BCOMP] = UP5(CC_SEL(src, 0)); rgba[ACOMP] = 255; } else if (code == 1) { rgba[RCOMP] = UP5(CC_SEL(src, 27)); rgba[GCOMP] = UP6(CC_SEL(src, 21)); rgba[BCOMP] = UP5(CC_SEL(src, 16)); rgba[ACOMP] = 255; } else { const word col0 = src[0] | (src[1] << 8); const word col1 = src[2] | (src[3] << 8); if (col0 > col1) { if (code == 2) { rgba[RCOMP] = (UP5(col0 >> 11) * 2 + UP5(col1 >> 11)) / 3; rgba[GCOMP] = (UP6(col0 >> 5) * 2 + UP6(col1 >> 5)) / 3; rgba[BCOMP] = (UP5(col0) * 2 + UP5(col1)) / 3; } else { rgba[RCOMP] = (UP5(col0 >> 11) + 2 * UP5(col1 >> 11)) / 3; rgba[GCOMP] = (UP6(col0 >> 5) + 2 * UP6(col1 >> 5)) / 3; rgba[BCOMP] = (UP5(col0) + 2 * UP5(col1)) / 3; } rgba[ACOMP] = 255; } else { if (code == 2) { rgba[RCOMP] = (UP5(col0 >> 11) + UP5(col1 >> 11)) / 2; rgba[GCOMP] = (UP6(col0 >> 5) + UP6(col1 >> 5)) / 2; rgba[BCOMP] = (UP5(col0) + UP5(col1)) / 2; rgba[ACOMP] = 255; } else { ZERO_4UBV(rgba); } } } } void TAPIENTRY dxt3_rgba_decode_1(const void *texture, int stride, int i, int j, byte *rgba) { const byte *src = (const byte *)texture + ((j / 4) * ((stride + 3) / 4) + i / 4) * 16; const int code = (src[12 + (j & 3)] >> ((i & 3) * 2)) & 0x3; const dword *cc = (const dword *)(src + 8); if (code == 0) { rgba[RCOMP] = UP5(CC_SEL(cc, 11)); rgba[GCOMP] = UP6(CC_SEL(cc, 5)); rgba[BCOMP] = UP5(CC_SEL(cc, 0)); } else if (code == 1) { rgba[RCOMP] = UP5(CC_SEL(cc, 27)); rgba[GCOMP] = UP6(CC_SEL(cc, 21)); rgba[BCOMP] = UP5(CC_SEL(cc, 16)); } else if (code == 2) { // (col0 * (4 - code) + col1 * (code - 1)) / 3 rgba[RCOMP] = (UP5(CC_SEL(cc, 11)) * 2 + UP5(CC_SEL(cc, 27))) / 3; rgba[GCOMP] = (UP6(CC_SEL(cc, 5)) * 2 + UP6(CC_SEL(cc, 21))) / 3; rgba[BCOMP] = (UP5(CC_SEL(cc, 0)) * 2 + UP5(CC_SEL(cc, 16))) / 3; } else { rgba[RCOMP] = (UP5(CC_SEL(cc, 11)) + 2 * UP5(CC_SEL(cc, 27))) / 3; rgba[GCOMP] = (UP6(CC_SEL(cc, 5)) + 2 * UP6(CC_SEL(cc, 21))) / 3; rgba[BCOMP] = (UP5(CC_SEL(cc, 0)) + 2 * UP5(CC_SEL(cc, 16))) / 3; } rgba[ACOMP] = UP4(src[((j & 3) * 4 + (i & 3)) / 2] >> ((i & 1) * 4)); } void TAPIENTRY dxt5_rgba_decode_1(const void *texture, int stride, int i, int j, byte *rgba) { const byte *src = (const byte *)texture + ((j / 4) * ((stride + 3) / 4) + i / 4) * 16; const int code = (src[12 + (j & 3)] >> ((i & 3) * 2)) & 0x3; const dword *cc = (const dword *)(src + 8); const byte alpha0 = src[0]; const byte alpha1 = src[1]; const int alphaShift = (((j & 3) * 4) + (i & 3)) * 3 + 16; const int acode = ((alphaShift == 31) ? CC_SEL(src + 2, alphaShift - 16) : CC_SEL(src, alphaShift)) & 0x7; if (code == 0) { rgba[RCOMP] = UP5(CC_SEL(cc, 11)); rgba[GCOMP] = UP6(CC_SEL(cc, 5)); rgba[BCOMP] = UP5(CC_SEL(cc, 0)); } else if (code == 1) { rgba[RCOMP] = UP5(CC_SEL(cc, 27)); rgba[GCOMP] = UP6(CC_SEL(cc, 21)); rgba[BCOMP] = UP5(CC_SEL(cc, 16)); } else if (code == 2) { // (col0 * (4 - code) + col1 * (code - 1)) / 3 rgba[RCOMP] = (UP5(CC_SEL(cc, 11)) * 2 + UP5(CC_SEL(cc, 27))) / 3; rgba[GCOMP] = (UP6(CC_SEL(cc, 5)) * 2 + UP6(CC_SEL(cc, 21))) / 3; rgba[BCOMP] = (UP5(CC_SEL(cc, 0)) * 2 + UP5(CC_SEL(cc, 16))) / 3; } else { rgba[RCOMP] = (UP5(CC_SEL(cc, 11)) + 2 * UP5(CC_SEL(cc, 27))) / 3; rgba[GCOMP] = (UP6(CC_SEL(cc, 5)) + 2 * UP6(CC_SEL(cc, 21))) / 3; rgba[BCOMP] = (UP5(CC_SEL(cc, 0)) + 2 * UP5(CC_SEL(cc, 16))) / 3; } if (acode == 0) { rgba[ACOMP] = alpha0; } else if (acode == 1) { rgba[ACOMP] = alpha1; } else if (alpha0 > alpha1) { rgba[ACOMP] = (uint8_t)(((8 - acode) * alpha0 + (acode - 1) * alpha1) / 7); } else if (acode == 6) { rgba[ACOMP] = 0; } else if (acode == 7) { rgba[ACOMP] = 255; } else { rgba[ACOMP] = (uint8_t)(((6 - acode) * alpha0 + (acode - 1) * alpha1) / 5); } }