improve image decoders
This commit is contained in:
+62
-54
@@ -1,27 +1,35 @@
|
|||||||
#include "dxtc.h"
|
#include "dxtc.h"
|
||||||
|
#include "common.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static inline uint_fast32_t color(uint_fast32_t r, uint_fast32_t g, uint_fast32_t b, uint_fast32_t a)
|
static inline uint_fast32_t color(uint_fast8_t r, uint_fast8_t g, uint_fast8_t b, uint_fast8_t a)
|
||||||
{
|
{
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
return r | g << 8 | b << 16 | a << 24;
|
return r | g << 8 | b << 16 | a << 24;
|
||||||
|
#else
|
||||||
|
return a | b << 8 | g << 16 | r << 24;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void rgb565(const uint_fast16_t c, int* r, int* g, int* b)
|
static inline void rgb565(const uint16_t d, uint8_t* r, uint8_t* g, uint8_t* b)
|
||||||
{
|
{
|
||||||
*r = (c & 0xf800) >> 8;
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
*g = (c & 0x07e0) >> 3;
|
*r = (d >> 8 & 0xf8) | (d >> 13);
|
||||||
*b = (c & 0x001f) << 3;
|
*g = (d >> 3 & 0xfc) | (d >> 9 & 3);
|
||||||
*r |= *r >> 5;
|
*b = (d << 3) | (d >> 2 & 7);
|
||||||
*g |= *g >> 6;
|
#else
|
||||||
*b |= *b >> 5;
|
*r = (d & 0xf8) | (d >> 5 & 7);
|
||||||
|
*g = (d << 5 & 0xe0) | (d >> 11 & 0x1c) | (d >> 1 & 3);
|
||||||
|
*b = (d >> 5 & 0xf8) | (d >> 10 & 0x7);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void decode_dxt1_block(const uint64_t* data, uint32_t* outbuf)
|
static inline void decode_dxt1_block(const uint8_t* data, uint32_t* outbuf)
|
||||||
{
|
{
|
||||||
int r0, g0, b0, r1, g1, b1;
|
uint8_t r0, g0, b0, r1, g1, b1;
|
||||||
int q0 = ((uint16_t*)data)[0];
|
int q0 = *(uint16_t*)(data);
|
||||||
int q1 = ((uint16_t*)data)[1];
|
int q1 = *(uint16_t*)(data + 2);
|
||||||
rgb565(q0, &r0, &g0, &b0);
|
rgb565(q0, &r0, &g0, &b0);
|
||||||
rgb565(q1, &r1, &g1, &b1);
|
rgb565(q1, &r1, &g1, &b1);
|
||||||
uint_fast32_t c[4] = { color(r0, g0, b0, 255), color(r1, g1, b1, 255) };
|
uint_fast32_t c[4] = { color(r0, g0, b0, 255), color(r1, g1, b1, 255) };
|
||||||
@@ -30,32 +38,39 @@ static inline void decode_dxt1_block(const uint64_t* data, uint32_t* outbuf)
|
|||||||
c[3] = color((r0 + r1 * 2) / 3, (g0 + g1 * 2) / 3, (b0 + b1 * 2) / 3, 255);
|
c[3] = color((r0 + r1 * 2) / 3, (g0 + g1 * 2) / 3, (b0 + b1 * 2) / 3, 255);
|
||||||
} else {
|
} else {
|
||||||
c[2] = color((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 255);
|
c[2] = color((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 255);
|
||||||
|
c[3] = color(0, 0, 0, 255);
|
||||||
}
|
}
|
||||||
uint_fast32_t d = *data >> 32;
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
uint_fast32_t d = *(uint32_t*)(data + 4);
|
||||||
|
#else
|
||||||
|
uint_fast32_t d = data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24;
|
||||||
|
#endif
|
||||||
for (int i = 0; i < 16; i++, d >>= 2)
|
for (int i = 0; i < 16; i++, d >>= 2)
|
||||||
outbuf[i] = c[d & 3];
|
outbuf[i] = c[d & 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_dxt1(const uint64_t* data, const int w, const int h, uint32_t* image)
|
void decode_dxt1(const uint8_t* data, const int w, const int h, uint32_t* image)
|
||||||
{
|
{
|
||||||
int bcw = (w + 3) / 4;
|
int num_blocks_x = (w + 3) / 4;
|
||||||
int bch = (h + 3) / 4;
|
int num_blocks_y = (h + 3) / 4;
|
||||||
int clen_last = (w + 3) % 4 + 1;
|
int copy_length_last = (w + 3) % 4 + 1;
|
||||||
uint32_t buf[16];
|
uint32_t buf[16];
|
||||||
const uint64_t* d = data;
|
uint32_t* buf_end = buf + 16;
|
||||||
for (int t = 0; t < bch; t++) {
|
const uint8_t* d = data;
|
||||||
for (int s = 0; s < bcw; s++, d++) {
|
for (int t = 0; t < num_blocks_y; t++) {
|
||||||
|
for (int s = 0; s < num_blocks_x; s++, d += 8) {
|
||||||
decode_dxt1_block(d, buf);
|
decode_dxt1_block(d, buf);
|
||||||
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
|
int copy_length = (s < num_blocks_x - 1 ? 4 : copy_length_last) * 4;
|
||||||
for (int i = 0, y = h - t * 4 - 1; i < 4 && y >= 0; i++, y--)
|
uint32_t* b = buf;
|
||||||
memcpy(image + y * w + s * 4, buf + i * 4, clen);
|
for (int y = h - t * 4 - 1; b < buf_end && y >= 0; b += 4, y--)
|
||||||
|
memcpy(image + y * w + s * 4, b, copy_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void decode_dxt5_block(const uint64_t* data, uint32_t* outbuf)
|
static inline void decode_dxt5_block(const uint8_t* data, uint32_t* outbuf)
|
||||||
{
|
{
|
||||||
uint_fast32_t a[8] = { ((uint8_t*)data)[0], ((uint8_t*)data)[1] };
|
uint_fast32_t a[8] = { data[0], data[1] };
|
||||||
if (a[0] > a[1]) {
|
if (a[0] > a[1]) {
|
||||||
a[2] = (a[0] * 6 + a[1]) / 7;
|
a[2] = (a[0] * 6 + a[1]) / 7;
|
||||||
a[3] = (a[0] * 5 + a[1] * 2) / 7;
|
a[3] = (a[0] * 5 + a[1] * 2) / 7;
|
||||||
@@ -68,43 +83,36 @@ static inline void decode_dxt5_block(const uint64_t* data, uint32_t* outbuf)
|
|||||||
a[3] = (a[0] * 3 + a[1] * 2) / 5;
|
a[3] = (a[0] * 3 + a[1] * 2) / 5;
|
||||||
a[4] = (a[0] * 2 + a[1] * 3) / 5;
|
a[4] = (a[0] * 2 + a[1] * 3) / 5;
|
||||||
a[5] = (a[0] + a[1] * 4) / 5;
|
a[5] = (a[0] + a[1] * 4) / 5;
|
||||||
|
a[6] = 0;
|
||||||
a[7] = 255;
|
a[7] = 255;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
a[i] <<= 24;
|
a[i] = color(255, 255, 255, a[i]);
|
||||||
|
decode_dxt1_block(data + 8, outbuf);
|
||||||
int r0, g0, b0, r1, g1, b1;
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
int q0 = ((uint16_t*)(data + 1))[0];
|
uint_fast64_t d = *(uint64_t*)data >> 16;
|
||||||
int q1 = ((uint16_t*)(data + 1))[1];
|
#else
|
||||||
rgb565(q0, &r0, &g0, &b0);
|
uint_fast64_t d = data[2] | data[3] << 8 | data[4] << 16 | data[5] << 24 | data[6] << 32 | data[7] << 40;
|
||||||
rgb565(q1, &r1, &g1, &b1);
|
#endif
|
||||||
uint_fast32_t c[4] = { color(r0, g0, b0, 0), color(r1, g1, b1, 0) };
|
for (int i = 0; i < 16; i++, d >>= 3)
|
||||||
if (q0 > q1) {
|
outbuf[i] &= a[d & 7];
|
||||||
c[2] = color((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 0);
|
|
||||||
c[3] = color((r0 + r1 * 2) / 3, (g0 + g1 * 2) / 3, (b0 + b1 * 2) / 3, 0);
|
|
||||||
} else {
|
|
||||||
c[2] = color((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint_fast64_t da = *data >> 16;
|
|
||||||
uint_fast32_t dc = *(data + 1) >> 32;
|
|
||||||
for (int i = 0; i < 16; i++, da >>= 3, dc >>= 2)
|
|
||||||
outbuf[i] = a[da & 7] | c[dc & 3];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_dxt5(const uint64_t* data, const int w, const int h, uint32_t* image)
|
void decode_dxt5(const uint8_t* data, const int w, const int h, uint32_t* image)
|
||||||
{
|
{
|
||||||
int bcw = (w + 3) / 4;
|
int num_blocks_x = (w + 3) / 4;
|
||||||
int bch = (h + 3) / 4;
|
int num_blocks_y = (h + 3) / 4;
|
||||||
int clen_last = (w + 3) % 4 + 1;
|
int copy_length_last = (w + 3) % 4 + 1;
|
||||||
uint32_t buf[16];
|
uint32_t buf[16];
|
||||||
const uint64_t* d = data;
|
uint32_t *buf_end = buf + 16;
|
||||||
for (int t = 0; t < bch; t++) {
|
const uint8_t* d = data;
|
||||||
for (int s = 0; s < bcw; s++, d += 2) {
|
for (int t = 0; t < num_blocks_y; t++) {
|
||||||
|
for (int s = 0; s < num_blocks_x; s++, d += 16) {
|
||||||
decode_dxt5_block(d, buf);
|
decode_dxt5_block(d, buf);
|
||||||
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
|
int copy_length = (s < num_blocks_x - 1 ? 4 : copy_length_last) * 4;
|
||||||
for (int i = 0, y = h - t * 4 - 1; i < 4 && y >= 0; i++, y--)
|
uint32_t *b = buf;
|
||||||
memcpy(image + y * w + s * 4, buf + i * 4, clen);
|
for (int y = h - t * 4 - 1; b < buf_end && y >= 0; b += 4, y--)
|
||||||
|
memcpy(image + y * w + s * 4, b, copy_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void decode_dxt1(const uint64_t*, const int, const int, uint32_t*);
|
void decode_dxt1(const uint8_t*, const int, const int, uint32_t*);
|
||||||
void decode_dxt5(const uint64_t*, const int, const int, uint32_t*);
|
void decode_dxt5(const uint8_t*, const int, const int, uint32_t*);
|
||||||
|
|
||||||
#endif /* end of include guard: DXTC_H */
|
#endif /* end of include guard: DXTC_H */
|
||||||
|
|||||||
+114
-4
@@ -6,6 +6,10 @@
|
|||||||
const uint_fast8_t WriteOrderTable[16] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
|
const uint_fast8_t WriteOrderTable[16] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
|
||||||
const uint_fast8_t WriteOrderTableRev[16] = { 15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0 };
|
const uint_fast8_t WriteOrderTableRev[16] = { 15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0 };
|
||||||
const uint_fast8_t Etc1ModifierTable[8][2] = { { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, { 18, 60 }, { 24, 80 }, { 33, 106 }, { 47, 183 } };
|
const uint_fast8_t Etc1ModifierTable[8][2] = { { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, { 18, 60 }, { 24, 80 }, { 33, 106 }, { 47, 183 } };
|
||||||
|
const uint_fast8_t Etc2aModifierTable[2][8][2] = {
|
||||||
|
{ { 0, 8 }, { 0, 17 }, { 0, 29 }, { 0, 42 }, { 0, 60 }, { 0, 80 }, { 0, 106 }, { 0, 183 } },
|
||||||
|
{ { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, { 18, 60 }, { 24, 80 }, { 33, 106 }, { 47, 183 } }
|
||||||
|
};
|
||||||
const uint_fast8_t Etc1SubblockTable[2][16] = { { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 } };
|
const uint_fast8_t Etc1SubblockTable[2][16] = { { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 } };
|
||||||
const uint_fast8_t Etc2DistanceTable[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
|
const uint_fast8_t Etc2DistanceTable[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
|
||||||
const int_fast8_t Etc2AlphaModTable[16][8] = {
|
const int_fast8_t Etc2AlphaModTable[16][8] = {
|
||||||
@@ -27,6 +31,12 @@ const int_fast8_t Etc2AlphaModTable[16][8] = {
|
|||||||
{ -3, -5, -7, -9, 2, 4, 6, 8 }
|
{ -3, -5, -7, -9, 2, 4, 6, 8 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
static const uint_fast32_t TRANSPARENT_MASK = 0x00ffffff;
|
||||||
|
#else
|
||||||
|
static const uint_fast32_t TRANSPARENT_MASK = 0xffffff00;
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline uint_fast32_t color(uint_fast8_t r, uint_fast8_t g, uint_fast8_t b, uint_fast8_t a)
|
static inline uint_fast32_t color(uint_fast8_t r, uint_fast8_t g, uint_fast8_t b, uint_fast8_t a)
|
||||||
{
|
{
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
@@ -46,6 +56,11 @@ static inline uint32_t applicate_color(uint_fast8_t c[3], int_fast16_t m)
|
|||||||
return color(clamp(c[0] + m), clamp(c[1] + m), clamp(c[2] + m), 255);
|
return color(clamp(c[0] + m), clamp(c[1] + m), clamp(c[2] + m), 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t applicate_color_alpha(uint_fast8_t c[3], int_fast16_t m, int transparent)
|
||||||
|
{
|
||||||
|
return color(clamp(c[0] + m), clamp(c[1] + m), clamp(c[2] + m), transparent ? 0 : 255);
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint32_t applicate_color_raw(uint_fast8_t c[3])
|
static inline uint32_t applicate_color_raw(uint_fast8_t c[3])
|
||||||
{
|
{
|
||||||
return color(c[0], c[1], c[2], 255);
|
return color(c[0], c[1], c[2], 255);
|
||||||
@@ -212,6 +227,103 @@ static inline void decode_etc2_block(const uint8_t* data, uint32_t* outbuf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void decode_etc2a1_block(const uint8_t* data, uint32_t* outbuf)
|
||||||
|
{
|
||||||
|
uint_fast16_t j = data[6] << 8 | data[7]; // 15 -> 0
|
||||||
|
uint_fast32_t k = data[4] << 8 | data[5]; // 31 -> 16
|
||||||
|
uint_fast8_t c[3][3] = {};
|
||||||
|
|
||||||
|
int obaq = data[3] >> 1 & 1;
|
||||||
|
|
||||||
|
// diff bit == 1
|
||||||
|
uint_fast8_t r = data[0] & 0xf8;
|
||||||
|
int_fast16_t dr = (data[0] << 3 & 0x18) - (data[0] << 3 & 0x20);
|
||||||
|
uint_fast8_t g = data[1] & 0xf8;
|
||||||
|
int_fast16_t dg = (data[1] << 3 & 0x18) - (data[1] << 3 & 0x20);
|
||||||
|
uint_fast8_t b = data[2] & 0xf8;
|
||||||
|
int_fast16_t db = (data[2] << 3 & 0x18) - (data[2] << 3 & 0x20);
|
||||||
|
if (r + dr < 0 || r + dr > 255) {
|
||||||
|
// T
|
||||||
|
c[0][0] = (data[0] << 3 & 0xc0) | (data[0] << 4 & 0x30) | (data[0] >> 1 & 0xc) | (data[0] & 3);
|
||||||
|
c[0][1] = (data[1] & 0xf0) | data[1] >> 4;
|
||||||
|
c[0][2] = (data[1] & 0x0f) | data[1] << 4;
|
||||||
|
c[1][0] = (data[2] & 0xf0) | data[2] >> 4;
|
||||||
|
c[1][1] = (data[2] & 0x0f) | data[2] << 4;
|
||||||
|
c[1][2] = (data[3] & 0xf0) | data[3] >> 4;
|
||||||
|
const uint_fast8_t d = Etc2DistanceTable[(data[3] >> 1 & 6) | (data[3] & 1)];
|
||||||
|
uint_fast32_t color_set[4] = { applicate_color_raw(c[0]), applicate_color(c[1], d), applicate_color_raw(c[1]), applicate_color(c[1], -d) };
|
||||||
|
k <<= 1;
|
||||||
|
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
|
||||||
|
int index = (k & 2) | (j & 1);
|
||||||
|
outbuf[WriteOrderTable[i]] = color_set[index];
|
||||||
|
if (!obaq && index == 2)
|
||||||
|
outbuf[WriteOrderTable[i]] &= TRANSPARENT_MASK;
|
||||||
|
}
|
||||||
|
} else if (g + dg < 0 || g + dg > 255) {
|
||||||
|
// H
|
||||||
|
c[0][0] = (data[0] << 1 & 0xf0) | (data[0] >> 3 & 0xf);
|
||||||
|
c[0][1] = (data[0] << 5 & 0xe0) | (data[1] & 0x10);
|
||||||
|
c[0][1] |= c[0][1] >> 4;
|
||||||
|
c[0][2] = (data[1] & 8) | (data[1] << 1 & 6) | data[2] >> 7;
|
||||||
|
c[0][2] |= c[0][2] << 4;
|
||||||
|
c[1][0] = (data[2] << 1 & 0xf0) | (data[2] >> 3 & 0xf);
|
||||||
|
c[1][1] = (data[2] << 5 & 0xe0) | (data[3] >> 3 & 0x10);
|
||||||
|
c[1][1] |= c[1][1] >> 4;
|
||||||
|
c[1][2] = (data[3] << 1 & 0xf0) | (data[3] >> 3 & 0xf);
|
||||||
|
uint_fast8_t d = (data[3] & 4) | (data[3] << 1 & 2);
|
||||||
|
if (c[0][0] > c[1][0] || (c[0][0] == c[1][0] && (c[0][1] > c[1][1] || (c[0][1] == c[1][1] && c[0][2] >= c[1][2]))))
|
||||||
|
++d;
|
||||||
|
d = Etc2DistanceTable[d];
|
||||||
|
uint_fast32_t color_set[4] = { applicate_color(c[0], d), applicate_color(c[0], -d), applicate_color(c[1], d), applicate_color(c[1], -d) };
|
||||||
|
k <<= 1;
|
||||||
|
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
|
||||||
|
int index = (k & 2) | (j & 1);
|
||||||
|
outbuf[WriteOrderTable[i]] = color_set[index];
|
||||||
|
if (!obaq && index == 2)
|
||||||
|
outbuf[WriteOrderTable[i]] &= TRANSPARENT_MASK;
|
||||||
|
}
|
||||||
|
} else if (b + db < 0 || b + db > 255) {
|
||||||
|
// planar
|
||||||
|
c[0][0] = (data[0] << 1 & 0xfc) | (data[0] >> 5 & 3);
|
||||||
|
c[0][1] = (data[0] << 7 & 0x80) | (data[1] & 0x7e) | (data[0] & 1);
|
||||||
|
c[0][2] = (data[1] << 7 & 0x80) | (data[2] << 2 & 0x60) | (data[2] << 3 & 0x18) | (data[3] >> 5 & 4);
|
||||||
|
c[0][2] |= c[0][2] >> 6;
|
||||||
|
c[1][0] = (data[3] << 1 & 0xf8) | (data[3] << 2 & 4) | (data[3] >> 5 & 3);
|
||||||
|
c[1][1] = (data[4] & 0xfe) | data[4] >> 7;
|
||||||
|
c[1][2] = (data[4] << 7 & 0x80) | (data[5] >> 1 & 0x7c);
|
||||||
|
c[1][2] |= c[1][2] >> 6;
|
||||||
|
c[2][0] = (data[5] << 5 & 0xe0) | (data[6] >> 3 & 0x1c) | (data[5] >> 1 & 3);
|
||||||
|
c[2][1] = (data[6] << 3 & 0xf8) | (data[7] >> 5 & 0x6) | (data[6] >> 4 & 1);
|
||||||
|
c[2][2] = data[7] << 2 | (data[7] >> 4 & 3);
|
||||||
|
for (int y = 0, i = 0; y < 4; y++) {
|
||||||
|
for (int x = 0; x < 4; x++, i++) {
|
||||||
|
uint8_t r = clamp((x * (c[1][0] - c[0][0]) + y * (c[2][0] - c[0][0]) + 4 * c[0][0] + 2) >> 2);
|
||||||
|
uint8_t g = clamp((x * (c[1][1] - c[0][1]) + y * (c[2][1] - c[0][1]) + 4 * c[0][1] + 2) >> 2);
|
||||||
|
uint8_t b = clamp((x * (c[1][2] - c[0][2]) + y * (c[2][2] - c[0][2]) + 4 * c[0][2] + 2) >> 2);
|
||||||
|
outbuf[i] = color(r, g, b, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// differential
|
||||||
|
const uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
|
||||||
|
const uint_fast8_t* table = Etc1SubblockTable[data[3] & 1];
|
||||||
|
c[0][0] = r | r >> 5;
|
||||||
|
c[0][1] = g | g >> 5;
|
||||||
|
c[0][2] = b | b >> 5;
|
||||||
|
c[1][0] = r + dr;
|
||||||
|
c[1][1] = g + dg;
|
||||||
|
c[1][2] = b + db;
|
||||||
|
c[1][0] |= c[1][0] >> 5;
|
||||||
|
c[1][1] |= c[1][1] >> 5;
|
||||||
|
c[1][2] |= c[1][2] >> 5;
|
||||||
|
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
|
||||||
|
uint_fast8_t s = table[i];
|
||||||
|
uint_fast8_t m = Etc2aModifierTable[obaq][code[s]][j & 1];
|
||||||
|
outbuf[WriteOrderTable[i]] = applicate_color_alpha(c[s], k & 1 ? -m : m, !obaq && (k & 1) && !(j & 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void decode_etc2a8_block(const uint8_t* data, uint32_t* outbuf)
|
static inline void decode_etc2a8_block(const uint8_t* data, uint32_t* outbuf)
|
||||||
{
|
{
|
||||||
if (data[1] & 0xf0) {
|
if (data[1] & 0xf0) {
|
||||||
@@ -256,10 +368,8 @@ void decode_etc2a1(const void* data, const int w, const int h, uint32_t* image)
|
|||||||
uint32_t* buf_end = buf + 16;
|
uint32_t* buf_end = buf + 16;
|
||||||
const uint8_t* d = (uint8_t*)data;
|
const uint8_t* d = (uint8_t*)data;
|
||||||
for (int by = 0; by < num_blocks_y; by++) {
|
for (int by = 0; by < num_blocks_y; by++) {
|
||||||
for (int bx = 0, x = 0; bx < num_blocks_x; bx++, d += 9, x += 4) {
|
for (int bx = 0, x = 0; bx < num_blocks_x; bx++, d += 8, x += 4) {
|
||||||
decode_etc2_block(d + 1, buf);
|
decode_etc2a1_block(d, buf);
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
((uint8_t*)(buf + i))[3] = d[0];
|
|
||||||
int copy_length = (bx < num_blocks_x - 1 ? 4 : copy_length_last) * 4;
|
int copy_length = (bx < num_blocks_x - 1 ? 4 : copy_length_last) * 4;
|
||||||
uint32_t* b = buf;
|
uint32_t* b = buf;
|
||||||
for (int y = h - by * 4 - 1; b < buf_end && y >= 0; y--, b += 4)
|
for (int y = h - by * 4 - 1; b < buf_end && y >= 0; y--, b += 4)
|
||||||
|
|||||||
@@ -23,6 +23,23 @@ static VALUE rb_decode_a8(VALUE self, VALUE rb_data, VALUE size)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode image from R8 binary
|
||||||
|
*
|
||||||
|
* @param [String] rb_data binary to decode
|
||||||
|
* @param [Integer] size width * height
|
||||||
|
* @return [String] decoded rgb binary
|
||||||
|
*/
|
||||||
|
static VALUE rb_decode_r8(VALUE self, VALUE rb_data, VALUE size)
|
||||||
|
{
|
||||||
|
if (RSTRING_LEN(rb_data) < FIX2LONG(size))
|
||||||
|
rb_raise(rb_eStandardError, "Data size is not enough.");
|
||||||
|
VALUE ret = rb_str_buf_new(FIX2LONG(size) * 3);
|
||||||
|
decode_r8((uint8_t*)RSTRING_PTR(rb_data), FIX2INT(size), (uint8_t*)RSTRING_PTR(ret));
|
||||||
|
rb_str_set_len(ret, FIX2LONG(size) * 3);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode image from R16 binary
|
* Decode image from R16 binary
|
||||||
*
|
*
|
||||||
@@ -107,11 +124,10 @@ static VALUE rb_decode_etc2(VALUE self, VALUE rb_data, VALUE w, VALUE h)
|
|||||||
*/
|
*/
|
||||||
static VALUE rb_decode_etc2a1(VALUE self, VALUE rb_data, VALUE w, VALUE h)
|
static VALUE rb_decode_etc2a1(VALUE self, VALUE rb_data, VALUE w, VALUE h)
|
||||||
{
|
{
|
||||||
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 9)
|
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 8)
|
||||||
rb_raise(rb_eStandardError, "Data size is not enough.");
|
rb_raise(rb_eStandardError, "Data size is not enough.");
|
||||||
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
||||||
decode_etc2a8((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h),
|
decode_etc2a1((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
|
||||||
image);
|
|
||||||
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
||||||
free(image);
|
free(image);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -130,8 +146,7 @@ static VALUE rb_decode_etc2a8(VALUE self, VALUE rb_data, VALUE w, VALUE h)
|
|||||||
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 16)
|
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 16)
|
||||||
rb_raise(rb_eStandardError, "Data size is not enough.");
|
rb_raise(rb_eStandardError, "Data size is not enough.");
|
||||||
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
||||||
decode_etc2a8((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h),
|
decode_etc2a8((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
|
||||||
image);
|
|
||||||
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
||||||
free(image);
|
free(image);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -152,9 +167,8 @@ static VALUE rb_decode_astc(VALUE self, VALUE rb_data, VALUE w, VALUE h,
|
|||||||
{
|
{
|
||||||
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + FIX2LONG(bw) - 1) / FIX2LONG(bw)) * ((FIX2LONG(h) + FIX2LONG(bh) - 1) / FIX2LONG(bh)) * 16)
|
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + FIX2LONG(bw) - 1) / FIX2LONG(bw)) * ((FIX2LONG(h) + FIX2LONG(bh) - 1) / FIX2LONG(bh)) * 16)
|
||||||
rb_raise(rb_eStandardError, "Data size is not enough.");
|
rb_raise(rb_eStandardError, "Data size is not enough.");
|
||||||
const uint8_t* data = (uint8_t*)RSTRING_PTR(rb_data);
|
|
||||||
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
||||||
decode_astc(data, FIX2INT(w), FIX2INT(h), FIX2INT(bw), FIX2INT(bh), image);
|
decode_astc((uint8_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), FIX2INT(bw), FIX2INT(bh), image);
|
||||||
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
||||||
free(image);
|
free(image);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -173,7 +187,7 @@ static VALUE rb_decode_dxt1(VALUE self, VALUE rb_data, VALUE w, VALUE h)
|
|||||||
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 8)
|
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 8)
|
||||||
rb_raise(rb_eStandardError, "Data size is not enough.");
|
rb_raise(rb_eStandardError, "Data size is not enough.");
|
||||||
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
||||||
decode_dxt1((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
|
decode_dxt1((uint8_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
|
||||||
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
||||||
free(image);
|
free(image);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -192,7 +206,7 @@ static VALUE rb_decode_dxt5(VALUE self, VALUE rb_data, VALUE w, VALUE h)
|
|||||||
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 16)
|
if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 16)
|
||||||
rb_raise(rb_eStandardError, "Data size is not enough.");
|
rb_raise(rb_eStandardError, "Data size is not enough.");
|
||||||
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
uint32_t* image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
|
||||||
decode_dxt5((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
|
decode_dxt5((uint8_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
|
||||||
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
|
||||||
free(image);
|
free(image);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -203,6 +217,7 @@ void Init_native()
|
|||||||
VALUE mMikunyan = rb_define_module("Mikunyan");
|
VALUE mMikunyan = rb_define_module("Mikunyan");
|
||||||
VALUE mDecodeHelper = rb_define_module_under(mMikunyan, "DecodeHelper");
|
VALUE mDecodeHelper = rb_define_module_under(mMikunyan, "DecodeHelper");
|
||||||
rb_define_module_function(mDecodeHelper, "decode_a8", rb_decode_a8, 2);
|
rb_define_module_function(mDecodeHelper, "decode_a8", rb_decode_a8, 2);
|
||||||
|
rb_define_module_function(mDecodeHelper, "decode_r8", rb_decode_r8, 2);
|
||||||
rb_define_module_function(mDecodeHelper, "decode_r16", rb_decode_r16, 3);
|
rb_define_module_function(mDecodeHelper, "decode_r16", rb_decode_r16, 3);
|
||||||
rb_define_module_function(mDecodeHelper, "decode_rgb565", rb_decode_rgb565, 3);
|
rb_define_module_function(mDecodeHelper, "decode_rgb565", rb_decode_rgb565, 3);
|
||||||
rb_define_module_function(mDecodeHelper, "decode_etc1", rb_decode_etc1, 3);
|
rb_define_module_function(mDecodeHelper, "decode_etc1", rb_decode_etc1, 3);
|
||||||
|
|||||||
@@ -12,6 +12,16 @@ void decode_a8(const uint8_t* data, const int size, uint8_t* image)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decode_r8(const uint8_t* data, const int size, uint8_t* image)
|
||||||
|
{
|
||||||
|
const uint8_t *d = data, *d_end = data + size;
|
||||||
|
for (int i = 0; d < d_end; d++) {
|
||||||
|
image[i++] = *d;
|
||||||
|
image[i++] = 0;
|
||||||
|
image[i++] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void decode_r16(const uint16_t* data, const int size, const int endian_big, uint8_t* image)
|
void decode_r16(const uint16_t* data, const int size, const int endian_big, uint8_t* image)
|
||||||
{
|
{
|
||||||
const uint16_t *d = data, *d_end = data + size;
|
const uint16_t *d = data, *d_end = data + size;
|
||||||
@@ -20,16 +30,15 @@ void decode_r16(const uint16_t* data, const int size, const int endian_big, uint
|
|||||||
for (int i = 0; d < d_end; d++) {
|
for (int i = 0; d < d_end; d++) {
|
||||||
uint8_t c = *d >> 8;
|
uint8_t c = *d >> 8;
|
||||||
image[i++] = c;
|
image[i++] = c;
|
||||||
image[i++] = c;
|
image[i++] = 0;
|
||||||
image[i++] = c;
|
image[i++] = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Different endian
|
// Different endian
|
||||||
for (int i = 0; d < d_end; d++) {
|
for (int i = 0; d < d_end; d++) {
|
||||||
uint8_t c = *d;
|
image[i++] = *d;
|
||||||
image[i++] = c;
|
image[i++] = 0;
|
||||||
image[i++] = c;
|
image[i++] = 0;
|
||||||
image[i++] = c;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void decode_a8(const uint8_t*, const int, uint8_t*);
|
void decode_a8(const uint8_t*, const int, uint8_t*);
|
||||||
|
void decode_r8(const uint8_t*, const int, uint8_t*);
|
||||||
void decode_r16(const uint16_t*, const int, const int, uint8_t*);
|
void decode_r16(const uint16_t*, const int, const int, uint8_t*);
|
||||||
void decode_rgb565(const uint16_t*, const int, const int, uint8_t*);
|
void decode_rgb565(const uint16_t*, const int, const int, uint8_t*);
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ module Mikunyan
|
|||||||
when 62 # RG16
|
when 62 # RG16
|
||||||
decode_rg16(width, height, bin)
|
decode_rg16(width, height, bin)
|
||||||
when 63 # R8
|
when 63 # R8
|
||||||
decode_a8(width, height, bin)
|
decode_r8(width, height, bin)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -119,6 +119,15 @@ module Mikunyan
|
|||||||
ChunkyPNG::Image.from_rgb_stream(width, height, DecodeHelper.decode_a8(bin, width * height)).flip
|
ChunkyPNG::Image.from_rgb_stream(width, height, DecodeHelper.decode_a8(bin, width * height)).flip
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Decode image from R8 binary
|
||||||
|
# @param [Integer] width image width
|
||||||
|
# @param [Integer] height image height
|
||||||
|
# @param [String] bin binary to decode
|
||||||
|
# @return [ChunkyPNG::Image] decoded image
|
||||||
|
def self.decode_r8(width, height, bin)
|
||||||
|
ChunkyPNG::Image.from_rgb_stream(width, height, DecodeHelper.decode_r8(bin, width * height)).flip
|
||||||
|
end
|
||||||
|
|
||||||
# Decode image from ARGB4444 binary
|
# Decode image from ARGB4444 binary
|
||||||
# @param [Integer] width image width
|
# @param [Integer] width image width
|
||||||
# @param [Integer] height image height
|
# @param [Integer] height image height
|
||||||
@@ -240,14 +249,12 @@ module Mikunyan
|
|||||||
mem = String.new(capacity: width * height * 3)
|
mem = String.new(capacity: width * height * 3)
|
||||||
(width * height).times do |i|
|
(width * height).times do |i|
|
||||||
n = endian == :little ? BinUtils.get_int32_le(bin, i * 4) : BinUtils.get_int32_be(bin, i * 4)
|
n = endian == :little ? BinUtils.get_int32_le(bin, i * 4) : BinUtils.get_int32_be(bin, i * 4)
|
||||||
e = (n & 0xf8000000) >> 27
|
b = n >> 18 & 0x1ff
|
||||||
r = (n & 0x7fc0000) >> 9
|
g = n >> 9 & 0x1ff
|
||||||
g = (n & 0x3fe00) >> 9
|
r = n & 0x1ff
|
||||||
b = n & 0x1ff
|
scale = n >> 27 & 0x1f
|
||||||
r = (r / 512r + 1) * (2**(e - 15))
|
scale = 2**(scale - 24)
|
||||||
g = (g / 512r + 1) * (2**(e - 15))
|
BinUtils.append_int8!(mem, f2i(r * scale), f2i(g * scale), f2i(b * scale))
|
||||||
b = (b / 512r + 1) * (2**(e - 15))
|
|
||||||
BinUtils.append_int8!(mem, f2i(r), f2i(g), f2i(b))
|
|
||||||
end
|
end
|
||||||
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
|
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
|
||||||
end
|
end
|
||||||
@@ -441,24 +448,21 @@ module Mikunyan
|
|||||||
def self.create_astc_file(object)
|
def self.create_astc_file(object)
|
||||||
astc_list = {
|
astc_list = {
|
||||||
48 => 4, 49 => 5, 50 => 6, 51 => 8, 52 => 10, 53 => 12,
|
48 => 4, 49 => 5, 50 => 6, 51 => 8, 52 => 10, 53 => 12,
|
||||||
54 => 4, 55 => 5, 56 => 6, 57 => 8, 58 => 10, 59 => 12
|
54 => 4, 55 => 5, 56 => 6, 57 => 8, 58 => 10, 59 => 12,
|
||||||
|
66 => 4, 67 => 5, 68 => 6, 69 => 8, 70 => 10, 71 => 12
|
||||||
}
|
}
|
||||||
width = object['m_Width']
|
width = object['m_Width']&.value
|
||||||
height = object['m_Height']
|
height = object['m_Height']&.value
|
||||||
fmt = object['m_TextureFormat']
|
fmt = object['m_TextureFormat']&.value
|
||||||
bin = object['image data']
|
bin = object['image data']&.value
|
||||||
width = width.value if width.class == ObjectValue
|
return unless width && height && fmt && bin && astc_list[fmt]
|
||||||
height = height.value if height.class == ObjectValue
|
bin = object['m_StreamData']&.value if bin.empty?
|
||||||
fmt = fmt.value if fmt.class == ObjectValue
|
return unless bin
|
||||||
bin = bin.value if bin.class == ObjectValue
|
header = [0x13, 0xab, 0xa1, 0x5c, astc_list[fmt], astc_list[fmt], 1].pack('C*')
|
||||||
if width && height && fmt && astc_list[fmt]
|
header << [width].pack('V').byteslice(0, 3)
|
||||||
header = "\x13\xAB\xA1\x5C".force_encoding('ascii-8bit')
|
header << [height].pack('V').byteslice(0, 3)
|
||||||
header << [astc_list[fmt], astc_list[fmt], 1].pack('C*')
|
header << [1, 0, 0].pack('C*')
|
||||||
header << [width].pack('V').byteslice(0, 3)
|
header + bin
|
||||||
header << [height].pack('V').byteslice(0, 3)
|
|
||||||
header << "\x01\x00\x00"
|
|
||||||
header + bin
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# convert 16bit float
|
# convert 16bit float
|
||||||
|
|||||||
Reference in New Issue
Block a user