mikunyan 3.9.4 → 3.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +35 -41
  4. data/Rakefile +9 -0
  5. data/exe/mikunyan-image +12 -8
  6. data/ext/decoders/native/astc.c +760 -0
  7. data/ext/decoders/native/astc.h +8 -0
  8. data/ext/decoders/native/dxtc.c +104 -0
  9. data/ext/decoders/native/dxtc.h +9 -0
  10. data/ext/decoders/native/etc.c +271 -0
  11. data/ext/decoders/native/etc.h +11 -0
  12. data/ext/decoders/native/extconf.rb +8 -0
  13. data/ext/decoders/native/main.c +167 -0
  14. data/ext/decoders/native/rgb.c +26 -0
  15. data/ext/decoders/native/rgb.h +8 -0
  16. data/lib/mikunyan/asset.rb +13 -7
  17. data/lib/mikunyan/decoders/image_decoder.rb +40 -201
  18. data/lib/mikunyan/typetrees/00ad972a9b8de1baeacb62e297cbb968.dat +0 -0
  19. data/lib/mikunyan/typetrees/01ccfe05c6fbc7ff03dcf8afa8213ff5.dat +0 -0
  20. data/lib/mikunyan/typetrees/086efb68ee41abe4e98e1ae93ae96290.dat +0 -0
  21. data/lib/mikunyan/typetrees/10355709bc95355f57466913ac850d0b.dat +0 -0
  22. data/lib/mikunyan/typetrees/1e87d82d4fd058509a3c7866db0e7356.dat +0 -0
  23. data/lib/mikunyan/typetrees/26165a24a953362edb6a7078f6536c4b.dat +0 -0
  24. data/lib/mikunyan/typetrees/266d53113fa30d2b858f2768f92eaa14.dat +0 -0
  25. data/lib/mikunyan/typetrees/2d2b1d63eb2a68ed94bbf7f50fc21d7b.dat +0 -0
  26. data/lib/mikunyan/typetrees/434b934f757d042e20f52d8c2ae20843.dat +0 -0
  27. data/lib/mikunyan/typetrees/486ba4e15dbd6aea8ac1a064305889c8.dat +0 -0
  28. data/lib/mikunyan/typetrees/49ff511929094ac12ffaa4ab38ed7bd1.dat +0 -0
  29. data/lib/mikunyan/typetrees/4dbfaa1def6adb569b550804b19b4305.dat +0 -0
  30. data/lib/mikunyan/typetrees/5bc42b93159267aabba724a6a7923603.dat +0 -0
  31. data/lib/mikunyan/typetrees/66405447c6973a81e978410c391172fe.dat +0 -0
  32. data/lib/mikunyan/typetrees/6932d6d1d46264c8680a181056f98be2.dat +0 -0
  33. data/lib/mikunyan/typetrees/6974f6c74321933ec4ba7437a55be2c3.dat +0 -0
  34. data/lib/mikunyan/typetrees/69b01db128625aa95f1f92fb890ff045.dat +0 -0
  35. data/lib/mikunyan/typetrees/6f10d8f832d5adde6982d4515b3f0bb3.dat +0 -0
  36. data/lib/mikunyan/typetrees/761ca81f78491542badc37f810ab3455.dat +0 -0
  37. data/lib/mikunyan/typetrees/76ce55d4dbaf38f5c674ea9f0a344951.dat +0 -0
  38. data/lib/mikunyan/typetrees/7e050781d08ca9d10bc74beb7e91c3b5.dat +0 -0
  39. data/lib/mikunyan/typetrees/8198e72b2e2a96b9cfa38636b5565e13.dat +0 -0
  40. data/lib/mikunyan/typetrees/84c6ac46ef89030991cbbb3fd21d2889.dat +0 -0
  41. data/lib/mikunyan/typetrees/852794becbcf95f66992da2b96a69704.dat +0 -0
  42. data/lib/mikunyan/typetrees/961be27d12d60b1b3421191d5256a876.dat +0 -0
  43. data/lib/mikunyan/typetrees/96a47566b4e135078f690a4a69935d58.dat +0 -0
  44. data/lib/mikunyan/typetrees/97da5f4688e45a57c8b42d4f42497297.dat +0 -0
  45. data/lib/mikunyan/typetrees/97ec0712102a3ea3f1cf8c0a4e47c070.dat +0 -0
  46. data/lib/mikunyan/typetrees/9eabac6ec66ffe818e008883728fcc1b.dat +0 -0
  47. data/lib/mikunyan/typetrees/a372646834bcaf26eab1d21b29e39553.dat +0 -0
  48. data/lib/mikunyan/typetrees/a4f194097b08bc4c5019c3a4ea6f5cbd.dat +0 -0
  49. data/lib/mikunyan/typetrees/af863b6969b9b82be9450f0574339f65.dat +0 -0
  50. data/lib/mikunyan/typetrees/b0adafbe24f8148ebf01794ee6679925.dat +0 -0
  51. data/lib/mikunyan/typetrees/b14bcb0865632d1b2d6e215a000e4c0f.dat +0 -0
  52. data/lib/mikunyan/typetrees/b35bf02952f2946208ff6b4deca3a6a9.dat +0 -0
  53. data/lib/mikunyan/typetrees/b6bbd0e88d1feb636d89bd766ea5934f.dat +0 -0
  54. data/lib/mikunyan/typetrees/b78821b6aeb5b79c8961728a9f068024.dat +0 -0
  55. data/lib/mikunyan/typetrees/bea915a8ab3d9b55e80c969a22e692d3.dat +0 -0
  56. data/lib/mikunyan/typetrees/c184743520186f546000de20f4d19736.dat +0 -0
  57. data/lib/mikunyan/typetrees/d50ed13362e98df8096b2f735131fce5.dat +0 -0
  58. data/lib/mikunyan/typetrees/d871346d990bbc294d02f4c366bf1b6d.dat +0 -0
  59. data/lib/mikunyan/typetrees/d8e8eeb43589ccd7019398e56f6c16b0.dat +0 -0
  60. data/lib/mikunyan/typetrees/daea1bb1bba6613afb2cb001ca8fa0d4.dat +0 -0
  61. data/lib/mikunyan/typetrees/db088f9c2f2224da9f488879467856e5.dat +0 -0
  62. data/lib/mikunyan/typetrees/e7c5c01b0369574e9346ce846e1e8e63.dat +0 -0
  63. data/lib/mikunyan/typetrees/f123b055a61dfa7dc679d78cdaecd383.dat +0 -0
  64. data/lib/mikunyan/typetrees/f92d618c5266ea3a8ca770b6eca728c8.dat +0 -0
  65. data/lib/mikunyan/typetrees/fad2d0a58e9174708176102b418facf1.dat +0 -0
  66. data/lib/mikunyan/typetrees/ff001a2e51937aa5add9eaf9cd3d8ae4.dat +0 -0
  67. data/lib/mikunyan/version.rb +1 -1
  68. data/mikunyan.gemspec +1 -0
  69. metadata +63 -4
  70. data/lib/mikunyan/decoders/astc_block_decoder.rb +0 -526
