Added ETC2 decoding.

This commit is contained in:
bkaradzic 2013-09-15 14:36:51 -07:00
parent 666b431b40
commit 528a725387

View file

@ -442,7 +442,7 @@ namespace bgfx
}
}
static const int32_t s_mod[8][4] =
static const int32_t s_etc1Mod[8][4] =
{
{ 2, 8, -2, -8},
{ 15, 17, -15, -17},
@ -454,16 +454,248 @@ namespace bgfx
{ 47, 183, -47, -183},
};
uint8_t uint8_satadd(int32_t _a, int32_t _b)
static const uint8_t s_etc2Mod[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
uint8_t uint8_sat(int32_t _a)
{
using namespace bx;
const int32_t add = _a + _b;
const uint32_t min = uint32_imin(add, 255);
const uint32_t min = uint32_imin(_a, 255);
const uint32_t result = uint32_imax(min, 0);
return (uint8_t)result;
}
void decodeBlockEtc1(uint8_t _dst[16*4], const uint8_t _src[8])
uint8_t uint8_satadd(int32_t _a, int32_t _b)
{
const int32_t add = _a + _b;
return uint8_sat(add);
}
void decodeBlockEtc2ModeT(uint8_t _dst[16*4], const uint8_t _src[8])
{
uint8_t rgb[16];
// 0 1 2 3 4 5 6 7
// 7654321076543210765432107654321076543210765432107654321076543210
// ...rr.rrggggbbbbrrrrggggbbbbDDD.mmmmmmmmmmmmmmmmllllllllllllllll
// ^ ^ ^ ^ ^
// +-- c0 +-- c1 | +-- msb +-- lsb
// +-- dist
rgb[ 0] = ( (_src[0] >> 1) & 0xc)
| (_src[0] & 0x3)
;
rgb[ 1] = _src[1] >> 4;
rgb[ 2] = _src[1] & 0xf;
rgb[ 8] = _src[2] >> 4;
rgb[ 9] = _src[2] & 0xf;
rgb[10] = _src[3] >> 4;
rgb[ 0] = bitRangeConvert(rgb[ 0], 4, 8);
rgb[ 1] = bitRangeConvert(rgb[ 1], 4, 8);
rgb[ 2] = bitRangeConvert(rgb[ 2], 4, 8);
rgb[ 8] = bitRangeConvert(rgb[ 8], 4, 8);
rgb[ 9] = bitRangeConvert(rgb[ 9], 4, 8);
rgb[10] = bitRangeConvert(rgb[10], 4, 8);
uint8_t dist = (_src[3] >> 1) & 0x7;
int32_t mod = s_etc2Mod[dist];
rgb[ 4] = uint8_satadd(rgb[ 8], mod);
rgb[ 5] = uint8_satadd(rgb[ 9], mod);
rgb[ 6] = uint8_satadd(rgb[10], mod);
rgb[12] = uint8_satadd(rgb[ 8], -mod);
rgb[13] = uint8_satadd(rgb[ 9], -mod);
rgb[14] = uint8_satadd(rgb[10], -mod);
uint32_t indexMsb = (_src[4]<<8) | _src[5];
uint32_t indexLsb = (_src[6]<<8) | _src[7];
for (uint32_t ii = 0; ii < 16; ++ii)
{
const uint32_t idx = (ii&0xc) | ( (ii & 0x3)<<4);
const uint32_t lsbi = indexLsb & 1;
const uint32_t msbi = (indexMsb & 1)<<1;
const uint32_t pal = (lsbi | msbi)<<2;
_dst[idx + 0] = rgb[pal+2];
_dst[idx + 1] = rgb[pal+1];
_dst[idx + 2] = rgb[pal+0];
_dst[idx + 3] = 255;
indexLsb >>= 1;
indexMsb >>= 1;
}
}
void decodeBlockEtc2ModeH(uint8_t _dst[16*4], const uint8_t _src[8])
{
uint8_t rgb[16];
// 0 1 2 3 4 5 6 7
// 7654321076543210765432107654321076543210765432107654321076543210
// .rrrrggg...gb.bbbrrrrggggbbbbDD.mmmmmmmmmmmmmmmmllllllllllllllll
// ^ ^ ^ ^ ^
// +-- c0 +-- c1 | +-- msb +-- lsb
// +-- dist
rgb[ 0] = (_src[0] >> 3) & 0xf;
rgb[ 1] = ( (_src[0] << 1) & 0xe)
| ( (_src[1] >> 4) & 0x1)
;
rgb[ 2] = (_src[1] & 0x8)
| ( (_src[1] << 1) & 0x6)
| (_src[2] >> 7)
;
rgb[ 8] = (_src[2] >> 3) & 0xf;
rgb[ 9] = ( (_src[2] << 1) & 0xe)
| (_src[3] >> 7)
;
rgb[10] = (_src[2] >> 3) & 0xf;
rgb[ 0] = bitRangeConvert(rgb[ 0], 4, 8);
rgb[ 1] = bitRangeConvert(rgb[ 1], 4, 8);
rgb[ 2] = bitRangeConvert(rgb[ 2], 4, 8);
rgb[ 8] = bitRangeConvert(rgb[ 8], 4, 8);
rgb[ 9] = bitRangeConvert(rgb[ 9], 4, 8);
rgb[10] = bitRangeConvert(rgb[10], 4, 8);
uint32_t col0 = uint32_t(rgb[0]<<16) | uint32_t(rgb[1]<<8) | uint32_t(rgb[ 2]);
uint32_t col1 = uint32_t(rgb[8]<<16) | uint32_t(rgb[9]<<8) | uint32_t(rgb[10]);
uint8_t dist = (_src[3] & 0x6) | (col0 >= col1);
int32_t mod = s_etc2Mod[dist];
rgb[ 4] = uint8_satadd(rgb[ 0], -mod);
rgb[ 5] = uint8_satadd(rgb[ 1], -mod);
rgb[ 6] = uint8_satadd(rgb[ 2], -mod);
rgb[ 0] = uint8_satadd(rgb[ 0], mod);
rgb[ 1] = uint8_satadd(rgb[ 1], mod);
rgb[ 2] = uint8_satadd(rgb[ 2], mod);
rgb[12] = uint8_satadd(rgb[ 8], -mod);
rgb[13] = uint8_satadd(rgb[ 9], -mod);
rgb[14] = uint8_satadd(rgb[10], -mod);
rgb[ 8] = uint8_satadd(rgb[ 8], mod);
rgb[ 9] = uint8_satadd(rgb[ 9], mod);
rgb[10] = uint8_satadd(rgb[10], mod);
uint32_t indexMsb = (_src[4]<<8) | _src[5];
uint32_t indexLsb = (_src[6]<<8) | _src[7];
for (uint32_t ii = 0; ii < 16; ++ii)
{
const uint32_t idx = (ii&0xc) | ( (ii & 0x3)<<4);
const uint32_t lsbi = indexLsb & 1;
const uint32_t msbi = (indexMsb & 1)<<1;
const uint32_t pal = (lsbi | msbi)<<2;
_dst[idx + 0] = rgb[pal+2];
_dst[idx + 1] = rgb[pal+1];
_dst[idx + 2] = rgb[pal+0];
_dst[idx + 3] = 255;
indexLsb >>= 1;
indexMsb >>= 1;
}
}
void decodeBlockEtc2ModePlanar(uint8_t _dst[16*4], const uint8_t _src[8])
{
// 0 1 2 3 4 5 6 7
// 7654321076543210765432107654321076543210765432107654321076543210
// .rrrrrrg.ggggggb...bb.bbbrrrrr.rgggggggbbbbbbrrrrrrgggggggbbbbbb
// ^ ^ ^
// +-- c0 +-- cH +-- cV
uint8_t c0[3];
uint8_t cH[3];
uint8_t cV[3];
c0[0] = (_src[0] >> 1) & 0x3f;
c0[1] = ( (_src[0] & 1) << 6)
| ( (_src[1] >> 1) & 0x3f)
;
c0[2] = ( (_src[1] & 1) << 5)
| ( (_src[2] & 0x18) )
| ( (_src[2] << 1) & 6)
| ( (_src[3] >> 7) )
;
cH[0] = ( (_src[3] >> 1) & 0x3e)
| (_src[3] & 1)
;
cH[1] = _src[4] >> 1;
cH[2] = ( (_src[4] & 1) << 5)
| (_src[5] >> 3)
;
cV[0] = ( (_src[5] & 0x7) << 3)
| (_src[6] >> 5)
;
cV[1] = ( (_src[6] & 0x1f) << 2)
| (_src[7] >> 5)
;
cV[2] = _src[8] & 0x3f;
c0[0] = bitRangeConvert(c0[0], 6, 8);
c0[1] = bitRangeConvert(c0[1], 7, 8);
c0[2] = bitRangeConvert(c0[2], 6, 8);
cH[0] = bitRangeConvert(cH[0], 6, 8);
cH[1] = bitRangeConvert(cH[1], 7, 8);
cH[2] = bitRangeConvert(cH[2], 6, 8);
cV[0] = bitRangeConvert(cV[0], 6, 8);
cV[1] = bitRangeConvert(cV[1], 7, 8);
cV[2] = bitRangeConvert(cV[2], 6, 8);
int16_t dy[3];
dy[0] = cV[0] - c0[0];
dy[1] = cV[1] - c0[1];
dy[2] = cV[2] - c0[2];
int16_t sx[3];
sx[0] = int16_t(c0[0])<<2;
sx[1] = int16_t(c0[1])<<2;
sx[2] = int16_t(c0[2])<<2;
int16_t ex[3];
ex[0] = int16_t(cH[0])<<2;
ex[1] = int16_t(cH[1])<<2;
ex[2] = int16_t(cH[2])<<2;
for (int32_t vv = 0; vv < 4; ++vv)
{
int16_t dx[3];
dx[0] = (ex[0] - sx[0])>>2;
dx[1] = (ex[1] - sx[1])>>2;
dx[2] = (ex[2] - sx[2])>>2;
for (int32_t hh = 0; hh < 4; ++hh)
{
const uint32_t idx = (vv<<4) + (hh<<2);
_dst[idx + 0] = uint8_sat( (sx[2] + dx[2]*hh)>>2);
_dst[idx + 1] = uint8_sat( (sx[1] + dx[1]*hh)>>2);
_dst[idx + 2] = uint8_sat( (sx[0] + dx[0]*hh)>>2);
_dst[idx + 3] = 255;
}
sx[0] += dy[0];
sx[1] += dy[1];
sx[2] += dy[2];
ex[0] += dy[0];
ex[1] += dy[1];
ex[2] += dy[2];
}
}
void decodeBlockEtc12(uint8_t _dst[16*4], const uint8_t _src[8])
{
bool flipBit = 0 != (_src[3] & 0x1);
bool diffBit = 0 != (_src[3] & 0x2);
@ -477,20 +709,38 @@ namespace bgfx
rgb[2] = _src[2] >> 3;
int8_t diff[3];
diff[0] = int8_t( (_src[0] & 0x07)<<5)>>5;
diff[1] = int8_t( (_src[1] & 0x07)<<5)>>5;
diff[2] = int8_t( (_src[2] & 0x07)<<5)>>5;
diff[0] = int8_t( (_src[0] & 0x7)<<5)>>5;
diff[1] = int8_t( (_src[1] & 0x7)<<5)>>5;
diff[2] = int8_t( (_src[2] & 0x7)<<5)>>5;
rgb[4] = rgb[0] + diff[0];
rgb[5] = rgb[1] + diff[1];
rgb[6] = rgb[2] + diff[2];
int8_t rr = rgb[0] + diff[0];
int8_t gg = rgb[1] + diff[1];
int8_t bb = rgb[2] + diff[2];
// Etc2 3-modes
if (rr < 0 || rr > 31)
{
decodeBlockEtc2ModeT(_dst, _src);
return;
}
if (gg < 0 || gg > 31)
{
decodeBlockEtc2ModeH(_dst, _src);
return;
}
if (bb < 0 || bb > 31)
{
decodeBlockEtc2ModePlanar(_dst, _src);
return;
}
// Etc1
rgb[0] = bitRangeConvert(rgb[0], 5, 8);
rgb[1] = bitRangeConvert(rgb[1], 5, 8);
rgb[2] = bitRangeConvert(rgb[2], 5, 8);
rgb[4] = bitRangeConvert(rgb[4], 5, 8);
rgb[5] = bitRangeConvert(rgb[5], 5, 8);
rgb[6] = bitRangeConvert(rgb[6], 5, 8);
rgb[4] = bitRangeConvert(rr, 5, 8);
rgb[5] = bitRangeConvert(gg, 5, 8);
rgb[6] = bitRangeConvert(bb, 5, 8);
}
else
{
@ -525,12 +775,13 @@ namespace bgfx
const uint32_t color = block<<2;
const uint32_t idx = (ii&0xc) | ( (ii & 0x3)<<4);
const uint32_t lsbi = indexLsb & 1;
const uint32_t msbi = indexMsb & 1;
const int32_t mod = s_mod[table[block] ][lsbi + msbi*2];
const uint32_t msbi = (indexMsb & 1)<<1;
const int32_t mod = s_etc1Mod[table[block] ][lsbi | msbi];
_dst[idx + 0] = uint8_satadd(rgb[color+2], mod);
_dst[idx + 1] = uint8_satadd(rgb[color+1], mod);
_dst[idx + 2] = uint8_satadd(rgb[color+0], mod);
_dst[idx + 3] = 255;
indexLsb >>= 1;
indexMsb >>= 1;
@ -544,12 +795,13 @@ namespace bgfx
const uint32_t color = block<<2;
const uint32_t idx = (ii&0xc) | ( (ii & 0x3)<<4);
const uint32_t lsbi = indexLsb & 1;
const uint32_t msbi = indexMsb & 1;
const int32_t mod = s_mod[table[block] ][lsbi + msbi*2];
const uint32_t msbi = (indexMsb & 1)<<1;
const int32_t mod = s_etc1Mod[table[block] ][lsbi | msbi];
_dst[idx + 0] = uint8_satadd(rgb[color+2], mod);
_dst[idx + 1] = uint8_satadd(rgb[color+1], mod);
_dst[idx + 2] = uint8_satadd(rgb[color+0], mod);
_dst[idx + 3] = 255;
indexLsb >>= 1;
indexMsb >>= 1;
@ -1197,11 +1449,12 @@ namespace bgfx
break;
case TextureFormat::ETC1:
case TextureFormat::ETC2:
for (uint32_t yy = 0; yy < height; ++yy)
{
for (uint32_t xx = 0; xx < width; ++xx)
{
decodeBlockEtc1(temp, src);
decodeBlockEtc12(temp, src);
src += 8;
uint8_t* dst = &_dst[(yy*pitch+xx*4)*4];
@ -1213,11 +1466,6 @@ namespace bgfx
}
break;
case TextureFormat::ETC2:
BX_WARN(false, "ETC2 decoder is not implemented.");
imageCheckerboard(_width, _height, 16, UINT32_C(0xff000000), UINT32_C(0xff0000ff), _dst);
break;
case TextureFormat::ETC2A:
BX_WARN(false, "ETC2A decoder is not implemented.");
imageCheckerboard(_width, _height, 16, UINT32_C(0xff000000), UINT32_C(0xff00ff00), _dst);