improve image decoders

This commit is contained in:
Ishotihadus
2019-12-10 23:46:30 +09:00
parent 2271b33cdd
commit aa29a229ea
7 changed files with 248 additions and 101 deletions
+62 -54
View File
@@ -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);
} }
} }
} }
+2 -2
View File
@@ -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
View File
@@ -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)
+24 -9
View File
@@ -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);
+15 -6
View File
@@ -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;
} }
} }
} }
+1
View File
@@ -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*);
+30 -26
View File
@@ -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