@@ -0,0 +1,8 @@
1
+ #ifndef ASTC_H
2
+ #define ASTC_H
3
+
4
+ #include <stdint.h>
5
+
6
+ void decode_astc(const uint8_t*, const int, const int, const int, const int, uint32_t*);
7
+
8
+ #endif /* end of include guard: ASTC_H */
@@ -0,0 +1,104 @@
1
+ #include <stdint.h>
2
+ #include <string.h>
3
+ #include "dxtc.h"
4
+
5
+ static inline uint_fast32_t color(uint_fast32_t r, uint_fast32_t g, uint_fast32_t b, uint_fast32_t a) {
6
+ return r | g << 8 | b << 16 | a << 24;
7
+ }
8
+
9
+ static inline void rgb565(const uint_fast16_t c, int *r, int *g, int *b) {
10
+ *r = (c & 0xf800) >> 8;
11
+ *g = (c & 0x07e0) >> 3;
12
+ *b = (c & 0x001f) << 3;
13
+ *r |= *r >> 5;
14
+ *g |= *g >> 6;
15
+ *b |= *b >> 5;
16
+ }
17
+
18
+ static inline void decode_dxt1_block(const uint64_t *data, uint32_t *outbuf) {
19
+ int r0, g0, b0, r1, g1, b1;
20
+ int q0 = ((uint16_t*)data)[0];
21
+ int q1 = ((uint16_t*)data)[1];
22
+ rgb565(q0, &r0, &g0, &b0);
23
+ rgb565(q1, &r1, &g1, &b1);
24
+ uint_fast32_t c[4] = { color(r0, g0, b0, 255), color(r1, g1, b1, 255) };
25
+ if (q0 > q1) {
26
+ c[2] = color((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 255);
27
+ c[3] = color((r0 + r1 * 2) / 3, (g0 + g1 * 2) / 3, (b0 + b1 * 2) / 3, 255);
28
+ } else {
29
+ c[2] = color((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 255);
30
+ }
31
+ uint_fast32_t d = *data >> 32;
32
+ for (int i = 0; i < 16; i++, d >>= 2)
33
+ outbuf[i] = c[d & 3];
34
+ }
35
+
36
+ void decode_dxt1(const uint64_t *data, const int w, const int h, uint32_t *image) {
37
+ int bcw = (w + 3) / 4;
38
+ int bch = (h + 3) / 4;
39
+ int clen_last = (w + 3) % 4 + 1;
40
+ uint32_t buf[16];
41
+ const uint64_t *d = data;
42
+ for (int t = 0; t < bch; t++) {
43
+ for (int s = 0; s < bcw; s++, d++) {
44
+ decode_dxt1_block(d, buf);
45
+ int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
46
+ for (int i = 0, y = h - t * 4 - 1; i < 4 && y >= 0; i++, y--)
47
+ memcpy(image + y * w + s * 4, buf + i * 4, clen);
48
+ }
49
+ }
50
+ }
51
+
52
+ static inline void decode_dxt5_block(const uint64_t *data, uint32_t *outbuf) {
53
+ uint_fast32_t a[8] = { ((uint8_t*)data)[0], ((uint8_t*)data)[1] };
54
+ if (a[0] > a[1]) {
55
+ a[2] = (a[0] * 6 + a[1] ) / 7;
56
+ a[3] = (a[0] * 5 + a[1] * 2) / 7;
57
+ a[4] = (a[0] * 4 + a[1] * 3) / 7;
58
+ a[5] = (a[0] * 3 + a[1] * 4) / 7;
59
+ a[6] = (a[0] * 2 + a[1] * 5) / 7;
60
+ a[7] = (a[0] + a[1] * 6) / 7;
61
+ } else {
62
+ a[2] = (a[0] * 4 + a[1] ) / 5;
63
+ a[3] = (a[0] * 3 + a[1] * 2) / 5;
64
+ a[4] = (a[0] * 2 + a[1] * 3) / 5;
65
+ a[5] = (a[0] + a[1] * 4) / 5;
66
+ a[7] = 255;
67
+ }
68
+ for (int i = 0; i < 8; i++)
69
+ a[i] <<= 24;
70
+
71
+ int r0, g0, b0, r1, g1, b1;
72
+ int q0 = ((uint16_t*)(data + 1))[0];
73
+ int q1 = ((uint16_t*)(data + 1))[1];
74
+ rgb565(q0, &r0, &g0, &b0);
75
+ rgb565(q1, &r1, &g1, &b1);
76
+ uint_fast32_t c[4] = { color(r0, g0, b0, 0), color(r1, g1, b1, 0) };
77
+ if (q0 > q1) {
78
+ c[2] = color((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 0);
79
+ c[3] = color((r0 + r1 * 2) / 3, (g0 + g1 * 2) / 3, (b0 + b1 * 2) / 3, 0);
80
+ } else {
81
+ c[2] = color((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 0);
82
+ }
83
+
84
+ uint_fast64_t da = *data >> 16;
85
+ uint_fast32_t dc = *(data + 1) >> 32;
86
+ for (int i = 0; i < 16; i++, da >>= 3, dc >>= 2)
87
+ outbuf[i] = a[da & 7] | c[dc & 3];
88
+ }
89
+
90
+ void decode_dxt5(const uint64_t *data, const int w, const int h, uint32_t *image) {
91
+ int bcw = (w + 3) / 4;
92
+ int bch = (h + 3) / 4;
93
+ int clen_last = (w + 3) % 4 + 1;
94
+ uint32_t buf[16];
95
+ const uint64_t *d = data;
96
+ for (int t = 0; t < bch; t++) {
97
+ for (int s = 0; s < bcw; s++, d += 2) {
98
+ decode_dxt5_block(d, buf);
99
+ int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
100
+ for (int i = 0, y = h - t * 4 - 1; i < 4 && y >= 0; i++, y--)
101
+ memcpy(image + y * w + s * 4, buf + i * 4, clen);
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef DXTC_H
2
+ #define DXTC_H
3
+
4
+ #include <stdint.h>
5
+
6
+ void decode_dxt1(const uint64_t*, const int, const int, uint32_t*);
7
+ void decode_dxt5(const uint64_t*, const int, const int, uint32_t*);
8
+
9
+ #endif /* end of include guard: DXTC_H */
@@ -0,0 +1,271 @@
1
+ #include <stdint.h>
2
+ #include <string.h>
3
+ #include "etc.h"
4
+
5
+ uint_fast8_t WriteOrderTable[16] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
6
+ uint_fast8_t WriteOrderTableRev[16] = { 15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0 };
7
+ uint_fast8_t Etc1ModifierTable[8][2] = {{2, 8}, {5, 17}, {9, 29}, {13, 42}, {18, 60}, {24, 80}, {33, 106}, {47, 183}};
8
+ 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}};
9
+ uint_fast8_t Etc2DistanceTable[8] = {3, 6, 11, 16, 23, 32, 41, 64};
10
+ int_fast8_t Etc2AlphaModTable[16][8] = {
11
+ {-3, -6, -9, -15, 2, 5, 8, 14},
12
+ {-3, -7, -10, -13, 2, 6, 9, 12},
13
+ {-2, -5, -8, -13, 1, 4, 7, 12},
14
+ {-2, -4, -6, -13, 1, 3, 5, 12},
15
+ {-3, -6, -8, -12, 2, 5, 7, 11},
16
+ {-3, -7, -9, -11, 2, 6, 8, 10},
17
+ {-4, -7, -8, -11, 3, 6, 7, 10},
18
+ {-3, -5, -8, -11, 2, 4, 7, 10},
19
+ {-2, -6, -8, -10, 1, 5, 7, 9},
20
+ {-2, -5, -8, -10, 1, 4, 7, 9},
21
+ {-2, -4, -8, -10, 1, 3, 7, 9},
22
+ {-2, -5, -7, -10, 1, 4, 6, 9},
23
+ {-3, -4, -7, -10, 2, 3, 6, 9},
24
+ {-1, -2, -3, -10, 0, 1, 2, 9},
25
+ {-4, -6, -8, -9, 3, 5, 7, 8},
26
+ {-3, -5, -7, -9, 2, 4, 6, 8}
27
+ };
28
+
29
+ static inline uint_fast32_t color(uint_fast32_t r, uint_fast32_t g, uint_fast32_t b, uint_fast32_t a) {
30
+ return r | g << 8 | b << 16 | a << 24;
31
+ }
32
+
33
+ static inline uint_fast8_t clamp(const int n) {
34
+ return n < 0 ? 0 : n > 255 ? 255 : n;
35
+ }
36
+
37
+ static inline uint32_t applicate_color(uint_fast8_t c[3], int_fast16_t m) {
38
+ return color(clamp(c[0] + m), clamp(c[1] + m), clamp(c[2] + m), 255);
39
+ }
40
+
41
+ static inline uint32_t applicate_color_raw(uint_fast8_t c[3]) {
42
+ return color(c[0], c[1], c[2], 255);
43
+ }
44
+
45
+ static inline void decode_etc1_block(const uint8_t *data, uint32_t *outbuf) {
46
+ uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
47
+ uint_fast8_t *table = Etc1SubblockTable[data[3] & 1];
48
+ uint_fast8_t c[2][3];
49
+ if (data[3] & 2) {
50
+ c[0][0] = data[0] & 0xf8;
51
+ c[0][1] = data[1] & 0xf8;
52
+ c[0][2] = data[2] & 0xf8;
53
+ c[1][0] = c[0][0] + (data[0] << 3 & 0x18) - (data[0] << 3 & 0x20);
54
+ c[1][1] = c[0][1] + (data[1] << 3 & 0x18) - (data[1] << 3 & 0x20);
55
+ c[1][2] = c[0][2] + (data[2] << 3 & 0x18) - (data[2] << 3 & 0x20);
56
+ c[0][0] |= c[0][0] >> 5;
57
+ c[0][1] |= c[0][1] >> 5;
58
+ c[0][2] |= c[0][2] >> 5;
59
+ c[1][0] |= c[1][0] >> 5;
60
+ c[1][1] |= c[1][1] >> 5;
61
+ c[1][2] |= c[1][2] >> 5;
62
+ } else {
63
+ c[0][0] = data[0] & 0xf0 | data[0] >> 4;
64
+ c[1][0] = data[0] & 0x0f | data[0] << 4;
65
+ c[0][1] = data[1] & 0xf0 | data[1] >> 4;
66
+ c[1][1] = data[1] & 0x0f | data[1] << 4;
67
+ c[0][2] = data[2] & 0xf0 | data[2] >> 4;
68
+ c[1][2] = data[2] & 0x0f | data[2] << 4;
69
+ }
70
+
71
+ uint_fast16_t j = data[6] << 8 | data[7];
72
+ uint_fast16_t k = data[4] << 8 | data[5];
73
+ for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
74
+ uint_fast8_t s = table[i];
75
+ uint_fast8_t m = Etc1ModifierTable[code[s]][j & 1];
76
+ outbuf[WriteOrderTable[i]] = applicate_color(c[s], k & 1 ? -m : m);
77
+ }
78
+ }
79
+
80
+ void decode_etc1(const void *data, const int w, const int h, uint32_t *image) {
81
+ int bcw = (w + 3) / 4;
82
+ int bch = (h + 3) / 4;
83
+ int clen_last = (w + 3) % 4 + 1;
84
+ uint32_t buf[16];
85
+ const uint8_t *d = (uint8_t*)data;
86
+ for (int t = 0; t < bch; t++) {
87
+ for (int s = 0; s < bcw; s++, d += 8) {
88
+ decode_etc1_block(d, buf);
89
+ int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
90
+ for (int i = 0, y = h - t * 4 - 1; i < 4 && y >= 0; i++, y--)
91
+ memcpy(image + y * w + s * 4, buf + i * 4, clen);
92
+ }
93
+ }
94
+ }
95
+
96
+ static inline void decode_etc2_block(const uint8_t *data, uint32_t *outbuf) {
97
+ uint_fast16_t j = data[6] << 8 | data[7];
98
+ uint_fast16_t k = data[4] << 8 | data[5];
99
+ uint_fast8_t c[3][3] = {};
100
+
101
+ if (data[3] & 2) {
102
+ uint_fast8_t r = data[0] & 0xf8;
103
+ int_fast16_t dr = (data[0] << 3 & 0x18) - (data[0] << 3 & 0x20);
104
+ uint_fast8_t g = data[1] & 0xf8;
105
+ int_fast16_t dg = (data[1] << 3 & 0x18) - (data[1] << 3 & 0x20);
106
+ uint_fast8_t b = data[2] & 0xf8;
107
+ int_fast16_t db = (data[2] << 3 & 0x18) - (data[2] << 3 & 0x20);
108
+ if (r + dr < 0 || r + dr > 255) {
109
+ // T
110
+ c[0][0] = data[0] << 3 & 0xc0 | data[0] << 4 & 0x30 | data[0] >> 1 & 0xc | data[0] & 3;
111
+ c[0][1] = data[1] & 0xf0 | data[1] >> 4;
112
+ c[0][2] = data[1] & 0x0f | data[1] << 4;
113
+ c[1][0] = data[2] & 0xf0 | data[2] >> 4;
114
+ c[1][1] = data[2] & 0x0f | data[2] << 4;
115
+ c[1][2] = data[3] & 0xf0 | data[3] >> 4;
116
+ uint_fast8_t d = Etc2DistanceTable[data[3] >> 1 & 6 | data[3] & 1];
117
+ uint_fast32_t color_set[4] = {
118
+ applicate_color_raw(c[0]),
119
+ applicate_color(c[1], d),
120
+ applicate_color_raw(c[1]),
121
+ applicate_color(c[1], -d)
122
+ };
123
+ for (int i = 0; i < 16; i++, j >>= 1, k >>= 1)
124
+ outbuf[WriteOrderTable[i]] = color_set[k << 1 & 2 | j & 1];
125
+ } else if (g + dg < 0 || g + dg > 255) {
126
+ // H
127
+ c[0][0] = data[0] << 1 & 0xf0 | data[0] >> 3 & 0xf;
128
+ c[0][1] = data[0] << 5 & 0xe0 | data[1] & 0x10;
129
+ c[0][1] |= c[0][1] >> 4;
130
+ c[0][2] = data[1] & 8 | data[1] << 1 & 6 | data[2] >> 7;
131
+ c[0][2] |= c[0][2] << 4;
132
+ c[1][0] = data[2] << 1 & 0xf0 | data[2] >> 3 & 0xf;
133
+ c[1][1] = data[2] << 5 & 0xe0 | data[3] >> 3 & 0x10;
134
+ c[1][1] |= c[1][1] >> 4;
135
+ c[1][2] = data[3] << 1 & 0xf0 | data[3] >> 3 & 0xf;
136
+ uint_fast8_t d = data[3] & 4 | data[3] << 1 & 2;
137
+ 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]))))
138
+ ++d;
139
+ d = Etc2DistanceTable[d];
140
+ uint_fast32_t color_set[4] = {
141
+ applicate_color(c[0], d),
142
+ applicate_color(c[0], -d),
143
+ applicate_color(c[1], d),
144
+ applicate_color(c[1], -d)
145
+ };
146
+ for (int i = 0; i < 16; i++, j >>= 1, k >>= 1)
147
+ outbuf[WriteOrderTable[i]] = color_set[k << 1 & 2 | j & 1];
148
+ } else if (b + db < 0 || b + db > 255) {
149
+ // planar
150
+ c[0][0] = data[0] << 1 & 0xfc | data[0] >> 5 & 3;
151
+ c[0][1] = data[0] << 7 & 0x80 | data[1] & 0x7e | data[0] & 1;
152
+ c[0][2] = data[1] << 7 & 0x80 | data[2] << 2 & 0x60 | data[2] << 3 & 0x18 | data[3] >> 5 & 4;
153
+ c[0][2] |= c[0][2] >> 6;
154
+ c[1][0] = data[3] << 1 & 0xf8 | data[3] << 2 & 4 | data[3] >> 5 & 3;
155
+ c[1][1] = data[4] & 0xfe | data[4] >> 7;
156
+ c[1][2] = data[4] << 7 & 0x80 | data[5] >> 1 & 0x7c;
157
+ c[1][2] |= c[1][2] >> 6;
158
+ c[2][0] = data[5] << 5 & 0xe0 | data[6] >> 3 & 0x1c | data[5] >> 1 & 3;
159
+ c[2][1] = data[6] << 3 & 0xf8 | data[7] >> 5 & 0x6 | data[6] >> 4 & 1;
160
+ c[2][2] = data[7] << 2 | data[7] >> 4 & 3;
161
+ for (int x = 3, i = 0; x >= 0; x--) {
162
+ for (int y = 3; y >= 0; y--, i++) {
163
+ uint8_t r = clamp((x * (c[1][0] - c[0][0]) + y * (c[2][0] - c[0][0]) + 4 * c[0][0] + 2) >> 2);
164
+ uint8_t g = clamp((x * (c[1][1] - c[0][1]) + y * (c[2][1] - c[0][1]) + 4 * c[0][1] + 2) >> 2);
165
+ uint8_t b = clamp((x * (c[1][2] - c[0][2]) + y * (c[2][2] - c[0][2]) + 4 * c[0][2] + 2) >> 2);
166
+ outbuf[i] = color(r, g, b, 255);
167
+ }
168
+ }
169
+ } else {
170
+ // differential
171
+ uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
172
+ uint_fast8_t *table = Etc1SubblockTable[data[3] & 1];
173
+ c[0][0] = r | r >> 5;
174
+ c[0][1] = g | g >> 5;
175
+ c[0][2] = b | b >> 5;
176
+ c[1][0] = r + dr;
177
+ c[1][1] = g + dg;
178
+ c[1][2] = b + db;
179
+ c[1][0] |= c[1][0] >> 5;
180
+ c[1][1] |= c[1][1] >> 5;
181
+ c[1][2] |= c[1][2] >> 5;
182
+ for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
183
+ uint_fast8_t s = table[i];
184
+ uint_fast8_t m = Etc1ModifierTable[code[s]][j & 1];
185
+ outbuf[WriteOrderTable[i]] = applicate_color(c[s], k & 1 ? -m : m);
186
+ }
187
+ }
188
+ } else {
189
+ // individual
190
+ uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
191
+ uint_fast8_t *table = Etc1SubblockTable[data[3] & 1];
192
+ c[0][0] = data[0] & 0xf0 | data[0] >> 4;
193
+ c[1][0] = data[0] & 0x0f | data[0] << 4;
194
+ c[0][1] = data[1] & 0xf0 | data[1] >> 4;
195
+ c[1][1] = data[1] & 0x0f | data[1] << 4;
196
+ c[0][2] = data[2] & 0xf0 | data[2] >> 4;
197
+ c[1][2] = data[2] & 0x0f | data[2] << 4;
198
+ for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
199
+ uint_fast8_t s = table[i];
200
+ uint_fast8_t m = Etc1ModifierTable[code[s]][j & 1];
201
+ outbuf[WriteOrderTable[i]] = applicate_color(c[s], k & 1 ? -m : m);
202
+ }
203
+ }
204
+ }
205
+
206
+ static inline void decode_etc2a8_block(const uint8_t *data, uint32_t *outbuf) {
207
+ if (data[1] & 0xf0) {
208
+ uint_fast8_t mult = data[1] >> 4;
209
+ int_fast8_t *table = Etc2AlphaModTable[data[1] & 0xf];
210
+ uint_fast64_t l =
211
+ data[7] | (uint_fast16_t)data[6] << 8 |
212
+ (uint_fast32_t)data[5] << 16 | (uint_fast32_t)data[4] << 24 |
213
+ (uint_fast64_t)data[3] << 32 | (uint_fast64_t)data[2] << 40;
214
+ for (int i = 0; i < 16; i++, l >>= 3)
215
+ ((uint8_t*)(outbuf + WriteOrderTableRev[i]))[3] = clamp(data[0] + mult * table[l & 7]);
216
+ } else {
217
+ for (int i = 0; i < 16; i++)
218
+ ((uint8_t*)(outbuf + i))[3] = data[0];
219
+ }
220
+ }
221
+
222
+ void decode_etc2(const void *data, const int w, const int h, uint32_t *image) {
223
+ int bcw = (w + 3) / 4;
224
+ int bch = (h + 3) / 4;
225
+ int clen_last = (w + 3) % 4 + 1;
226
+ uint32_t buf[16];
227
+ const uint8_t *d = (uint8_t*)data;
228
+ for (int t = 0; t < bch; t++) {
229
+ for (int s = 0; s < bcw; s++, d += 8) {
230
+ decode_etc2_block(d, buf);
231
+ int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
232
+ for (int i = 0, y = h - t * 4 - 1; i < 4 && y >= 0; i++, y--)
233
+ memcpy(image + y * w + s * 4, buf + i * 4, clen);
234
+ }
235
+ }
236
+ }
237
+
238
+ void decode_etc2a1(const void *data, const int w, const int h, uint32_t *image) {
239
+ int bcw = (w + 3) / 4;
240
+ int bch = (h + 3) / 4;
241
+ int clen_last = (w + 3) % 4 + 1;
242
+ uint32_t buf[16];
243
+ const uint8_t *d = (uint8_t*)data;
244
+ for (int t = 0; t < bch; t++) {
245
+ for (int s = 0; s < bcw; s++, d += 9) {
246
+ decode_etc2_block(d + 1, buf);
247
+ for (int i = 0; i < 16; i++)
248
+ ((uint8_t*)(buf + i))[3] = d[0];
249
+ int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
250
+ for (int i = 0, y = h - t * 4 - 1; i < 4 && y >= 0; i++, y--)
251
+ memcpy(image + y * w + s * 4, buf + i * 4, clen);
252
+ }
253
+ }
254
+ }
255
+
256
+ void decode_etc2a8(const void *data, const int w, const int h, uint32_t *image) {
257
+ int bcw = (w + 3) / 4;
258
+ int bch = (h + 3) / 4;
259
+ int clen_last = (w + 3) % 4 + 1;
260
+ uint32_t buf[16];
261
+ const uint8_t *d = (uint8_t*)data;
262
+ for (int t = 0; t < bch; t++) {
263
+ for (int s = 0; s < bcw; s++, d += 16) {
264
+ decode_etc2_block(d + 8, buf);
265
+ decode_etc2a8_block(d, buf);
266
+ int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
267
+ for (int i = 0, y = h - t * 4 - 1; i < 4 && y >= 0; i++, y--)
268
+ memcpy(image + y * w + s * 4, buf + i * 4, clen);
269
+ }
270
+ }
271
+ }
@@ -0,0 +1,11 @@
1
+ #ifndef ETC_H
2
+ #define ETC_H
3
+
4
+ #include <stdint.h>
5
+
6
+ void decode_etc1(const void*, const int, const int, uint32_t*);
7
+ void decode_etc2(const void*, const int, const int, uint32_t*);
8
+ void decode_etc2a1(const void*, const int, const int, uint32_t*);
9
+ void decode_etc2a8(const void*, const int, const int, uint32_t*);
10
+
11
+ #endif /* end of include guard: ETC_H */
@@ -0,0 +1,8 @@
1
+ require 'mkmf'
2
+
3
+ append_cppflags('-std=c11')
4
+ append_cppflags('-O3')
5
+ append_cppflags('-Wall')
6
+ append_cppflags('-Wextra')
7
+ append_cppflags('-Wvla')
8
+ create_makefile('mikunyan/decoders/native')
@@ -0,0 +1,167 @@
1
+ #include <stdlib.h>
2
+ #include <stdint.h>
3
+ #include <ruby.h>
4
+ #include "rgb.h"
5
+ #include "etc.h"
6
+ #include "astc.h"
7
+ #include "dxtc.h"
8
+
9
+ /*
10
+ * Decode image from RGB565 binary
11
+ *
12
+ * @param [String] rb_data binary to decode
13
+ * @param [Integer] size width * height
14
+ * @param [Boolean] big whether input data are big endian
15
+ * @return [String] decoded rgba binary
16
+ */
17
+ static VALUE rb_decode_rgb565(VALUE self, VALUE rb_data, VALUE size, VALUE big) {
18
+ if (RSTRING_LEN(rb_data) < FIX2LONG(size) * 2)
19
+ rb_raise(rb_eStandardError, "Data size is not enough.");
20
+ uint8_t *image = (uint8_t*)malloc(FIX2LONG(size) * 4);
21
+ decode_rgb565((uint16_t*)RSTRING_PTR(rb_data), FIX2INT(size), RTEST(big), image);
22
+ VALUE ret = rb_str_new((char*)image, FIX2LONG(size) * 4);
23
+ free(image);
24
+ return ret;
25
+ }
26
+
27
+ /*
28
+ * Decode image from ETC1 compressed binary
29
+ *
30
+ * @param [String] rb_data binary to decode
31
+ * @param [Integer] w image width
32
+ * @param [Integer] h image height
33
+ * @return [String] decoded rgba binary
34
+ */
35
+ static VALUE rb_decode_etc1(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
36
+ if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 8)
37
+ rb_raise(rb_eStandardError, "Data size is not enough.");
38
+ uint32_t *image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
39
+ decode_etc1((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
40
+ VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
41
+ free(image);
42
+ return ret;
43
+ }
44
+
45
+ /*
46
+ * Decode image from ETC2 compressed binary
47
+ *
48
+ * @param [String] rb_data binary to decode
49
+ * @param [Integer] w image width
50
+ * @param [Integer] h image height
51
+ * @return [String] decoded rgba binary
52
+ */
53
+ static VALUE rb_decode_etc2(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
54
+ if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 8)
55
+ rb_raise(rb_eStandardError, "Data size is not enough.");
56
+ uint32_t *image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
57
+ decode_etc2((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
58
+ VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
59
+ free(image);
60
+ return ret;
61
+ }
62
+
63
+ /*
64
+ * Decode image from ETC2 Alpha1 compressed binary
65
+ *
66
+ * @param [String] rb_data binary to decode
67
+ * @param [Integer] w image width
68
+ * @param [Integer] h image height
69
+ * @return [String] decoded rgba binary
70
+ */
71
+ static VALUE rb_decode_etc2a1(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
72
+ if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 9)
73
+ rb_raise(rb_eStandardError, "Data size is not enough.");
74
+ uint32_t *image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
75
+ decode_etc2a8((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
76
+ VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
77
+ free(image);
78
+ return ret;
79
+ }
80
+
81
+ /*
82
+ * Decode image from ETC2 Alpha8 compressed binary
83
+ *
84
+ * @param [String] rb_data binary to decode
85
+ * @param [Integer] w image width
86
+ * @param [Integer] h image height
87
+ * @return [String] decoded rgba binary
88
+ */
89
+ static VALUE rb_decode_etc2a8(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
90
+ if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 16)
91
+ rb_raise(rb_eStandardError, "Data size is not enough.");
92
+ uint32_t *image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
93
+ decode_etc2a8((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
94
+ VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
95
+ free(image);
96
+ return ret;
97
+ }
98
+
99
+ /*
100
+ * Decode image from ASTC compressed binary
101
+ *
102
+ * @param [String] rb_data binary to decode
103
+ * @param [Integer] w image width
104
+ * @param [Integer] h image height
105
+ * @param [Integer] bw block width
106
+ * @param [Integer] bh block height
107
+ * @return [String] decoded rgba binary
108
+ */
109
+ static VALUE rb_decode_astc(VALUE self, VALUE rb_data, VALUE w, VALUE h, VALUE bw, VALUE bh) {
110
+ if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + FIX2LONG(bw) - 1) / FIX2LONG(bw)) * ((FIX2LONG(h) + FIX2LONG(bh) - 1) / FIX2LONG(bh)) * 16)
111
+ rb_raise(rb_eStandardError, "Data size is not enough.");
112
+ const uint8_t *data = (uint8_t*)RSTRING_PTR(rb_data);
113
+ uint32_t *image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
114
+ decode_astc(data, FIX2INT(w), FIX2INT(h), FIX2INT(bw), FIX2INT(bh), image);
115
+ VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
116
+ free(image);
117
+ return ret;
118
+ }
119
+
120
+ /*
121
+ * Decode image from DXT1 compressed binary
122
+ *
123
+ * @param [String] rb_data binary to decode
124
+ * @param [Integer] w image width
125
+ * @param [Integer] h image height
126
+ * @return [String] decoded rgba binary
127
+ */
128
+ static VALUE rb_decode_dxt1(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
129
+ if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 8)
130
+ rb_raise(rb_eStandardError, "Data size is not enough.");
131
+ uint32_t *image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
132
+ decode_dxt1((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
133
+ VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
134
+ free(image);
135
+ return ret;
136
+ }
137
+
138
+ /*
139
+ * Decode image from DXT5 compressed binary
140
+ *
141
+ * @param [String] rb_data binary to decode
142
+ * @param [Integer] w image width
143
+ * @param [Integer] h image height
144
+ * @return [String] decoded rgba binary
145
+ */
146
+ static VALUE rb_decode_dxt5(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
147
+ if (RSTRING_LEN(rb_data) < ((FIX2LONG(w) + 3) / 4) * ((FIX2LONG(h) + 3) / 4) * 16)
148
+ rb_raise(rb_eStandardError, "Data size is not enough.");
149
+ uint32_t *image = (uint32_t*)calloc(FIX2LONG(w) * FIX2LONG(h), sizeof(uint32_t));
150
+ decode_dxt5((uint64_t*)RSTRING_PTR(rb_data), FIX2INT(w), FIX2INT(h), image);
151
+ VALUE ret = rb_str_new((char*)image, FIX2LONG(w) * FIX2LONG(h) * sizeof(uint32_t));
152
+ free(image);
153
+ return ret;
154
+ }
155
+
156
+ void Init_native() {
157
+ VALUE mMikunyan = rb_define_module("Mikunyan");
158
+ VALUE mDecodeHelper = rb_define_module_under(mMikunyan, "DecodeHelper");
159
+ rb_define_module_function(mDecodeHelper, "decode_rgb565", rb_decode_rgb565, 3);
160
+ rb_define_module_function(mDecodeHelper, "decode_etc1", rb_decode_etc1, 3);
161
+ rb_define_module_function(mDecodeHelper, "decode_etc2", rb_decode_etc2, 3);
162
+ rb_define_module_function(mDecodeHelper, "decode_etc2a1", rb_decode_etc2a1, 3);
163
+ rb_define_module_function(mDecodeHelper, "decode_etc2a8", rb_decode_etc2a8, 3);
164
+ rb_define_module_function(mDecodeHelper, "decode_astc", rb_decode_astc, 5);
165
+ rb_define_module_function(mDecodeHelper, "decode_dxt1", rb_decode_dxt1, 3);
166
+ rb_define_module_function(mDecodeHelper, "decode_dxt5", rb_decode_dxt5, 3);
167
+ }