project64/Source/Project64-video/TextureEnhancer/tc-1.1+/dxtn.c

884 lines
25 KiB
C

// 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 <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#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);
}
}