add ASTC/HDR support and improve ImageDecoder
This commit is contained in:
+548
-102
@@ -1,59 +1,69 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ruby.h>
|
|
||||||
#include "astc.h"
|
#include "astc.h"
|
||||||
|
#include "fp16.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <ruby.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static const int BitReverseTable[] = {
|
static const int BitReverseTable[] = {
|
||||||
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
|
||||||
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
|
0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
|
||||||
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4,
|
||||||
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
|
0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
||||||
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
|
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
|
||||||
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
|
||||||
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
|
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA,
|
||||||
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
|
0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
||||||
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
|
||||||
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
|
0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
|
||||||
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
|
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1,
|
||||||
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
||||||
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
|
||||||
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
|
0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
|
||||||
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD,
|
||||||
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
||||||
|
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
|
||||||
|
0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
|
||||||
|
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7,
|
||||||
|
0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
||||||
|
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
|
||||||
|
0x3F, 0xBF, 0x7F, 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
static int WeightPrecTableA[] = {0, 0, 0, 3, 0, 5, 3, 0, 0, 0, 5, 3, 0, 5, 3, 0};
|
static const int WeightPrecTableA[] = { 0, 0, 0, 3, 0, 5, 3, 0, 0, 0, 5, 3, 0, 5, 3, 0 };
|
||||||
static int WeightPrecTableB[] = {0, 0, 1, 0, 2, 0, 1, 3, 0, 0, 1, 2, 4, 2, 3, 5};
|
static const int WeightPrecTableB[] = { 0, 0, 1, 0, 2, 0, 1, 3, 0, 0, 1, 2, 4, 2, 3, 5 };
|
||||||
|
|
||||||
static int CemTableA[] = {0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 0, 0};
|
static const int CemTableA[] = { 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 0, 0 };
|
||||||
static int CemTableB[] = {8, 6, 5, 7, 5, 4, 6, 4, 3, 5, 3, 2, 4, 2, 1, 3, 1, 2, 1};
|
static const int CemTableB[] = { 8, 6, 5, 7, 5, 4, 6, 4, 3, 5, 3, 2, 4, 2, 1, 3, 1, 2, 1 };
|
||||||
|
|
||||||
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 uint_fast8_t bit_reverse_u8(const uint_fast8_t c, const int bits) {
|
static inline uint_fast8_t bit_reverse_u8(const uint_fast8_t c, const int bits)
|
||||||
|
{
|
||||||
return BitReverseTable[c] >> (8 - bits);
|
return BitReverseTable[c] >> (8 - bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint_fast64_t bit_reverse_u64(const uint_fast64_t d, const int bits) {
|
static inline uint_fast64_t bit_reverse_u64(const uint_fast64_t d, const int bits)
|
||||||
uint_fast64_t ret =
|
{
|
||||||
(uint_fast64_t)BitReverseTable[d & 0xff] << 56 |
|
uint_fast64_t ret = (uint_fast64_t)BitReverseTable[d & 0xff] << 56 | (uint_fast64_t)BitReverseTable[d >> 8 & 0xff] << 48 | (uint_fast64_t)BitReverseTable[d >> 16 & 0xff] << 40 | (uint_fast64_t)BitReverseTable[d >> 24 & 0xff] << 32 | (uint_fast32_t)BitReverseTable[d >> 32 & 0xff] << 24 | (uint_fast32_t)BitReverseTable[d >> 40 & 0xff] << 16 | (uint_fast16_t)BitReverseTable[d >> 48 & 0xff] << 8 | BitReverseTable[d >> 56 & 0xff];
|
||||||
(uint_fast64_t)BitReverseTable[d >> 8 & 0xff] << 48 |
|
|
||||||
(uint_fast64_t)BitReverseTable[d >> 16 & 0xff] << 40 |
|
|
||||||
(uint_fast64_t)BitReverseTable[d >> 24 & 0xff] << 32 |
|
|
||||||
(uint_fast32_t)BitReverseTable[d >> 32 & 0xff] << 24 |
|
|
||||||
(uint_fast32_t)BitReverseTable[d >> 40 & 0xff] << 16 |
|
|
||||||
(uint_fast16_t)BitReverseTable[d >> 48 & 0xff] << 8 | BitReverseTable[d >> 56 & 0xff];
|
|
||||||
return ret >> (64 - bits);
|
return ret >> (64 - bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int getbits(const uint8_t *buf, const int bit, const int len) {
|
static inline int getbits(const uint8_t* buf, const int bit, const int len)
|
||||||
|
{
|
||||||
return (*(int*)(buf + bit / 8) >> (bit % 8)) & ((1 << len) - 1);
|
return (*(int*)(buf + bit / 8) >> (bit % 8)) & ((1 << len) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint_fast64_t getbits64(const uint8_t *buf, const int bit, const int len) {
|
static inline uint_fast64_t getbits64(const uint8_t* buf, const int bit, const int len)
|
||||||
|
{
|
||||||
uint_fast64_t mask = len == 64 ? 0xffffffffffffffff : (1ull << len) - 1;
|
uint_fast64_t mask = len == 64 ? 0xffffffffffffffff : (1ull << len) - 1;
|
||||||
if (len < 1)
|
if (len < 1)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -67,18 +77,30 @@ static inline uint_fast64_t getbits64(const uint8_t *buf, const int bit, const i
|
|||||||
return ((*(uint_fast64_t*)buf) >> bit | *(uint_fast64_t*)(buf + 8) << (64 - bit)) & mask;
|
return ((*(uint_fast64_t*)buf) >> bit | *(uint_fast64_t*)(buf + 8) << (64 - bit)) & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint_fast8_t clamp(const int n) {
|
static inline uint16_t u8ptr_to_u16(const uint8_t* ptr)
|
||||||
|
{
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
return *(uint16_t*)ptr;
|
||||||
|
#else
|
||||||
|
return ptr[0] | ptr[1] << 8;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint_fast8_t clamp(const int n)
|
||||||
|
{
|
||||||
return n < 0 ? 0 : n > 255 ? 255 : n;
|
return n < 0 ? 0 : n > 255 ? 255 : n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void bit_transfer_signed(int *a, int *b) {
|
static inline void bit_transfer_signed(int* a, int* b)
|
||||||
|
{
|
||||||
*b = (*b >> 1) | (*a & 0x80);
|
*b = (*b >> 1) | (*a & 0x80);
|
||||||
*a = (*a >> 1) & 0x3f;
|
*a = (*a >> 1) & 0x3f;
|
||||||
if (*a & 0x20)
|
if (*a & 0x20)
|
||||||
*a -= 0x40;
|
*a -= 0x40;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_endpoint(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2) {
|
static inline void set_endpoint(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2)
|
||||||
|
{
|
||||||
endpoint[0] = r1;
|
endpoint[0] = r1;
|
||||||
endpoint[1] = g1;
|
endpoint[1] = g1;
|
||||||
endpoint[2] = b1;
|
endpoint[2] = b1;
|
||||||
@@ -89,7 +111,8 @@ static inline void set_endpoint(int endpoint[8], int r1, int g1, int b1, int a1,
|
|||||||
endpoint[7] = a2;
|
endpoint[7] = a2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_endpoint_clamp(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2) {
|
static inline void set_endpoint_clamp(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2)
|
||||||
|
{
|
||||||
endpoint[0] = clamp(r1);
|
endpoint[0] = clamp(r1);
|
||||||
endpoint[1] = clamp(g1);
|
endpoint[1] = clamp(g1);
|
||||||
endpoint[2] = clamp(b1);
|
endpoint[2] = clamp(b1);
|
||||||
@@ -100,7 +123,8 @@ static inline void set_endpoint_clamp(int endpoint[8], int r1, int g1, int b1, i
|
|||||||
endpoint[7] = clamp(a2);
|
endpoint[7] = clamp(a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_endpoint_blue(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2) {
|
static inline void set_endpoint_blue(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2)
|
||||||
|
{
|
||||||
endpoint[0] = (r1 + b1) >> 1;
|
endpoint[0] = (r1 + b1) >> 1;
|
||||||
endpoint[1] = (g1 + b1) >> 1;
|
endpoint[1] = (g1 + b1) >> 1;
|
||||||
endpoint[2] = b1;
|
endpoint[2] = b1;
|
||||||
@@ -111,7 +135,8 @@ static inline void set_endpoint_blue(int endpoint[8], int r1, int g1, int b1, in
|
|||||||
endpoint[7] = a2;
|
endpoint[7] = a2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_endpoint_blue_clamp(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2) {
|
static inline void set_endpoint_blue_clamp(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2)
|
||||||
|
{
|
||||||
endpoint[0] = clamp((r1 + b1) >> 1);
|
endpoint[0] = clamp((r1 + b1) >> 1);
|
||||||
endpoint[1] = clamp((g1 + b1) >> 1);
|
endpoint[1] = clamp((g1 + b1) >> 1);
|
||||||
endpoint[2] = clamp(b1);
|
endpoint[2] = clamp(b1);
|
||||||
@@ -122,10 +147,79 @@ static inline void set_endpoint_blue_clamp(int endpoint[8], int r1, int g1, int
|
|||||||
endpoint[7] = clamp(a2);
|
endpoint[7] = clamp(a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint_fast8_t select_color(int v0, int v1, int weight) {
|
static inline uint_fast16_t clamp_hdr(const int n)
|
||||||
|
{
|
||||||
|
return n < 0 ? 0 : n > 0xfff ? 0xfff : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_endpoint_hdr(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2)
|
||||||
|
{
|
||||||
|
endpoint[0] = r1;
|
||||||
|
endpoint[1] = g1;
|
||||||
|
endpoint[2] = b1;
|
||||||
|
endpoint[3] = a1;
|
||||||
|
endpoint[4] = r2;
|
||||||
|
endpoint[5] = g2;
|
||||||
|
endpoint[6] = b2;
|
||||||
|
endpoint[7] = a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_endpoint_hdr_clamp(int endpoint[8], int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2)
|
||||||
|
{
|
||||||
|
endpoint[0] = clamp_hdr(r1);
|
||||||
|
endpoint[1] = clamp_hdr(g1);
|
||||||
|
endpoint[2] = clamp_hdr(b1);
|
||||||
|
endpoint[3] = clamp_hdr(a1);
|
||||||
|
endpoint[4] = clamp_hdr(r2);
|
||||||
|
endpoint[5] = clamp_hdr(g2);
|
||||||
|
endpoint[6] = clamp_hdr(b2);
|
||||||
|
endpoint[7] = clamp_hdr(a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef uint_fast8_t (*t_select_folor_func_ptr)(int, int, int);
|
||||||
|
|
||||||
|
static uint_fast8_t select_color(int v0, int v1, int weight)
|
||||||
|
{
|
||||||
return ((((v0 << 8 | v0) * (64 - weight) + (v1 << 8 | v1) * weight + 32) >> 6) * 255 + 32768) / 65536;
|
return ((((v0 << 8 | v0) * (64 - weight) + (v1 << 8 | v1) * weight + 32) >> 6) * 255 + 32768) / 65536;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint_fast8_t select_color_hdr(int v0, int v1, int weight)
|
||||||
|
{
|
||||||
|
uint16_t c = ((v0 << 4) * (64 - weight) + (v1 << 4) * weight + 32) >> 6;
|
||||||
|
uint16_t m = c & 0x7ff;
|
||||||
|
if (m < 512)
|
||||||
|
m *= 3;
|
||||||
|
else if (m < 1536)
|
||||||
|
m = 4 * m - 512;
|
||||||
|
else
|
||||||
|
m = 5 * m - 2048;
|
||||||
|
float f = fp16_ieee_to_fp32_value((c >> 1 & 0x7c00) | m >> 3);
|
||||||
|
return isfinite(f) ? clamp(roundf(f * 255)) : 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t f32_to_u8(const float f)
|
||||||
|
{
|
||||||
|
float c = roundf(f * 255);
|
||||||
|
if (c < 0)
|
||||||
|
return 0;
|
||||||
|
else if (c > 255)
|
||||||
|
return 255;
|
||||||
|
else
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t f16ptr_to_u8(const uint8_t* ptr)
|
||||||
|
{
|
||||||
|
const uint16_t c =
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
*(uint16_t*)ptr
|
||||||
|
#else
|
||||||
|
ptr[0] | ptr[1] << 8
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
return f32_to_u8(fp16_ieee_to_fp32_value(c));
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int bw;
|
int bw;
|
||||||
int bh;
|
int bh;
|
||||||
@@ -149,20 +243,86 @@ typedef struct {
|
|||||||
int nonbits;
|
int nonbits;
|
||||||
} IntSeqData;
|
} IntSeqData;
|
||||||
|
|
||||||
void decode_intseq(const uint8_t *buf, int offset, const int a, const int b, const int count, const int reverse, IntSeqData *out) {
|
void decode_intseq(const uint8_t* buf, int offset, const int a, const int b, const int count, const int reverse, IntSeqData* out)
|
||||||
|
{
|
||||||
static int mt[] = { 0, 2, 4, 5, 7 };
|
static int mt[] = { 0, 2, 4, 5, 7 };
|
||||||
static int mq[] = { 0, 3, 5 };
|
static int mq[] = { 0, 3, 5 };
|
||||||
static int TritsTable[5][256] = {
|
static int TritsTable[5][256] = {
|
||||||
{0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 1, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 1, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2},
|
{ 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1,
|
||||||
{0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1},
|
0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2,
|
||||||
{0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2},
|
0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 1, 0, 1, 2, 0, 0, 1, 2, 1,
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2},
|
0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2,
|
||||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
|
0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1,
|
||||||
|
0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2,
|
||||||
|
0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 1,
|
||||||
|
0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 1,
|
||||||
|
0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1,
|
||||||
|
0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2,
|
||||||
|
0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 2, 2, 0, 1, 2, 2 },
|
||||||
|
{ 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1,
|
||||||
|
2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0,
|
||||||
|
0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0,
|
||||||
|
2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 0,
|
||||||
|
0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1,
|
||||||
|
2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0,
|
||||||
|
0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0,
|
||||||
|
2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||||
|
0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1,
|
||||||
|
2, 2, 2, 1, 2, 2, 2, 1, 0, 0, 0, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2, 0,
|
||||||
|
0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1 },
|
||||||
|
{ 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2,
|
||||||
|
1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2,
|
||||||
|
1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2,
|
||||||
|
0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2,
|
||||||
|
0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2,
|
||||||
|
1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2,
|
||||||
|
1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2,
|
||||||
|
0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2,
|
||||||
|
0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 2,
|
||||||
|
1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2,
|
||||||
|
1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2 },
|
||||||
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 },
|
||||||
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
|
||||||
};
|
};
|
||||||
static int QuintsTable[3][128] = {
|
static int QuintsTable[3][128] = {
|
||||||
{0, 1, 2, 3, 4, 0, 4, 4, 0, 1, 2, 3, 4, 1, 4, 4, 0, 1, 2, 3, 4, 2, 4, 4, 0, 1, 2, 3, 4, 3, 4, 4, 0, 1, 2, 3, 4, 0, 4, 0, 0, 1, 2, 3, 4, 1, 4, 1, 0, 1, 2, 3, 4, 2, 4, 2, 0, 1, 2, 3, 4, 3, 4, 3, 0, 1, 2, 3, 4, 0, 2, 3, 0, 1, 2, 3, 4, 1, 2, 3, 0, 1, 2, 3, 4, 2, 2, 3, 0, 1, 2, 3, 4, 3, 2, 3, 0, 1, 2, 3, 4, 0, 0, 1, 0, 1, 2, 3, 4, 1, 0, 1, 0, 1, 2, 3, 4, 2, 0, 1, 0, 1, 2, 3, 4, 3, 0, 1},
|
{ 0, 1, 2, 3, 4, 0, 4, 4, 0, 1, 2, 3, 4, 1, 4, 4, 0, 1, 2, 3, 4, 2,
|
||||||
{0, 0, 0, 0, 0, 4, 4, 4, 1, 1, 1, 1, 1, 4, 4, 4, 2, 2, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 4, 0, 4, 1, 1, 1, 1, 1, 4, 1, 4, 2, 2, 2, 2, 2, 4, 2, 4, 3, 3, 3, 3, 3, 4, 3, 4, 0, 0, 0, 0, 0, 4, 0, 0, 1, 1, 1, 1, 1, 4, 1, 1, 2, 2, 2, 2, 2, 4, 2, 2, 3, 3, 3, 3, 3, 4, 3, 3, 0, 0, 0, 0, 0, 4, 0, 0, 1, 1, 1, 1, 1, 4, 1, 1, 2, 2, 2, 2, 2, 4, 2, 2, 3, 3, 3, 3, 3, 4, 3, 3},
|
4, 4, 0, 1, 2, 3, 4, 3, 4, 4, 0, 1, 2, 3, 4, 0, 4, 0, 0, 1, 2, 3,
|
||||||
{0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 3, 4, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4}
|
4, 1, 4, 1, 0, 1, 2, 3, 4, 2, 4, 2, 0, 1, 2, 3, 4, 3, 4, 3, 0, 1,
|
||||||
|
2, 3, 4, 0, 2, 3, 0, 1, 2, 3, 4, 1, 2, 3, 0, 1, 2, 3, 4, 2, 2, 3,
|
||||||
|
0, 1, 2, 3, 4, 3, 2, 3, 0, 1, 2, 3, 4, 0, 0, 1, 0, 1, 2, 3, 4, 1,
|
||||||
|
0, 1, 0, 1, 2, 3, 4, 2, 0, 1, 0, 1, 2, 3, 4, 3, 0, 1 },
|
||||||
|
{ 0, 0, 0, 0, 0, 4, 4, 4, 1, 1, 1, 1, 1, 4, 4, 4, 2, 2, 2, 2, 2, 4,
|
||||||
|
4, 4, 3, 3, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 4, 0, 4, 1, 1, 1, 1,
|
||||||
|
1, 4, 1, 4, 2, 2, 2, 2, 2, 4, 2, 4, 3, 3, 3, 3, 3, 4, 3, 4, 0, 0,
|
||||||
|
0, 0, 0, 4, 0, 0, 1, 1, 1, 1, 1, 4, 1, 1, 2, 2, 2, 2, 2, 4, 2, 2,
|
||||||
|
3, 3, 3, 3, 3, 4, 3, 3, 0, 0, 0, 0, 0, 4, 0, 0, 1, 1, 1, 1, 1, 4,
|
||||||
|
1, 1, 2, 2, 2, 2, 2, 4, 2, 2, 3, 3, 3, 3, 3, 4, 3, 3 },
|
||||||
|
{ 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0,
|
||||||
|
2, 4, 0, 0, 0, 0, 0, 0, 3, 4, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1,
|
||||||
|
1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 2, 2,
|
||||||
|
2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4,
|
||||||
|
2, 2, 2, 2, 2, 2, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3,
|
||||||
|
4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4 }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
@@ -187,7 +347,8 @@ void decode_intseq(const uint8_t *buf, int offset, const int a, const int b, con
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0, p = offset; i < block_count; i++, p += block_size) {
|
for (int i = 0, p = offset; i < block_count; i++, p += block_size) {
|
||||||
uint_fast64_t d = getbits64(buf, p, (i < block_count - 1) ? block_size : last_block_size);
|
uint_fast64_t d = getbits64(
|
||||||
|
buf, p, (i < block_count - 1) ? block_size : last_block_size);
|
||||||
int x = (d >> b & 3) | (d >> b * 2 & 0xc) | (d >> b * 3 & 0x10) | (d >> b * 4 & 0x60) | (d >> b * 5 & 0x80);
|
int x = (d >> b & 3) | (d >> b * 2 & 0xc) | (d >> b * 3 & 0x10) | (d >> b * 4 & 0x60) | (d >> b * 5 & 0x80);
|
||||||
for (int j = 0; j < 5 && n < count; j++, n++)
|
for (int j = 0; j < 5 && n < count; j++, n++)
|
||||||
out[n] = (IntSeqData){ d >> (mt[j] + b * j) & mask, TritsTable[j][x] };
|
out[n] = (IntSeqData){ d >> (mt[j] + b * j) & mask, TritsTable[j][x] };
|
||||||
@@ -210,7 +371,8 @@ void decode_intseq(const uint8_t *buf, int offset, const int a, const int b, con
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0, p = offset; i < block_count; i++, p += block_size) {
|
for (int i = 0, p = offset; i < block_count; i++, p += block_size) {
|
||||||
uint_fast64_t d = getbits64(buf, p, (i < block_count - 1) ? block_size : last_block_size);
|
uint_fast64_t d = getbits64(
|
||||||
|
buf, p, (i < block_count - 1) ? block_size : last_block_size);
|
||||||
int x = (d >> b & 7) | (d >> b * 2 & 0x18) | (d >> b * 3 & 0x60);
|
int x = (d >> b & 7) | (d >> b * 2 & 0x18) | (d >> b * 3 & 0x60);
|
||||||
for (int j = 0; j < 3 && n < count; j++, n++)
|
for (int j = 0; j < 3 && n < count; j++, n++)
|
||||||
out[n] = (IntSeqData){ d >> (mq[j] + b * j) & mask, QuintsTable[j][x] };
|
out[n] = (IntSeqData){ d >> (mq[j] + b * j) & mask, QuintsTable[j][x] };
|
||||||
@@ -226,24 +388,26 @@ void decode_intseq(const uint8_t *buf, int offset, const int a, const int b, con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_block_params(const uint8_t *buf, BlockData *block_data) {
|
void decode_block_params(const uint8_t* buf, BlockData* block_data)
|
||||||
block_data->dual_plane = (buf[1] & 4) >> 2;
|
{
|
||||||
|
block_data->dual_plane = !!(buf[1] & 4);
|
||||||
block_data->weight_range = (buf[0] >> 4 & 1) | (buf[1] << 2 & 8);
|
block_data->weight_range = (buf[0] >> 4 & 1) | (buf[1] << 2 & 8);
|
||||||
|
|
||||||
if (buf[0] & 3) {
|
if (buf[0] & 3) {
|
||||||
|
// ← W | H H | ρ0 | ? | ? | ρ2 | ρ1
|
||||||
block_data->weight_range |= buf[0] << 1 & 6;
|
block_data->weight_range |= buf[0] << 1 & 6;
|
||||||
switch (buf[0] & 0xc) {
|
switch (buf[0] & 0xc) {
|
||||||
case 0:
|
case 0:
|
||||||
block_data->width = (*(int*)buf >> 7 & 3) + 4;
|
block_data->width = (u8ptr_to_u16(buf) >> 7 & 3) + 4;
|
||||||
block_data->height = (buf[0] >> 5 & 3) + 2;
|
block_data->height = (buf[0] >> 5 & 3) + 2;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
block_data->width = (*(int*)buf >> 7 & 3) + 8;
|
block_data->width = (u8ptr_to_u16(buf) >> 7 & 3) + 8;
|
||||||
block_data->height = (buf[0] >> 5 & 3) + 2;
|
block_data->height = (buf[0] >> 5 & 3) + 2;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
block_data->width = (buf[0] >> 5 & 3) + 2;
|
block_data->width = (buf[0] >> 5 & 3) + 2;
|
||||||
block_data->height = (*(int*)buf >> 7 & 3) + 8;
|
block_data->height = (u8ptr_to_u16(buf) >> 7 & 3) + 8;
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
if (buf[1] & 1) {
|
if (buf[1] & 1) {
|
||||||
@@ -256,8 +420,9 @@ void decode_block_params(const uint8_t *buf, BlockData *block_data) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// ← W | H H | ρ0 | ρ2 | ρ1 | 0 | 0
|
||||||
block_data->weight_range |= buf[0] >> 1 & 6;
|
block_data->weight_range |= buf[0] >> 1 & 6;
|
||||||
switch ((*(int*)buf) & 0x180) {
|
switch (u8ptr_to_u16(buf) & 0x180) {
|
||||||
case 0:
|
case 0:
|
||||||
block_data->width = 12;
|
block_data->width = 12;
|
||||||
block_data->height = (buf[0] >> 5 & 3) + 2;
|
block_data->height = (buf[0] >> 5 & 3) + 2;
|
||||||
@@ -299,10 +464,10 @@ void decode_block_params(const uint8_t *buf, BlockData *block_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (block_data->part_num == 1) {
|
if (block_data->part_num == 1) {
|
||||||
block_data->cem[0] = *(int*)(buf + 1) >> 5 & 0xf;
|
block_data->cem[0] = u8ptr_to_u16(buf + 1) >> 5 & 0xf;
|
||||||
config_bits = 17;
|
config_bits = 17;
|
||||||
} else {
|
} else {
|
||||||
cem_base = *(int*)(buf + 2) >> 7 & 3;
|
cem_base = u8ptr_to_u16(buf + 2) >> 7 & 3;
|
||||||
if (cem_base == 0) {
|
if (cem_base == 0) {
|
||||||
int cem = buf[3] >> 1 & 0xf;
|
int cem = buf[3] >> 1 & 0xf;
|
||||||
for (int i = 0; i < block_data->part_num; i++)
|
for (int i = 0; i < block_data->part_num; i++)
|
||||||
@@ -361,9 +526,217 @@ void decode_block_params(const uint8_t *buf, BlockData *block_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_endpoints(const uint8_t *buf, BlockData *data) {
|
void decode_endpoints_hdr7(int* endpoints, int* v)
|
||||||
static int TritsTable[] = { 0, 204, 93, 44, 22, 11, 5 };
|
{
|
||||||
static int QuintsTable[] = { 0, 113, 54, 26, 13, 6 };
|
int modeval = (v[2] >> 4 & 0x8) | (v[1] >> 5 & 0x4) | (v[0] >> 6);
|
||||||
|
int major_component, mode;
|
||||||
|
if ((modeval & 0xc) != 0xc) {
|
||||||
|
major_component = modeval >> 2;
|
||||||
|
mode = modeval & 3;
|
||||||
|
} else if (modeval != 0xf) {
|
||||||
|
major_component = modeval & 3;
|
||||||
|
mode = 4;
|
||||||
|
} else {
|
||||||
|
major_component = 0;
|
||||||
|
mode = 5;
|
||||||
|
}
|
||||||
|
int c[] = { v[0] & 0x3f, v[1] & 0x1f, v[2] & 0x1f, v[3] & 0x1f };
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
c[3] |= v[3] & 0x60;
|
||||||
|
c[0] |= v[3] >> 1 & 0x40;
|
||||||
|
c[0] |= v[2] << 1 & 0x80;
|
||||||
|
c[0] |= v[1] << 3 & 0x300;
|
||||||
|
c[0] |= v[2] << 5 & 0x400;
|
||||||
|
c[0] <<= 1;
|
||||||
|
c[1] <<= 1;
|
||||||
|
c[2] <<= 1;
|
||||||
|
c[3] <<= 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
c[1] |= v[1] & 0x20;
|
||||||
|
c[2] |= v[2] & 0x20;
|
||||||
|
c[0] |= v[3] >> 1 & 0x40;
|
||||||
|
c[0] |= v[2] << 1 & 0x80;
|
||||||
|
c[0] |= v[1] << 2 & 0x100;
|
||||||
|
c[0] |= v[3] << 4 & 0x600;
|
||||||
|
c[0] <<= 1;
|
||||||
|
c[1] <<= 1;
|
||||||
|
c[2] <<= 1;
|
||||||
|
c[3] <<= 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
c[3] |= v[3] & 0xe0;
|
||||||
|
c[0] |= v[2] << 1 & 0xc0;
|
||||||
|
c[0] |= v[1] << 3 & 0x300;
|
||||||
|
c[0] <<= 2;
|
||||||
|
c[1] <<= 2;
|
||||||
|
c[2] <<= 2;
|
||||||
|
c[3] <<= 2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
c[1] |= v[1] & 0x20;
|
||||||
|
c[2] |= v[2] & 0x20;
|
||||||
|
c[3] |= v[3] & 0x60;
|
||||||
|
c[0] |= v[3] >> 1 & 0x40;
|
||||||
|
c[0] |= v[2] << 1 & 0x80;
|
||||||
|
c[0] |= v[1] << 2 & 0x100;
|
||||||
|
c[0] <<= 3;
|
||||||
|
c[1] <<= 3;
|
||||||
|
c[2] <<= 3;
|
||||||
|
c[3] <<= 3;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
c[1] |= v[1] & 0x60;
|
||||||
|
c[2] |= v[2] & 0x60;
|
||||||
|
c[3] |= v[3] & 0x20;
|
||||||
|
c[0] |= v[3] >> 1 & 0x40;
|
||||||
|
c[0] |= v[3] << 1 & 0x80;
|
||||||
|
c[0] <<= 4;
|
||||||
|
c[1] <<= 4;
|
||||||
|
c[2] <<= 4;
|
||||||
|
c[3] <<= 4;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
c[1] |= v[1] & 0x60;
|
||||||
|
c[2] |= v[2] & 0x60;
|
||||||
|
c[3] |= v[3] & 0x60;
|
||||||
|
c[0] |= v[3] >> 1 & 0x40;
|
||||||
|
c[0] <<= 5;
|
||||||
|
c[1] <<= 5;
|
||||||
|
c[2] <<= 5;
|
||||||
|
c[3] <<= 5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mode != 5) {
|
||||||
|
c[1] = c[0] - c[1];
|
||||||
|
c[2] = c[0] - c[2];
|
||||||
|
}
|
||||||
|
if (major_component == 1)
|
||||||
|
set_endpoint_hdr_clamp(endpoints, c[1] - c[3], c[0] - c[3], c[2] - c[3], 0x780, c[1], c[0], c[2], 0x780);
|
||||||
|
else if (major_component == 2)
|
||||||
|
set_endpoint_hdr_clamp(endpoints, c[2] - c[3], c[1] - c[3], c[0] - c[3], 0x780, c[2], c[1], c[0], 0x780);
|
||||||
|
else
|
||||||
|
set_endpoint_hdr_clamp(endpoints, c[0] - c[3], c[1] - c[3], c[2] - c[3], 0x780, c[0], c[1], c[2], 0x780);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decode_endpoints_hdr11(int* endpoints, int* v, int alpha1, int alpha2)
|
||||||
|
{
|
||||||
|
int major_component = (v[4] >> 7) | (v[5] >> 6 & 2);
|
||||||
|
if (major_component == 3) {
|
||||||
|
set_endpoint_hdr(endpoints, v[0] << 4, v[2] << 4, v[4] << 5 & 0xfe0, alpha1, v[1] << 4, v[3] << 4, v[5] << 5 & 0xfe0, alpha2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int mode = (v[1] >> 7) | (v[2] >> 6 & 2) | (v[3] >> 5 & 4);
|
||||||
|
int va = v[0] | (v[1] << 2 & 0x100);
|
||||||
|
int vb0 = v[2] & 0x3f, vb1 = v[3] & 0x3f;
|
||||||
|
int vc = v[1] & 0x3f;
|
||||||
|
int16_t vd0, vd1;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
vd0 = v[4] & 0x7f;
|
||||||
|
if (vd0 & 0x40)
|
||||||
|
vd0 |= 0xff80;
|
||||||
|
vd1 = v[5] & 0x7f;
|
||||||
|
if (vd1 & 0x40)
|
||||||
|
vd1 |= 0xff80;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
case 5:
|
||||||
|
case 7:
|
||||||
|
vd0 = v[4] & 0x3f;
|
||||||
|
if (vd0 & 0x20)
|
||||||
|
vd0 |= 0xffc0;
|
||||||
|
vd1 = v[5] & 0x3f;
|
||||||
|
if (vd1 & 0x20)
|
||||||
|
vd1 |= 0xffc0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vd0 = v[4] & 0x1f;
|
||||||
|
if (vd0 & 0x10)
|
||||||
|
vd0 |= 0xffe0;
|
||||||
|
vd1 = v[5] & 0x1f;
|
||||||
|
if (vd1 & 0x10)
|
||||||
|
vd1 |= 0xffe0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
vb0 |= v[2] & 0x40;
|
||||||
|
vb1 |= v[3] & 0x40;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
vb0 |= v[2] & 0x40;
|
||||||
|
vb1 |= v[3] & 0x40;
|
||||||
|
vb0 |= v[4] << 1 & 0x80;
|
||||||
|
vb1 |= v[5] << 1 & 0x80;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
va |= v[2] << 3 & 0x200;
|
||||||
|
vc |= v[3] & 0x40;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
va |= v[4] << 3 & 0x200;
|
||||||
|
vc |= v[5] & 0x40;
|
||||||
|
vb0 |= v[2] & 0x40;
|
||||||
|
vb1 |= v[3] & 0x40;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
va |= v[4] << 4 & 0x200;
|
||||||
|
va |= v[5] << 5 & 0x400;
|
||||||
|
vb0 |= v[2] & 0x40;
|
||||||
|
vb1 |= v[3] & 0x40;
|
||||||
|
vb0 |= v[4] << 1 & 0x80;
|
||||||
|
vb1 |= v[5] << 1 & 0x80;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
va |= v[2] << 3 & 0x200;
|
||||||
|
va |= v[3] << 4 & 0x400;
|
||||||
|
vc |= v[5] & 0x40;
|
||||||
|
vc |= v[4] << 1 & 0x80;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
va |= v[4] << 4 & 0x200;
|
||||||
|
va |= v[5] << 5 & 0x400;
|
||||||
|
va |= v[4] << 5 & 0x800;
|
||||||
|
vc |= v[5] & 0x40;
|
||||||
|
vb0 |= v[2] & 0x40;
|
||||||
|
vb1 |= v[3] & 0x40;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
va |= v[2] << 3 & 0x200;
|
||||||
|
va |= v[3] << 4 & 0x400;
|
||||||
|
va |= v[4] << 5 & 0x800;
|
||||||
|
vc |= v[5] & 0x40;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shamt = (mode >> 1) ^ 3;
|
||||||
|
va <<= shamt;
|
||||||
|
vb0 <<= shamt;
|
||||||
|
vb1 <<= shamt;
|
||||||
|
vc <<= shamt;
|
||||||
|
int mult = 1 << shamt;
|
||||||
|
vd0 *= mult;
|
||||||
|
vd1 *= mult;
|
||||||
|
|
||||||
|
if (major_component == 1)
|
||||||
|
set_endpoint_hdr_clamp(endpoints, va - vb0 - vc - vd0, va - vc, va - vb1 - vc - vd1, alpha1, va - vb0, va, va - vb1, alpha2);
|
||||||
|
else if (major_component == 2)
|
||||||
|
set_endpoint_hdr_clamp(endpoints, va - vb1 - vc - vd1, va - vb0 - vc - vd0, va - vc, alpha1, va - vb1, va - vb0, va, alpha2);
|
||||||
|
else
|
||||||
|
set_endpoint_hdr_clamp(endpoints, va - vc, va - vb0 - vc - vd0, va - vb1 - vc - vd1, alpha1, va, va - vb0, va - vb1, alpha2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decode_endpoints(const uint8_t* buf, BlockData* data)
|
||||||
|
{
|
||||||
|
static const int TritsTable[] = { 0, 204, 93, 44, 22, 11, 5 };
|
||||||
|
static const int QuintsTable[] = { 0, 113, 54, 26, 13, 6 };
|
||||||
IntSeqData seq[32];
|
IntSeqData seq[32];
|
||||||
int ev[32];
|
int ev[32];
|
||||||
decode_intseq(buf, data->part_num == 1 ? 17 : 29, CemTableA[data->cem_range], CemTableB[data->cem_range], data->endpoint_value_num, 0, seq);
|
decode_intseq(buf, data->part_num == 1 ? 17 : 29, CemTableA[data->cem_range], CemTableB[data->cem_range], data->endpoint_value_num, 0, seq);
|
||||||
@@ -463,13 +836,34 @@ void decode_endpoints(const uint8_t *buf, BlockData *data) {
|
|||||||
case 0:
|
case 0:
|
||||||
set_endpoint(data->endpoints[cem], v[0], v[0], v[0], 255, v[1], v[1], v[1], 255);
|
set_endpoint(data->endpoints[cem], v[0], v[0], v[0], 255, v[1], v[1], v[1], 255);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1: {
|
||||||
{
|
|
||||||
int l0 = (v[0] >> 2) | (v[1] & 0xc0);
|
int l0 = (v[0] >> 2) | (v[1] & 0xc0);
|
||||||
int l1 = clamp(l0 + (v[1] & 0x3f));
|
int l1 = clamp(l0 + (v[1] & 0x3f));
|
||||||
set_endpoint(data->endpoints[cem], l0, l0, l0, 255, l1, l1, l1, 255);
|
set_endpoint(data->endpoints[cem], l0, l0, l0, 255, l1, l1, l1, 255);
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
int y0, y1;
|
||||||
|
if (v[0] <= v[1]) {
|
||||||
|
y0 = v[0] << 4;
|
||||||
|
y1 = v[1] << 4;
|
||||||
|
} else {
|
||||||
|
y0 = (v[1] << 4) + 8;
|
||||||
|
y1 = (v[0] << 4) - 8;
|
||||||
}
|
}
|
||||||
break;
|
set_endpoint_hdr(data->endpoints[cem], y0, y0, y0, 0x780, y1, y1, y1, 0x780);
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
int y0, d;
|
||||||
|
if (v[0] & 0x80) {
|
||||||
|
y0 = (v[1] & 0xe0) << 4 | (v[0] & 0x7f) << 2;
|
||||||
|
d = (v[1] & 0x1f) << 2;
|
||||||
|
} else {
|
||||||
|
y0 = (v[1] & 0xf0) << 4 | (v[0] & 0x7f) << 1;
|
||||||
|
d = (v[1] & 0x0f) << 1;
|
||||||
|
}
|
||||||
|
int y1 = clamp_hdr(y0 + d);
|
||||||
|
set_endpoint_hdr(data->endpoints[cem], y0, y0, y0, 0x780, y1, y1, y1, 0x780);
|
||||||
|
} break;
|
||||||
case 4:
|
case 4:
|
||||||
set_endpoint(data->endpoints[cem], v[0], v[0], v[0], v[2], v[1], v[1], v[1], v[3]);
|
set_endpoint(data->endpoints[cem], v[0], v[0], v[0], v[2], v[1], v[1], v[1], v[3]);
|
||||||
break;
|
break;
|
||||||
@@ -482,6 +876,9 @@ void decode_endpoints(const uint8_t *buf, BlockData *data) {
|
|||||||
case 6:
|
case 6:
|
||||||
set_endpoint(data->endpoints[cem], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, 255, v[0], v[1], v[2], 255);
|
set_endpoint(data->endpoints[cem], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, 255, v[0], v[1], v[2], 255);
|
||||||
break;
|
break;
|
||||||
|
case 7:
|
||||||
|
decode_endpoints_hdr7(data->endpoints[cem], v);
|
||||||
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5])
|
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5])
|
||||||
set_endpoint(data->endpoints[cem], v[0], v[2], v[4], 255, v[1], v[3], v[5], 255);
|
set_endpoint(data->endpoints[cem], v[0], v[2], v[4], 255, v[1], v[3], v[5], 255);
|
||||||
@@ -500,6 +897,9 @@ void decode_endpoints(const uint8_t *buf, BlockData *data) {
|
|||||||
case 10:
|
case 10:
|
||||||
set_endpoint(data->endpoints[cem], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, v[4], v[0], v[1], v[2], v[5]);
|
set_endpoint(data->endpoints[cem], v[0] * v[3] >> 8, v[1] * v[3] >> 8, v[2] * v[3] >> 8, v[4], v[0], v[1], v[2], v[5]);
|
||||||
break;
|
break;
|
||||||
|
case 11:
|
||||||
|
decode_endpoints_hdr11(data->endpoints[cem], v, 0x780, 0x780);
|
||||||
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5])
|
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5])
|
||||||
set_endpoint(data->endpoints[cem], v[0], v[2], v[4], v[6], v[1], v[3], v[5], v[7]);
|
set_endpoint(data->endpoints[cem], v[0], v[2], v[4], v[6], v[1], v[3], v[5], v[7]);
|
||||||
@@ -516,16 +916,35 @@ void decode_endpoints(const uint8_t *buf, BlockData *data) {
|
|||||||
else
|
else
|
||||||
set_endpoint_blue_clamp(data->endpoints[cem], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7], v[0], v[2], v[4], v[6]);
|
set_endpoint_blue_clamp(data->endpoints[cem], v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7], v[0], v[2], v[4], v[6]);
|
||||||
break;
|
break;
|
||||||
|
case 14:
|
||||||
|
decode_endpoints_hdr11(data->endpoints[cem], v, v[6], v[7]);
|
||||||
|
break;
|
||||||
|
case 15: {
|
||||||
|
int mode = ((v[6] >> 7) & 1) | ((v[7] >> 6) & 2);
|
||||||
|
v[6] &= 0x7f;
|
||||||
|
v[7] &= 0x7f;
|
||||||
|
if (mode == 3) {
|
||||||
|
decode_endpoints_hdr11(data->endpoints[cem], v, v[6] << 5, v[7] << 5);
|
||||||
|
} else {
|
||||||
|
v[6] |= (v[7] << (mode + 1)) & 0x780;
|
||||||
|
v[7] = ((v[7] & (0x3f >> mode)) ^ (0x20 >> mode)) - (0x20 >> mode);
|
||||||
|
v[6] <<= 4 - mode;
|
||||||
|
v[7] <<= 4 - mode;
|
||||||
|
decode_endpoints_hdr11(data->endpoints[cem], v, v[6], clamp_hdr(v[6] + v[7]));
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
rb_raise(rb_eStandardError, "Unsupported ASTC format");
|
rb_raise(rb_eStandardError, "Unsupported ASTC format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_weights(const uint8_t *buf, BlockData *data) {
|
void decode_weights(const uint8_t* buf, BlockData* data)
|
||||||
|
{
|
||||||
IntSeqData seq[128];
|
IntSeqData seq[128];
|
||||||
int wv[128] = {};
|
int wv[128] = {};
|
||||||
decode_intseq(buf, 128, WeightPrecTableA[data->weight_range], WeightPrecTableB[data->weight_range], data->weight_num, 1, seq);
|
decode_intseq(buf, 128, WeightPrecTableA[data->weight_range],
|
||||||
|
WeightPrecTableB[data->weight_range], data->weight_num, 1, seq);
|
||||||
|
|
||||||
if (WeightPrecTableA[data->weight_range] == 0) {
|
if (WeightPrecTableA[data->weight_range] == 0) {
|
||||||
switch (WeightPrecTableB[data->weight_range]) {
|
switch (WeightPrecTableB[data->weight_range]) {
|
||||||
@@ -626,7 +1045,8 @@ void decode_weights(const uint8_t *buf, BlockData *data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void select_partition(const uint8_t *buf, BlockData *data) {
|
void select_partition(const uint8_t* buf, BlockData* data)
|
||||||
|
{
|
||||||
int small_block = data->bw * data->bh < 31;
|
int small_block = data->bw * data->bh < 31;
|
||||||
int seed = (*(int*)buf >> 13 & 0x3ff) | (data->part_num - 1) << 10;
|
int seed = (*(int*)buf >> 13 & 0x3ff) | (data->part_num - 1) << 10;
|
||||||
|
|
||||||
@@ -682,51 +1102,75 @@ void select_partition(const uint8_t *buf, BlockData *data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void applicate_color(const BlockData *data, uint32_t *outbuf) {
|
void applicate_color(const BlockData* data, uint32_t* outbuf)
|
||||||
|
{
|
||||||
|
static const t_select_folor_func_ptr FuncTableC[] = {
|
||||||
|
select_color, select_color, select_color_hdr, select_color_hdr,
|
||||||
|
select_color, select_color, select_color, select_color_hdr,
|
||||||
|
select_color, select_color, select_color, select_color_hdr,
|
||||||
|
select_color, select_color, select_color_hdr, select_color_hdr
|
||||||
|
};
|
||||||
|
static const t_select_folor_func_ptr FuncTableA[] = {
|
||||||
|
select_color, select_color, select_color_hdr, select_color_hdr,
|
||||||
|
select_color, select_color, select_color, select_color_hdr,
|
||||||
|
select_color, select_color, select_color, select_color_hdr,
|
||||||
|
select_color, select_color, select_color, select_color_hdr
|
||||||
|
};
|
||||||
if (data->dual_plane) {
|
if (data->dual_plane) {
|
||||||
int ps[] = { 0, 0, 0, 0 };
|
int ps[] = { 0, 0, 0, 0 };
|
||||||
ps[data->plane_selector] = 1;
|
ps[data->plane_selector] = 1;
|
||||||
if (data->part_num > 1) {
|
if (data->part_num > 1) {
|
||||||
for (int i = 0; i < data->bw * data->bh; i++) {
|
for (int i = 0; i < data->bw * data->bh; i++) {
|
||||||
int p = data->partition[i];
|
int p = data->partition[i];
|
||||||
uint_fast8_t r = select_color(data->endpoints[p][0], data->endpoints[p][4], data->weights[i][ps[0]]);
|
uint_fast8_t r = FuncTableC[data->cem[p]](data->endpoints[p][0], data->endpoints[p][4], data->weights[i][ps[0]]);
|
||||||
uint_fast8_t g = select_color(data->endpoints[p][1], data->endpoints[p][5], data->weights[i][ps[1]]);
|
uint_fast8_t g = FuncTableC[data->cem[p]](data->endpoints[p][1], data->endpoints[p][5], data->weights[i][ps[1]]);
|
||||||
uint_fast8_t b = select_color(data->endpoints[p][2], data->endpoints[p][6], data->weights[i][ps[2]]);
|
uint_fast8_t b = FuncTableC[data->cem[p]](data->endpoints[p][2], data->endpoints[p][6], data->weights[i][ps[2]]);
|
||||||
uint_fast8_t a = select_color(data->endpoints[p][3], data->endpoints[p][7], data->weights[i][ps[3]]);
|
uint_fast8_t a = FuncTableA[data->cem[p]](data->endpoints[p][3], data->endpoints[p][7], data->weights[i][ps[3]]);
|
||||||
outbuf[i] = color(r, g, b, a);
|
outbuf[i] = color(r, g, b, a);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < data->bw * data->bh; i++) {
|
for (int i = 0; i < data->bw * data->bh; i++) {
|
||||||
uint_fast8_t r = select_color(data->endpoints[0][0], data->endpoints[0][4], data->weights[i][ps[0]]);
|
uint_fast8_t r = FuncTableC[data->cem[0]](data->endpoints[0][0], data->endpoints[0][4], data->weights[i][ps[0]]);
|
||||||
uint_fast8_t g = select_color(data->endpoints[0][1], data->endpoints[0][5], data->weights[i][ps[1]]);
|
uint_fast8_t g = FuncTableC[data->cem[0]](data->endpoints[0][1], data->endpoints[0][5], data->weights[i][ps[1]]);
|
||||||
uint_fast8_t b = select_color(data->endpoints[0][2], data->endpoints[0][6], data->weights[i][ps[2]]);
|
uint_fast8_t b = FuncTableC[data->cem[0]](data->endpoints[0][2], data->endpoints[0][6], data->weights[i][ps[2]]);
|
||||||
uint_fast8_t a = select_color(data->endpoints[0][3], data->endpoints[0][7], data->weights[i][ps[3]]);
|
uint_fast8_t a = FuncTableA[data->cem[0]](data->endpoints[0][3], data->endpoints[0][7], data->weights[i][ps[3]]);
|
||||||
outbuf[i] = color(r, g, b, a);
|
outbuf[i] = color(r, g, b, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (data->part_num > 1) {
|
} else if (data->part_num > 1) {
|
||||||
for (int i = 0; i < data->bw * data->bh; i++) {
|
for (int i = 0; i < data->bw * data->bh; i++) {
|
||||||
int p = data->partition[i];
|
int p = data->partition[i];
|
||||||
uint_fast8_t r = select_color(data->endpoints[p][0], data->endpoints[p][4], data->weights[i][0]);
|
uint_fast8_t r = FuncTableC[data->cem[p]](data->endpoints[p][0], data->endpoints[p][4], data->weights[i][0]);
|
||||||
uint_fast8_t g = select_color(data->endpoints[p][1], data->endpoints[p][5], data->weights[i][0]);
|
uint_fast8_t g = FuncTableC[data->cem[p]](data->endpoints[p][1], data->endpoints[p][5], data->weights[i][0]);
|
||||||
uint_fast8_t b = select_color(data->endpoints[p][2], data->endpoints[p][6], data->weights[i][0]);
|
uint_fast8_t b = FuncTableC[data->cem[p]](data->endpoints[p][2], data->endpoints[p][6], data->weights[i][0]);
|
||||||
uint_fast8_t a = select_color(data->endpoints[p][3], data->endpoints[p][7], data->weights[i][0]);
|
uint_fast8_t a = FuncTableA[data->cem[p]](data->endpoints[p][3], data->endpoints[p][7], data->weights[i][0]);
|
||||||
outbuf[i] = color(r, g, b, a);
|
outbuf[i] = color(r, g, b, a);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < data->bw * data->bh; i++) {
|
for (int i = 0; i < data->bw * data->bh; i++) {
|
||||||
uint_fast8_t r = select_color(data->endpoints[0][0], data->endpoints[0][4], data->weights[i][0]);
|
uint_fast8_t r = FuncTableC[data->cem[0]](data->endpoints[0][0], data->endpoints[0][4], data->weights[i][0]);
|
||||||
uint_fast8_t g = select_color(data->endpoints[0][1], data->endpoints[0][5], data->weights[i][0]);
|
uint_fast8_t g = FuncTableC[data->cem[0]](data->endpoints[0][1], data->endpoints[0][5], data->weights[i][0]);
|
||||||
uint_fast8_t b = select_color(data->endpoints[0][2], data->endpoints[0][6], data->weights[i][0]);
|
uint_fast8_t b = FuncTableC[data->cem[0]](data->endpoints[0][2], data->endpoints[0][6], data->weights[i][0]);
|
||||||
uint_fast8_t a = select_color(data->endpoints[0][3], data->endpoints[0][7], data->weights[i][0]);
|
uint_fast8_t a = FuncTableA[data->cem[0]](data->endpoints[0][3], data->endpoints[0][7], data->weights[i][0]);
|
||||||
outbuf[i] = color(r, g, b, a);
|
outbuf[i] = color(r, g, b, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_block(const uint8_t *buf, const int bw, const int bh, uint32_t *outbuf) {
|
void decode_block(const uint8_t* buf, const int bw, const int bh, uint32_t* outbuf)
|
||||||
|
{
|
||||||
if (buf[0] == 0xfc && (buf[1] & 1) == 1) {
|
if (buf[0] == 0xfc && (buf[1] & 1) == 1) {
|
||||||
uint_fast32_t c = color(buf[9], buf[11], buf[13], buf[15]);
|
// void-extent
|
||||||
|
uint_fast32_t c;
|
||||||
|
if (buf[1] & 2)
|
||||||
|
c = color(f16ptr_to_u8(buf + 8), f16ptr_to_u8(buf + 10), f16ptr_to_u8(buf + 12), f16ptr_to_u8(buf + 14));
|
||||||
|
else
|
||||||
|
c = color(buf[9], buf[11], buf[13], buf[15]);
|
||||||
|
for (int i = 0; i < bw * bh; i++)
|
||||||
|
outbuf[i] = c;
|
||||||
|
} else if (((buf[0] & 0xc3) == 0xc0 && (buf[1] & 1) == 1) || (buf[0] & 0xf) == 0) {
|
||||||
|
// reserved (illegal)
|
||||||
|
uint_fast32_t c = color(255, 0, 255, 255);
|
||||||
for (int i = 0; i < bw * bh; i++)
|
for (int i = 0; i < bw * bh; i++)
|
||||||
outbuf[i] = c;
|
outbuf[i] = c;
|
||||||
} else {
|
} else {
|
||||||
@@ -742,19 +1186,21 @@ void decode_block(const uint8_t *buf, const int bw, const int bh, uint32_t *outb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_astc(const uint8_t *data, const int w, const int h, const int bw, const int bh, uint32_t *image) {
|
void decode_astc(const uint8_t* data, const int w, const int h, const int bw, const int bh, uint32_t* image)
|
||||||
int bcw = (w + bw - 1) / bw;
|
{
|
||||||
int bch = (h + bh - 1) / bh;
|
const int num_blocks_x = (w + bw - 1) / bw;
|
||||||
int clen_last = (w + bw - 1) % bw + 1;
|
const int num_blocks_y = (h + bh - 1) / bh;
|
||||||
uint32_t *buf = (uint32_t*)calloc(bw * bh, sizeof(uint32_t));
|
const int copy_length_last = (w + bw - 1) % bw + 1;
|
||||||
|
uint32_t buf[144];
|
||||||
|
uint32_t* buf_end = buf + bw * bh;
|
||||||
const uint8_t* ptr = data;
|
const uint8_t* ptr = data;
|
||||||
for (int t = 0; t < bch; t++) {
|
for (int by = 0; by < num_blocks_y; by++) {
|
||||||
for (int s = 0; s < bcw; s++, ptr += 16) {
|
for (int bx = 0, x = 0; bx < num_blocks_x; bx++, ptr += 16, x += bw) {
|
||||||
decode_block(ptr, bw, bh, buf);
|
decode_block(ptr, bw, bh, buf);
|
||||||
int clen = (s < bcw - 1 ? bw : clen_last) * 4;
|
int copy_length = (bx < num_blocks_x - 1 ? bw : copy_length_last) * 4;
|
||||||
for (int i = 0, y = h - t * bh - 1; i < bh && y >= 0; i++, y--)
|
uint32_t* b = buf;
|
||||||
memcpy(image + y * w + s * bw, buf + i * bw, clen);
|
for (int y = h - by * bh - 1; b < buf_end && y >= 0; y--, b += bw)
|
||||||
|
memcpy(image + y * w + x, b, copy_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(buf);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <ruby.h>
|
||||||
|
|
||||||
|
/* https://github.com/ruby/ruby/blob/master/siphash.c */
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define BYTE_ORDER __LITTLE_ENDIAN
|
||||||
|
#elif !defined BYTE_ORDER
|
||||||
|
#include <endian.h>
|
||||||
|
#endif
|
||||||
|
#ifndef LITTLE_ENDIAN
|
||||||
|
#define LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#ifndef BIG_ENDIAN
|
||||||
|
#define BIG_ENDIAN __BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
#define IS_LITTLE_ENDIAN 1
|
||||||
|
#define IS_BIG_ENDIAN 0
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
#define IS_LITTLE_ENDIAN 0
|
||||||
|
#define IS_BIG_ENDIAN 1
|
||||||
|
#else
|
||||||
|
#error "Only strictly little or big endian supported"
|
||||||
|
#endif
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
|
#include "dxtc.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "dxtc.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_fast32_t r, uint_fast32_t g, uint_fast32_t b, uint_fast32_t a)
|
||||||
|
{
|
||||||
return r | g << 8 | b << 16 | a << 24;
|
return r | g << 8 | b << 16 | a << 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void rgb565(const uint_fast16_t c, int *r, int *g, int *b) {
|
static inline void rgb565(const uint_fast16_t c, int* r, int* g, int* b)
|
||||||
|
{
|
||||||
*r = (c & 0xf800) >> 8;
|
*r = (c & 0xf800) >> 8;
|
||||||
*g = (c & 0x07e0) >> 3;
|
*g = (c & 0x07e0) >> 3;
|
||||||
*b = (c & 0x001f) << 3;
|
*b = (c & 0x001f) << 3;
|
||||||
@@ -15,7 +17,8 @@ static inline void rgb565(const uint_fast16_t c, int *r, int *g, int *b) {
|
|||||||
*b |= *b >> 5;
|
*b |= *b >> 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void decode_dxt1_block(const uint64_t *data, uint32_t *outbuf) {
|
static inline void decode_dxt1_block(const uint64_t* data, uint32_t* outbuf)
|
||||||
|
{
|
||||||
int r0, g0, b0, r1, g1, b1;
|
int r0, g0, b0, r1, g1, b1;
|
||||||
int q0 = ((uint16_t*)data)[0];
|
int q0 = ((uint16_t*)data)[0];
|
||||||
int q1 = ((uint16_t*)data)[1];
|
int q1 = ((uint16_t*)data)[1];
|
||||||
@@ -33,7 +36,8 @@ static inline void decode_dxt1_block(const uint64_t *data, uint32_t *outbuf) {
|
|||||||
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 uint64_t* data, const int w, const int h, uint32_t* image)
|
||||||
|
{
|
||||||
int bcw = (w + 3) / 4;
|
int bcw = (w + 3) / 4;
|
||||||
int bch = (h + 3) / 4;
|
int bch = (h + 3) / 4;
|
||||||
int clen_last = (w + 3) % 4 + 1;
|
int clen_last = (w + 3) % 4 + 1;
|
||||||
@@ -49,7 +53,8 @@ void decode_dxt1(const uint64_t *data, const int w, const int h, uint32_t *image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void decode_dxt5_block(const uint64_t *data, uint32_t *outbuf) {
|
static inline void decode_dxt5_block(const uint64_t* data, uint32_t* outbuf)
|
||||||
|
{
|
||||||
uint_fast32_t a[8] = { ((uint8_t*)data)[0], ((uint8_t*)data)[1] };
|
uint_fast32_t a[8] = { ((uint8_t*)data)[0], ((uint8_t*)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;
|
||||||
@@ -87,7 +92,8 @@ static inline void decode_dxt5_block(const uint64_t *data, uint32_t *outbuf) {
|
|||||||
outbuf[i] = a[da & 7] | c[dc & 3];
|
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 uint64_t* data, const int w, const int h, uint32_t* image)
|
||||||
|
{
|
||||||
int bcw = (w + 3) / 4;
|
int bcw = (w + 3) / 4;
|
||||||
int bch = (h + 3) / 4;
|
int bch = (h + 3) / 4;
|
||||||
int clen_last = (w + 3) % 4 + 1;
|
int clen_last = (w + 3) % 4 + 1;
|
||||||
|
|||||||
+137
-119
@@ -1,13 +1,14 @@
|
|||||||
|
#include "etc.h"
|
||||||
|
#include "common.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "etc.h"
|
|
||||||
|
|
||||||
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 };
|
||||||
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 };
|
||||||
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 } };
|
||||||
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 } };
|
||||||
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 };
|
||||||
int_fast8_t Etc2AlphaModTable[16][8] = {
|
const int_fast8_t Etc2AlphaModTable[16][8] = {
|
||||||
{ -3, -6, -9, -15, 2, 5, 8, 14 },
|
{ -3, -6, -9, -15, 2, 5, 8, 14 },
|
||||||
{ -3, -7, -10, -13, 2, 6, 9, 12 },
|
{ -3, -7, -10, -13, 2, 6, 9, 12 },
|
||||||
{ -2, -5, -8, -13, 1, 4, 7, 12 },
|
{ -2, -5, -8, -13, 1, 4, 7, 12 },
|
||||||
@@ -26,27 +27,37 @@ int_fast8_t Etc2AlphaModTable[16][8] = {
|
|||||||
{ -3, -5, -7, -9, 2, 4, 6, 8 }
|
{ -3, -5, -7, -9, 2, 4, 6, 8 }
|
||||||
};
|
};
|
||||||
|
|
||||||
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 uint_fast8_t clamp(const int n) {
|
static inline uint_fast8_t clamp(const int n)
|
||||||
|
{
|
||||||
return n < 0 ? 0 : n > 255 ? 255 : n;
|
return n < 0 ? 0 : n > 255 ? 255 : n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t applicate_color(uint_fast8_t c[3], int_fast16_t m) {
|
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_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void decode_etc1_block(const uint8_t *data, uint32_t *outbuf) {
|
static inline void decode_etc1_block(const uint8_t* data, uint32_t* outbuf)
|
||||||
uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
|
{
|
||||||
uint_fast8_t *table = Etc1SubblockTable[data[3] & 1];
|
const uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 }; // Table codewords
|
||||||
|
const uint_fast8_t* table = Etc1SubblockTable[data[3] & 1];
|
||||||
uint_fast8_t c[2][3];
|
uint_fast8_t c[2][3];
|
||||||
if (data[3] & 2) {
|
if (data[3] & 2) {
|
||||||
|
// diff bit == 1
|
||||||
c[0][0] = data[0] & 0xf8;
|
c[0][0] = data[0] & 0xf8;
|
||||||
c[0][1] = data[1] & 0xf8;
|
c[0][1] = data[1] & 0xf8;
|
||||||
c[0][2] = data[2] & 0xf8;
|
c[0][2] = data[2] & 0xf8;
|
||||||
@@ -60,16 +71,17 @@ static inline void decode_etc1_block(const uint8_t *data, uint32_t *outbuf) {
|
|||||||
c[1][1] |= c[1][1] >> 5;
|
c[1][1] |= c[1][1] >> 5;
|
||||||
c[1][2] |= c[1][2] >> 5;
|
c[1][2] |= c[1][2] >> 5;
|
||||||
} else {
|
} else {
|
||||||
c[0][0] = data[0] & 0xf0 | data[0] >> 4;
|
// diff bit == 0
|
||||||
c[1][0] = data[0] & 0x0f | data[0] << 4;
|
c[0][0] = (data[0] & 0xf0) | data[0] >> 4;
|
||||||
c[0][1] = data[1] & 0xf0 | data[1] >> 4;
|
c[1][0] = (data[0] & 0x0f) | data[0] << 4;
|
||||||
c[1][1] = data[1] & 0x0f | data[1] << 4;
|
c[0][1] = (data[1] & 0xf0) | data[1] >> 4;
|
||||||
c[0][2] = data[2] & 0xf0 | data[2] >> 4;
|
c[1][1] = (data[1] & 0x0f) | data[1] << 4;
|
||||||
c[1][2] = data[2] & 0x0f | data[2] << 4;
|
c[0][2] = (data[2] & 0xf0) | data[2] >> 4;
|
||||||
|
c[1][2] = (data[2] & 0x0f) | data[2] << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint_fast16_t j = data[6] << 8 | data[7];
|
uint_fast16_t j = data[6] << 8 | data[7]; // less significant pixel index bits
|
||||||
uint_fast16_t k = data[4] << 8 | data[5];
|
uint_fast16_t k = data[4] << 8 | data[5]; // more significant pixel index bits
|
||||||
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
|
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
|
||||||
uint_fast8_t s = table[i];
|
uint_fast8_t s = table[i];
|
||||||
uint_fast8_t m = Etc1ModifierTable[code[s]][j & 1];
|
uint_fast8_t m = Etc1ModifierTable[code[s]][j & 1];
|
||||||
@@ -77,28 +89,33 @@ static inline void decode_etc1_block(const uint8_t *data, uint32_t *outbuf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_etc1(const void *data, const int w, const int h, uint32_t *image) {
|
void decode_etc1(const void* data, const int w, const int h, uint32_t* image)
|
||||||
int bcw = (w + 3) / 4;
|
{
|
||||||
int bch = (h + 3) / 4;
|
int num_blocks_x = (w + 3) / 4;
|
||||||
int clen_last = (w + 3) % 4 + 1;
|
int num_blocks_y = (h + 3) / 4;
|
||||||
|
int copy_length_last = (w + 3) % 4 + 1;
|
||||||
uint32_t buf[16];
|
uint32_t buf[16];
|
||||||
|
uint32_t* buf_end = buf + 16;
|
||||||
const uint8_t* d = (uint8_t*)data;
|
const uint8_t* d = (uint8_t*)data;
|
||||||
for (int t = 0; t < bch; t++) {
|
for (int by = 0; by < num_blocks_y; by++) {
|
||||||
for (int s = 0; s < bcw; s++, d += 8) {
|
for (int bx = 0, x = 0; bx < num_blocks_x; bx++, d += 8, x += 4) {
|
||||||
decode_etc1_block(d, buf);
|
decode_etc1_block(d, buf);
|
||||||
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
|
int copy_length = (bx < 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 - 1 - by * 4; b < buf_end && y >= 0; y--, b += 4)
|
||||||
|
memcpy(image + y * w + x, b, copy_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void decode_etc2_block(const uint8_t *data, uint32_t *outbuf) {
|
static inline void decode_etc2_block(const uint8_t* data, uint32_t* outbuf)
|
||||||
uint_fast16_t j = data[6] << 8 | data[7];
|
{
|
||||||
uint_fast16_t k = data[4] << 8 | data[5];
|
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] = {};
|
uint_fast8_t c[3][3] = {};
|
||||||
|
|
||||||
if (data[3] & 2) {
|
if (data[3] & 2) {
|
||||||
|
// diff bit == 1
|
||||||
uint_fast8_t r = data[0] & 0xf8;
|
uint_fast8_t r = data[0] & 0xf8;
|
||||||
int_fast16_t dr = (data[0] << 3 & 0x18) - (data[0] << 3 & 0x20);
|
int_fast16_t dr = (data[0] << 3 & 0x18) - (data[0] << 3 & 0x20);
|
||||||
uint_fast8_t g = data[1] & 0xf8;
|
uint_fast8_t g = data[1] & 0xf8;
|
||||||
@@ -107,57 +124,49 @@ static inline void decode_etc2_block(const uint8_t *data, uint32_t *outbuf) {
|
|||||||
int_fast16_t db = (data[2] << 3 & 0x18) - (data[2] << 3 & 0x20);
|
int_fast16_t db = (data[2] << 3 & 0x18) - (data[2] << 3 & 0x20);
|
||||||
if (r + dr < 0 || r + dr > 255) {
|
if (r + dr < 0 || r + dr > 255) {
|
||||||
// T
|
// T
|
||||||
c[0][0] = data[0] << 3 & 0xc0 | data[0] << 4 & 0x30 | data[0] >> 1 & 0xc | data[0] & 3;
|
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][1] = (data[1] & 0xf0) | data[1] >> 4;
|
||||||
c[0][2] = data[1] & 0x0f | data[1] << 4;
|
c[0][2] = (data[1] & 0x0f) | data[1] << 4;
|
||||||
c[1][0] = data[2] & 0xf0 | data[2] >> 4;
|
c[1][0] = (data[2] & 0xf0) | data[2] >> 4;
|
||||||
c[1][1] = data[2] & 0x0f | data[2] << 4;
|
c[1][1] = (data[2] & 0x0f) | data[2] << 4;
|
||||||
c[1][2] = data[3] & 0xf0 | data[3] >> 4;
|
c[1][2] = (data[3] & 0xf0) | data[3] >> 4;
|
||||||
uint_fast8_t d = Etc2DistanceTable[data[3] >> 1 & 6 | data[3] & 1];
|
const uint_fast8_t d = Etc2DistanceTable[(data[3] >> 1 & 6) | (data[3] & 1)];
|
||||||
uint_fast32_t color_set[4] = {
|
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) };
|
||||||
applicate_color_raw(c[0]),
|
k <<= 1;
|
||||||
applicate_color(c[1], d),
|
|
||||||
applicate_color_raw(c[1]),
|
|
||||||
applicate_color(c[1], -d)
|
|
||||||
};
|
|
||||||
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1)
|
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1)
|
||||||
outbuf[WriteOrderTable[i]] = color_set[k << 1 & 2 | j & 1];
|
outbuf[WriteOrderTable[i]] = color_set[(k & 2) | (j & 1)];
|
||||||
} else if (g + dg < 0 || g + dg > 255) {
|
} else if (g + dg < 0 || g + dg > 255) {
|
||||||
// H
|
// H
|
||||||
c[0][0] = data[0] << 1 & 0xf0 | data[0] >> 3 & 0xf;
|
c[0][0] = (data[0] << 1 & 0xf0) | (data[0] >> 3 & 0xf);
|
||||||
c[0][1] = data[0] << 5 & 0xe0 | data[1] & 0x10;
|
c[0][1] = (data[0] << 5 & 0xe0) | (data[1] & 0x10);
|
||||||
c[0][1] |= c[0][1] >> 4;
|
c[0][1] |= c[0][1] >> 4;
|
||||||
c[0][2] = data[1] & 8 | data[1] << 1 & 6 | data[2] >> 7;
|
c[0][2] = (data[1] & 8) | (data[1] << 1 & 6) | data[2] >> 7;
|
||||||
c[0][2] |= c[0][2] << 4;
|
c[0][2] |= c[0][2] << 4;
|
||||||
c[1][0] = data[2] << 1 & 0xf0 | data[2] >> 3 & 0xf;
|
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] = (data[2] << 5 & 0xe0) | (data[3] >> 3 & 0x10);
|
||||||
c[1][1] |= c[1][1] >> 4;
|
c[1][1] |= c[1][1] >> 4;
|
||||||
c[1][2] = data[3] << 1 & 0xf0 | data[3] >> 3 & 0xf;
|
c[1][2] = (data[3] << 1 & 0xf0) | (data[3] >> 3 & 0xf);
|
||||||
uint_fast8_t d = data[3] & 4 | data[3] << 1 & 2;
|
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]))))
|
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;
|
||||||
d = Etc2DistanceTable[d];
|
d = Etc2DistanceTable[d];
|
||||||
uint_fast32_t color_set[4] = {
|
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) };
|
||||||
applicate_color(c[0], d),
|
k <<= 1;
|
||||||
applicate_color(c[0], -d),
|
|
||||||
applicate_color(c[1], d),
|
|
||||||
applicate_color(c[1], -d)
|
|
||||||
};
|
|
||||||
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1)
|
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1)
|
||||||
outbuf[WriteOrderTable[i]] = color_set[k << 1 & 2 | j & 1];
|
outbuf[WriteOrderTable[i]] = color_set[(k & 2) | (j & 1)];
|
||||||
} else if (b + db < 0 || b + db > 255) {
|
} else if (b + db < 0 || b + db > 255) {
|
||||||
// planar
|
// planar
|
||||||
c[0][0] = data[0] << 1 & 0xfc | data[0] >> 5 & 3;
|
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][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] = (data[1] << 7 & 0x80) | (data[2] << 2 & 0x60) | (data[2] << 3 & 0x18) | (data[3] >> 5 & 4);
|
||||||
c[0][2] |= c[0][2] >> 6;
|
c[0][2] |= c[0][2] >> 6;
|
||||||
c[1][0] = data[3] << 1 & 0xf8 | data[3] << 2 & 4 | data[3] >> 5 & 3;
|
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][1] = (data[4] & 0xfe) | data[4] >> 7;
|
||||||
c[1][2] = data[4] << 7 & 0x80 | data[5] >> 1 & 0x7c;
|
c[1][2] = (data[4] << 7 & 0x80) | (data[5] >> 1 & 0x7c);
|
||||||
c[1][2] |= c[1][2] >> 6;
|
c[1][2] |= c[1][2] >> 6;
|
||||||
c[2][0] = data[5] << 5 & 0xe0 | data[6] >> 3 & 0x1c | data[5] >> 1 & 3;
|
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][1] = (data[6] << 3 & 0xf8) | (data[7] >> 5 & 0x6) | (data[6] >> 4 & 1);
|
||||||
c[2][2] = data[7] << 2 | data[7] >> 4 & 3;
|
c[2][2] = data[7] << 2 | (data[7] >> 4 & 3);
|
||||||
for (int y = 0, i = 0; y < 4; y++) {
|
for (int y = 0, i = 0; y < 4; y++) {
|
||||||
for (int x = 0; x < 4; x++, i++) {
|
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 r = clamp((x * (c[1][0] - c[0][0]) + y * (c[2][0] - c[0][0]) + 4 * c[0][0] + 2) >> 2);
|
||||||
@@ -168,8 +177,8 @@ static inline void decode_etc2_block(const uint8_t *data, uint32_t *outbuf) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// differential
|
// differential
|
||||||
uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
|
const uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
|
||||||
uint_fast8_t *table = Etc1SubblockTable[data[3] & 1];
|
const uint_fast8_t* table = Etc1SubblockTable[data[3] & 1];
|
||||||
c[0][0] = r | r >> 5;
|
c[0][0] = r | r >> 5;
|
||||||
c[0][1] = g | g >> 5;
|
c[0][1] = g | g >> 5;
|
||||||
c[0][2] = b | b >> 5;
|
c[0][2] = b | b >> 5;
|
||||||
@@ -186,15 +195,15 @@ static inline void decode_etc2_block(const uint8_t *data, uint32_t *outbuf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// individual
|
// individual (diff bit == 0)
|
||||||
uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
|
const uint_fast8_t code[2] = { data[3] >> 5, data[3] >> 2 & 7 };
|
||||||
uint_fast8_t *table = Etc1SubblockTable[data[3] & 1];
|
const uint_fast8_t* table = Etc1SubblockTable[data[3] & 1];
|
||||||
c[0][0] = data[0] & 0xf0 | data[0] >> 4;
|
c[0][0] = (data[0] & 0xf0) | data[0] >> 4;
|
||||||
c[1][0] = data[0] & 0x0f | data[0] << 4;
|
c[1][0] = (data[0] & 0x0f) | data[0] << 4;
|
||||||
c[0][1] = data[1] & 0xf0 | data[1] >> 4;
|
c[0][1] = (data[1] & 0xf0) | data[1] >> 4;
|
||||||
c[1][1] = data[1] & 0x0f | data[1] << 4;
|
c[1][1] = (data[1] & 0x0f) | data[1] << 4;
|
||||||
c[0][2] = data[2] & 0xf0 | data[2] >> 4;
|
c[0][2] = (data[2] & 0xf0) | data[2] >> 4;
|
||||||
c[1][2] = data[2] & 0x0f | data[2] << 4;
|
c[1][2] = (data[2] & 0x0f) | data[2] << 4;
|
||||||
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
|
for (int i = 0; i < 16; i++, j >>= 1, k >>= 1) {
|
||||||
uint_fast8_t s = table[i];
|
uint_fast8_t s = table[i];
|
||||||
uint_fast8_t m = Etc1ModifierTable[code[s]][j & 1];
|
uint_fast8_t m = Etc1ModifierTable[code[s]][j & 1];
|
||||||
@@ -203,69 +212,78 @@ static inline void decode_etc2_block(const uint8_t *data, uint32_t *outbuf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
uint_fast8_t mult = data[1] >> 4;
|
// multiplier != 0
|
||||||
int_fast8_t *table = Etc2AlphaModTable[data[1] & 0xf];
|
const uint_fast8_t multiplier = data[1] >> 4;
|
||||||
uint_fast64_t l =
|
const int_fast8_t* table = Etc2AlphaModTable[data[1] & 0xf];
|
||||||
data[7] | (uint_fast16_t)data[6] << 8 |
|
uint_fast64_t l = data[7] | (uint_fast16_t)data[6] << 8 | (uint_fast32_t)data[5] << 16 | (uint_fast32_t)data[4] << 24 | (uint_fast64_t)data[3] << 32 | (uint_fast64_t)data[2] << 40;
|
||||||
(uint_fast32_t)data[5] << 16 | (uint_fast32_t)data[4] << 24 |
|
|
||||||
(uint_fast64_t)data[3] << 32 | (uint_fast64_t)data[2] << 40;
|
|
||||||
for (int i = 0; i < 16; i++, l >>= 3)
|
for (int i = 0; i < 16; i++, l >>= 3)
|
||||||
((uint8_t*)(outbuf + WriteOrderTableRev[i]))[3] = clamp(data[0] + mult * table[l & 7]);
|
((uint8_t*)(outbuf + WriteOrderTableRev[i]))[3] = clamp(data[0] + multiplier * table[l & 7]);
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < 16; i++)
|
// multiplier == 0 (always same as base codeword)
|
||||||
((uint8_t*)(outbuf + i))[3] = data[0];
|
for (int i = 0; i < 16; i++, outbuf++)
|
||||||
|
((uint8_t*)outbuf)[3] = data[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_etc2(const void *data, const int w, const int h, uint32_t *image) {
|
void decode_etc2(const void* data, const int w, const int h, uint32_t* image)
|
||||||
int bcw = (w + 3) / 4;
|
{
|
||||||
int bch = (h + 3) / 4;
|
int num_blocks_x = (w + 3) / 4;
|
||||||
int clen_last = (w + 3) % 4 + 1;
|
int num_blocks_y = (h + 3) / 4;
|
||||||
|
int copy_length_last = (w + 3) % 4 + 1;
|
||||||
uint32_t buf[16];
|
uint32_t buf[16];
|
||||||
|
uint32_t* buf_end = buf + 16;
|
||||||
const uint8_t* d = (uint8_t*)data;
|
const uint8_t* d = (uint8_t*)data;
|
||||||
for (int t = 0; t < bch; t++) {
|
for (int by = 0; by < num_blocks_y; by++) {
|
||||||
for (int s = 0; s < bcw; s++, d += 8) {
|
for (int bx = 0, x = 0; bx < num_blocks_x; bx++, d += 8, x += 4) {
|
||||||
decode_etc2_block(d, buf);
|
decode_etc2_block(d, buf);
|
||||||
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
|
int copy_length = (bx < 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 - by * 4 - 1; b < buf_end && y >= 0; y--, b += 4)
|
||||||
|
memcpy(image + y * w + x, b, copy_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_etc2a1(const void *data, const int w, const int h, uint32_t *image) {
|
void decode_etc2a1(const void* data, const int w, const int h, uint32_t* image)
|
||||||
int bcw = (w + 3) / 4;
|
{
|
||||||
int bch = (h + 3) / 4;
|
int num_blocks_x = (w + 3) / 4;
|
||||||
int clen_last = (w + 3) % 4 + 1;
|
int num_blocks_y = (h + 3) / 4;
|
||||||
|
int copy_length_last = (w + 3) % 4 + 1;
|
||||||
uint32_t buf[16];
|
uint32_t buf[16];
|
||||||
|
uint32_t* buf_end = buf + 16;
|
||||||
const uint8_t* d = (uint8_t*)data;
|
const uint8_t* d = (uint8_t*)data;
|
||||||
for (int t = 0; t < bch; t++) {
|
for (int by = 0; by < num_blocks_y; by++) {
|
||||||
for (int s = 0; s < bcw; s++, d += 9) {
|
for (int bx = 0, x = 0; bx < num_blocks_x; bx++, d += 9, x += 4) {
|
||||||
decode_etc2_block(d + 1, buf);
|
decode_etc2_block(d + 1, buf);
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
((uint8_t*)(buf + i))[3] = d[0];
|
((uint8_t*)(buf + i))[3] = d[0];
|
||||||
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
|
int copy_length = (bx < 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 - by * 4 - 1; b < buf_end && y >= 0; y--, b += 4)
|
||||||
|
memcpy(image + y * w + x, b, copy_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_etc2a8(const void *data, const int w, const int h, uint32_t *image) {
|
void decode_etc2a8(const void* data, const int w, const int h, uint32_t* image)
|
||||||
int bcw = (w + 3) / 4;
|
{
|
||||||
int bch = (h + 3) / 4;
|
int num_blocks_x = (w + 3) / 4;
|
||||||
int clen_last = (w + 3) % 4 + 1;
|
int num_blocks_y = (h + 3) / 4;
|
||||||
|
int copy_length_last = (w + 3) % 4 + 1;
|
||||||
uint32_t buf[16];
|
uint32_t buf[16];
|
||||||
|
uint32_t* buf_end = buf + 16;
|
||||||
const uint8_t* d = (uint8_t*)data;
|
const uint8_t* d = (uint8_t*)data;
|
||||||
for (int t = 0; t < bch; t++) {
|
for (int by = 0; by < num_blocks_y; by++) {
|
||||||
for (int s = 0; s < bcw; s++, d += 16) {
|
for (int bx = 0, x = 0; bx < num_blocks_x; bx++, d += 16, x += 4) {
|
||||||
decode_etc2_block(d + 8, buf);
|
decode_etc2_block(d + 8, buf);
|
||||||
decode_etc2a8_block(d, buf);
|
decode_etc2a8_block(d, buf);
|
||||||
int clen = (s < bcw - 1 ? 4 : clen_last) * 4;
|
int copy_length = (bx < 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 - by * 4 - 1; b < buf_end && y >= 0; y--, b += 4)
|
||||||
|
memcpy(image + y * w + x, b, copy_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef FP16_H
|
||||||
|
#define FP16_H
|
||||||
|
|
||||||
|
#include "fp16/fp16.h"
|
||||||
|
|
||||||
|
#endif /* FP16_H */
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* License Information
|
||||||
|
*
|
||||||
|
* FP16 library is derived from https://github.com/Maratyszcza/FP16.
|
||||||
|
* The library is licensed under the MIT License shown below.
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 Facebook Inc.
|
||||||
|
Copyright (c) 2017 Georgia Institute of Technology
|
||||||
|
Copyright 2019 Google LLC
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
**/
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef FP16_BITCASTS_H
|
||||||
|
#define FP16_BITCASTS_H
|
||||||
|
|
||||||
|
#if defined(__cplusplus) && (__cplusplus >= 201103L)
|
||||||
|
#include <cstdint>
|
||||||
|
#elif !defined(__OPENCL_VERSION__)
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static inline float fp32_from_bits(uint32_t w) {
|
||||||
|
#if defined(__OPENCL_VERSION__)
|
||||||
|
return as_float(w);
|
||||||
|
#elif defined(__CUDA_ARCH__)
|
||||||
|
return __uint_as_float((unsigned int) w);
|
||||||
|
#elif defined(__INTEL_COMPILER)
|
||||||
|
return _castu32_f32(w);
|
||||||
|
#else
|
||||||
|
union {
|
||||||
|
uint32_t as_bits;
|
||||||
|
float as_value;
|
||||||
|
} fp32 = { w };
|
||||||
|
return fp32.as_value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t fp32_to_bits(float f) {
|
||||||
|
#if defined(__OPENCL_VERSION__)
|
||||||
|
return as_uint(f);
|
||||||
|
#elif defined(__CUDA_ARCH__)
|
||||||
|
return (uint32_t) __float_as_uint(f);
|
||||||
|
#elif defined(__INTEL_COMPILER)
|
||||||
|
return _castf32_u32(f);
|
||||||
|
#else
|
||||||
|
union {
|
||||||
|
float as_value;
|
||||||
|
uint32_t as_bits;
|
||||||
|
} fp32 = { f };
|
||||||
|
return fp32.as_bits;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double fp64_from_bits(uint64_t w) {
|
||||||
|
#if defined(__OPENCL_VERSION__)
|
||||||
|
return as_double(w);
|
||||||
|
#elif defined(__CUDA_ARCH__)
|
||||||
|
return __longlong_as_double((long long) w);
|
||||||
|
#elif defined(__INTEL_COMPILER)
|
||||||
|
return _castu64_f64(w);
|
||||||
|
#else
|
||||||
|
union {
|
||||||
|
uint64_t as_bits;
|
||||||
|
double as_value;
|
||||||
|
} fp64 = { w };
|
||||||
|
return fp64.as_value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t fp64_to_bits(double f) {
|
||||||
|
#if defined(__OPENCL_VERSION__)
|
||||||
|
return as_ulong(f);
|
||||||
|
#elif defined(__CUDA_ARCH__)
|
||||||
|
return (uint64_t) __double_as_longlong(f);
|
||||||
|
#elif defined(__INTEL_COMPILER)
|
||||||
|
return _castf64_u64(f);
|
||||||
|
#else
|
||||||
|
union {
|
||||||
|
double as_value;
|
||||||
|
uint64_t as_bits;
|
||||||
|
} fp64 = { f };
|
||||||
|
return fp64.as_bits;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FP16_BITCASTS_H */
|
||||||
@@ -0,0 +1,451 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef FP16_FP16_H
|
||||||
|
#define FP16_FP16_H
|
||||||
|
|
||||||
|
#if defined(__cplusplus) && (__cplusplus >= 201103L)
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cmath>
|
||||||
|
#elif !defined(__OPENCL_VERSION__)
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "fp16/bitcasts.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a 16-bit floating-point number in IEEE half-precision format, in bit representation, to
|
||||||
|
* a 32-bit floating-point number in IEEE single-precision format, in bit representation.
|
||||||
|
*
|
||||||
|
* @note The implementation doesn't use any floating-point operations.
|
||||||
|
*/
|
||||||
|
static inline uint32_t fp16_ieee_to_fp32_bits(uint16_t h) {
|
||||||
|
/*
|
||||||
|
* Extend the half-precision floating-point number to 32 bits and shift to the upper part of the 32-bit word:
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000|
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* Bits 31 26-30 16-25 0-15
|
||||||
|
*
|
||||||
|
* S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 - zero bits.
|
||||||
|
*/
|
||||||
|
const uint32_t w = (uint32_t) h << 16;
|
||||||
|
/*
|
||||||
|
* Extract the sign of the input number into the high bit of the 32-bit word:
|
||||||
|
*
|
||||||
|
* +---+----------------------------------+
|
||||||
|
* | S |0000000 00000000 00000000 00000000|
|
||||||
|
* +---+----------------------------------+
|
||||||
|
* Bits 31 0-31
|
||||||
|
*/
|
||||||
|
const uint32_t sign = w & UINT32_C(0x80000000);
|
||||||
|
/*
|
||||||
|
* Extract mantissa and biased exponent of the input number into the bits 0-30 of the 32-bit word:
|
||||||
|
*
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* | 0 |EEEEE|MM MMMM MMMM|0000 0000 0000 0000|
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* Bits 30 27-31 17-26 0-16
|
||||||
|
*/
|
||||||
|
const uint32_t nonsign = w & UINT32_C(0x7FFFFFFF);
|
||||||
|
/*
|
||||||
|
* Renorm shift is the number of bits to shift mantissa left to make the half-precision number normalized.
|
||||||
|
* If the initial number is normalized, some of its high 6 bits (sign == 0 and 5-bit exponent) equals one.
|
||||||
|
* In this case renorm_shift == 0. If the number is denormalize, renorm_shift > 0. Note that if we shift
|
||||||
|
* denormalized nonsign by renorm_shift, the unit bit of mantissa will shift into exponent, turning the
|
||||||
|
* biased exponent into 1, and making mantissa normalized (i.e. without leading 1).
|
||||||
|
*/
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
unsigned long nonsign_bsr;
|
||||||
|
_BitScanReverse(&nonsign_bsr, (unsigned long) nonsign);
|
||||||
|
uint32_t renorm_shift = (uint32_t) nonsign_bsr ^ 31;
|
||||||
|
#else
|
||||||
|
uint32_t renorm_shift = __builtin_clz(nonsign);
|
||||||
|
#endif
|
||||||
|
renorm_shift = renorm_shift > 5 ? renorm_shift - 5 : 0;
|
||||||
|
/*
|
||||||
|
* Iff half-precision number has exponent of 15, the addition overflows it into bit 31,
|
||||||
|
* and the subsequent shift turns the high 9 bits into 1. Thus
|
||||||
|
* inf_nan_mask ==
|
||||||
|
* 0x7F800000 if the half-precision number had exponent of 15 (i.e. was NaN or infinity)
|
||||||
|
* 0x00000000 otherwise
|
||||||
|
*/
|
||||||
|
const int32_t inf_nan_mask = ((int32_t) (nonsign + 0x04000000) >> 8) & INT32_C(0x7F800000);
|
||||||
|
/*
|
||||||
|
* Iff nonsign is 0, it overflows into 0xFFFFFFFF, turning bit 31 into 1. Otherwise, bit 31 remains 0.
|
||||||
|
* The signed shift right by 31 broadcasts bit 31 into all bits of the zero_mask. Thus
|
||||||
|
* zero_mask ==
|
||||||
|
* 0xFFFFFFFF if the half-precision number was zero (+0.0h or -0.0h)
|
||||||
|
* 0x00000000 otherwise
|
||||||
|
*/
|
||||||
|
const int32_t zero_mask = (int32_t) (nonsign - 1) >> 31;
|
||||||
|
/*
|
||||||
|
* 1. Shift nonsign left by renorm_shift to normalize it (if the input was denormal)
|
||||||
|
* 2. Shift nonsign right by 3 so the exponent (5 bits originally) becomes an 8-bit field and 10-bit mantissa
|
||||||
|
* shifts into the 10 high bits of the 23-bit mantissa of IEEE single-precision number.
|
||||||
|
* 3. Add 0x70 to the exponent (starting at bit 23) to compensate the different in exponent bias
|
||||||
|
* (0x7F for single-precision number less 0xF for half-precision number).
|
||||||
|
* 4. Subtract renorm_shift from the exponent (starting at bit 23) to account for renormalization. As renorm_shift
|
||||||
|
* is less than 0x70, this can be combined with step 3.
|
||||||
|
* 5. Binary OR with inf_nan_mask to turn the exponent into 0xFF if the input was NaN or infinity.
|
||||||
|
* 6. Binary ANDNOT with zero_mask to turn the mantissa and exponent into zero if the input was zero.
|
||||||
|
* 7. Combine with the sign of the input number.
|
||||||
|
*/
|
||||||
|
return sign | ((((nonsign << renorm_shift >> 3) + ((0x70 - renorm_shift) << 23)) | inf_nan_mask) & ~zero_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a 16-bit floating-point number in IEEE half-precision format, in bit representation, to
|
||||||
|
* a 32-bit floating-point number in IEEE single-precision format.
|
||||||
|
*
|
||||||
|
* @note The implementation relies on IEEE-like (no assumption about rounding mode and no operations on denormals)
|
||||||
|
* floating-point operations and bitcasts between integer and floating-point variables.
|
||||||
|
*/
|
||||||
|
static inline float fp16_ieee_to_fp32_value(uint16_t h) {
|
||||||
|
/*
|
||||||
|
* Extend the half-precision floating-point number to 32 bits and shift to the upper part of the 32-bit word:
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000|
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* Bits 31 26-30 16-25 0-15
|
||||||
|
*
|
||||||
|
* S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 - zero bits.
|
||||||
|
*/
|
||||||
|
const uint32_t w = (uint32_t) h << 16;
|
||||||
|
/*
|
||||||
|
* Extract the sign of the input number into the high bit of the 32-bit word:
|
||||||
|
*
|
||||||
|
* +---+----------------------------------+
|
||||||
|
* | S |0000000 00000000 00000000 00000000|
|
||||||
|
* +---+----------------------------------+
|
||||||
|
* Bits 31 0-31
|
||||||
|
*/
|
||||||
|
const uint32_t sign = w & UINT32_C(0x80000000);
|
||||||
|
/*
|
||||||
|
* Extract mantissa and biased exponent of the input number into the high bits of the 32-bit word:
|
||||||
|
*
|
||||||
|
* +-----+------------+---------------------+
|
||||||
|
* |EEEEE|MM MMMM MMMM|0 0000 0000 0000 0000|
|
||||||
|
* +-----+------------+---------------------+
|
||||||
|
* Bits 27-31 17-26 0-16
|
||||||
|
*/
|
||||||
|
const uint32_t two_w = w + w;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shift mantissa and exponent into bits 23-28 and bits 13-22 so they become mantissa and exponent
|
||||||
|
* of a single-precision floating-point number:
|
||||||
|
*
|
||||||
|
* S|Exponent | Mantissa
|
||||||
|
* +-+---+-----+------------+----------------+
|
||||||
|
* |0|000|EEEEE|MM MMMM MMMM|0 0000 0000 0000|
|
||||||
|
* +-+---+-----+------------+----------------+
|
||||||
|
* Bits | 23-31 | 0-22
|
||||||
|
*
|
||||||
|
* Next, there are some adjustments to the exponent:
|
||||||
|
* - The exponent needs to be corrected by the difference in exponent bias between single-precision and half-precision
|
||||||
|
* formats (0x7F - 0xF = 0x70)
|
||||||
|
* - Inf and NaN values in the inputs should become Inf and NaN values after conversion to the single-precision number.
|
||||||
|
* Therefore, if the biased exponent of the half-precision input was 0x1F (max possible value), the biased exponent
|
||||||
|
* of the single-precision output must be 0xFF (max possible value). We do this correction in two steps:
|
||||||
|
* - First, we adjust the exponent by (0xFF - 0x1F) = 0xE0 (see exp_offset below) rather than by 0x70 suggested
|
||||||
|
* by the difference in the exponent bias (see above).
|
||||||
|
* - Then we multiply the single-precision result of exponent adjustment by 2**(-112) to reverse the effect of
|
||||||
|
* exponent adjustment by 0xE0 less the necessary exponent adjustment by 0x70 due to difference in exponent bias.
|
||||||
|
* The floating-point multiplication hardware would ensure than Inf and NaN would retain their value on at least
|
||||||
|
* partially IEEE754-compliant implementations.
|
||||||
|
*
|
||||||
|
* Note that the above operations do not handle denormal inputs (where biased exponent == 0). However, they also do not
|
||||||
|
* operate on denormal inputs, and do not produce denormal results.
|
||||||
|
*/
|
||||||
|
const uint32_t exp_offset = UINT32_C(0xE0) << 23;
|
||||||
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
|
const float exp_scale = 0x1.0p-112f;
|
||||||
|
#else
|
||||||
|
const float exp_scale = fp32_from_bits(UINT32_C(0x7800000));
|
||||||
|
#endif
|
||||||
|
const float normalized_value = fp32_from_bits((two_w >> 4) + exp_offset) * exp_scale;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert denormalized half-precision inputs into single-precision results (always normalized).
|
||||||
|
* Zero inputs are also handled here.
|
||||||
|
*
|
||||||
|
* In a denormalized number the biased exponent is zero, and mantissa has on-zero bits.
|
||||||
|
* First, we shift mantissa into bits 0-9 of the 32-bit word.
|
||||||
|
*
|
||||||
|
* zeros | mantissa
|
||||||
|
* +---------------------------+------------+
|
||||||
|
* |0000 0000 0000 0000 0000 00|MM MMMM MMMM|
|
||||||
|
* +---------------------------+------------+
|
||||||
|
* Bits 10-31 0-9
|
||||||
|
*
|
||||||
|
* Now, remember that denormalized half-precision numbers are represented as:
|
||||||
|
* FP16 = mantissa * 2**(-24).
|
||||||
|
* The trick is to construct a normalized single-precision number with the same mantissa and thehalf-precision input
|
||||||
|
* and with an exponent which would scale the corresponding mantissa bits to 2**(-24).
|
||||||
|
* A normalized single-precision floating-point number is represented as:
|
||||||
|
* FP32 = (1 + mantissa * 2**(-23)) * 2**(exponent - 127)
|
||||||
|
* Therefore, when the biased exponent is 126, a unit change in the mantissa of the input denormalized half-precision
|
||||||
|
* number causes a change of the constructud single-precision number by 2**(-24), i.e. the same ammount.
|
||||||
|
*
|
||||||
|
* The last step is to adjust the bias of the constructed single-precision number. When the input half-precision number
|
||||||
|
* is zero, the constructed single-precision number has the value of
|
||||||
|
* FP32 = 1 * 2**(126 - 127) = 2**(-1) = 0.5
|
||||||
|
* Therefore, we need to subtract 0.5 from the constructed single-precision number to get the numerical equivalent of
|
||||||
|
* the input half-precision number.
|
||||||
|
*/
|
||||||
|
const uint32_t magic_mask = UINT32_C(126) << 23;
|
||||||
|
const float magic_bias = 0.5f;
|
||||||
|
const float denormalized_value = fp32_from_bits((two_w >> 17) | magic_mask) - magic_bias;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* - Choose either results of conversion of input as a normalized number, or as a denormalized number, depending on the
|
||||||
|
* input exponent. The variable two_w contains input exponent in bits 27-31, therefore if its smaller than 2**27, the
|
||||||
|
* input is either a denormal number, or zero.
|
||||||
|
* - Combine the result of conversion of exponent and mantissa with the sign of the input number.
|
||||||
|
*/
|
||||||
|
const uint32_t denormalized_cutoff = UINT32_C(1) << 27;
|
||||||
|
const uint32_t result = sign |
|
||||||
|
(two_w < denormalized_cutoff ? fp32_to_bits(denormalized_value) : fp32_to_bits(normalized_value));
|
||||||
|
return fp32_from_bits(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a 32-bit floating-point number in IEEE single-precision format to a 16-bit floating-point number in
|
||||||
|
* IEEE half-precision format, in bit representation.
|
||||||
|
*
|
||||||
|
* @note The implementation relies on IEEE-like (no assumption about rounding mode and no operations on denormals)
|
||||||
|
* floating-point operations and bitcasts between integer and floating-point variables.
|
||||||
|
*/
|
||||||
|
static inline uint16_t fp16_ieee_from_fp32_value(float f) {
|
||||||
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
|
const float scale_to_inf = 0x1.0p+112f;
|
||||||
|
const float scale_to_zero = 0x1.0p-110f;
|
||||||
|
#else
|
||||||
|
const float scale_to_inf = fp32_from_bits(UINT32_C(0x77800000));
|
||||||
|
const float scale_to_zero = fp32_from_bits(UINT32_C(0x08800000));
|
||||||
|
#endif
|
||||||
|
float base = (fabsf(f) * scale_to_inf) * scale_to_zero;
|
||||||
|
|
||||||
|
const uint32_t w = fp32_to_bits(f);
|
||||||
|
const uint32_t shl1_w = w + w;
|
||||||
|
const uint32_t sign = w & UINT32_C(0x80000000);
|
||||||
|
uint32_t bias = shl1_w & UINT32_C(0xFF000000);
|
||||||
|
if (bias < UINT32_C(0x71000000)) {
|
||||||
|
bias = UINT32_C(0x71000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
base = fp32_from_bits((bias >> 1) + UINT32_C(0x07800000)) + base;
|
||||||
|
const uint32_t bits = fp32_to_bits(base);
|
||||||
|
const uint32_t exp_bits = (bits >> 13) & UINT32_C(0x00007C00);
|
||||||
|
const uint32_t mantissa_bits = bits & UINT32_C(0x00000FFF);
|
||||||
|
const uint32_t nonsign = exp_bits + mantissa_bits;
|
||||||
|
return (sign >> 16) | (shl1_w > UINT32_C(0xFF000000) ? UINT16_C(0x7E00) : nonsign);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a 16-bit floating-point number in ARM alternative half-precision format, in bit representation, to
|
||||||
|
* a 32-bit floating-point number in IEEE single-precision format, in bit representation.
|
||||||
|
*
|
||||||
|
* @note The implementation doesn't use any floating-point operations.
|
||||||
|
*/
|
||||||
|
static inline uint32_t fp16_alt_to_fp32_bits(uint16_t h) {
|
||||||
|
/*
|
||||||
|
* Extend the half-precision floating-point number to 32 bits and shift to the upper part of the 32-bit word:
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000|
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* Bits 31 26-30 16-25 0-15
|
||||||
|
*
|
||||||
|
* S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 - zero bits.
|
||||||
|
*/
|
||||||
|
const uint32_t w = (uint32_t) h << 16;
|
||||||
|
/*
|
||||||
|
* Extract the sign of the input number into the high bit of the 32-bit word:
|
||||||
|
*
|
||||||
|
* +---+----------------------------------+
|
||||||
|
* | S |0000000 00000000 00000000 00000000|
|
||||||
|
* +---+----------------------------------+
|
||||||
|
* Bits 31 0-31
|
||||||
|
*/
|
||||||
|
const uint32_t sign = w & UINT32_C(0x80000000);
|
||||||
|
/*
|
||||||
|
* Extract mantissa and biased exponent of the input number into the bits 0-30 of the 32-bit word:
|
||||||
|
*
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* | 0 |EEEEE|MM MMMM MMMM|0000 0000 0000 0000|
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* Bits 30 27-31 17-26 0-16
|
||||||
|
*/
|
||||||
|
const uint32_t nonsign = w & UINT32_C(0x7FFFFFFF);
|
||||||
|
/*
|
||||||
|
* Renorm shift is the number of bits to shift mantissa left to make the half-precision number normalized.
|
||||||
|
* If the initial number is normalized, some of its high 6 bits (sign == 0 and 5-bit exponent) equals one.
|
||||||
|
* In this case renorm_shift == 0. If the number is denormalize, renorm_shift > 0. Note that if we shift
|
||||||
|
* denormalized nonsign by renorm_shift, the unit bit of mantissa will shift into exponent, turning the
|
||||||
|
* biased exponent into 1, and making mantissa normalized (i.e. without leading 1).
|
||||||
|
*/
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
unsigned long nonsign_bsr;
|
||||||
|
_BitScanReverse(&nonsign_bsr, (unsigned long) nonsign);
|
||||||
|
uint32_t renorm_shift = (uint32_t) nonsign_bsr ^ 31;
|
||||||
|
#else
|
||||||
|
uint32_t renorm_shift = __builtin_clz(nonsign);
|
||||||
|
#endif
|
||||||
|
renorm_shift = renorm_shift > 5 ? renorm_shift - 5 : 0;
|
||||||
|
/*
|
||||||
|
* Iff nonsign is 0, it overflows into 0xFFFFFFFF, turning bit 31 into 1. Otherwise, bit 31 remains 0.
|
||||||
|
* The signed shift right by 31 broadcasts bit 31 into all bits of the zero_mask. Thus
|
||||||
|
* zero_mask ==
|
||||||
|
* 0xFFFFFFFF if the half-precision number was zero (+0.0h or -0.0h)
|
||||||
|
* 0x00000000 otherwise
|
||||||
|
*/
|
||||||
|
const int32_t zero_mask = (int32_t) (nonsign - 1) >> 31;
|
||||||
|
/*
|
||||||
|
* 1. Shift nonsign left by renorm_shift to normalize it (if the input was denormal)
|
||||||
|
* 2. Shift nonsign right by 3 so the exponent (5 bits originally) becomes an 8-bit field and 10-bit mantissa
|
||||||
|
* shifts into the 10 high bits of the 23-bit mantissa of IEEE single-precision number.
|
||||||
|
* 3. Add 0x70 to the exponent (starting at bit 23) to compensate the different in exponent bias
|
||||||
|
* (0x7F for single-precision number less 0xF for half-precision number).
|
||||||
|
* 4. Subtract renorm_shift from the exponent (starting at bit 23) to account for renormalization. As renorm_shift
|
||||||
|
* is less than 0x70, this can be combined with step 3.
|
||||||
|
* 5. Binary ANDNOT with zero_mask to turn the mantissa and exponent into zero if the input was zero.
|
||||||
|
* 6. Combine with the sign of the input number.
|
||||||
|
*/
|
||||||
|
return sign | (((nonsign << renorm_shift >> 3) + ((0x70 - renorm_shift) << 23)) & ~zero_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a 16-bit floating-point number in ARM alternative half-precision format, in bit representation, to
|
||||||
|
* a 32-bit floating-point number in IEEE single-precision format.
|
||||||
|
*
|
||||||
|
* @note The implementation relies on IEEE-like (no assumption about rounding mode and no operations on denormals)
|
||||||
|
* floating-point operations and bitcasts between integer and floating-point variables.
|
||||||
|
*/
|
||||||
|
static inline float fp16_alt_to_fp32_value(uint16_t h) {
|
||||||
|
/*
|
||||||
|
* Extend the half-precision floating-point number to 32 bits and shift to the upper part of the 32-bit word:
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* | S |EEEEE|MM MMMM MMMM|0000 0000 0000 0000|
|
||||||
|
* +---+-----+------------+-------------------+
|
||||||
|
* Bits 31 26-30 16-25 0-15
|
||||||
|
*
|
||||||
|
* S - sign bit, E - bits of the biased exponent, M - bits of the mantissa, 0 - zero bits.
|
||||||
|
*/
|
||||||
|
const uint32_t w = (uint32_t) h << 16;
|
||||||
|
/*
|
||||||
|
* Extract the sign of the input number into the high bit of the 32-bit word:
|
||||||
|
*
|
||||||
|
* +---+----------------------------------+
|
||||||
|
* | S |0000000 00000000 00000000 00000000|
|
||||||
|
* +---+----------------------------------+
|
||||||
|
* Bits 31 0-31
|
||||||
|
*/
|
||||||
|
const uint32_t sign = w & UINT32_C(0x80000000);
|
||||||
|
/*
|
||||||
|
* Extract mantissa and biased exponent of the input number into the high bits of the 32-bit word:
|
||||||
|
*
|
||||||
|
* +-----+------------+---------------------+
|
||||||
|
* |EEEEE|MM MMMM MMMM|0 0000 0000 0000 0000|
|
||||||
|
* +-----+------------+---------------------+
|
||||||
|
* Bits 27-31 17-26 0-16
|
||||||
|
*/
|
||||||
|
const uint32_t two_w = w + w;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shift mantissa and exponent into bits 23-28 and bits 13-22 so they become mantissa and exponent
|
||||||
|
* of a single-precision floating-point number:
|
||||||
|
*
|
||||||
|
* S|Exponent | Mantissa
|
||||||
|
* +-+---+-----+------------+----------------+
|
||||||
|
* |0|000|EEEEE|MM MMMM MMMM|0 0000 0000 0000|
|
||||||
|
* +-+---+-----+------------+----------------+
|
||||||
|
* Bits | 23-31 | 0-22
|
||||||
|
*
|
||||||
|
* Next, the exponent is adjusted for the difference in exponent bias between single-precision and half-precision
|
||||||
|
* formats (0x7F - 0xF = 0x70). This operation never overflows or generates non-finite values, as the largest
|
||||||
|
* half-precision exponent is 0x1F and after the adjustment is can not exceed 0x8F < 0xFE (largest single-precision
|
||||||
|
* exponent for non-finite values).
|
||||||
|
*
|
||||||
|
* Note that this operation does not handle denormal inputs (where biased exponent == 0). However, they also do not
|
||||||
|
* operate on denormal inputs, and do not produce denormal results.
|
||||||
|
*/
|
||||||
|
const float exp_offset = UINT32_C(0x70) << 23;
|
||||||
|
const float normalized_value = fp32_from_bits((two_w >> 4) + exp_offset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert denormalized half-precision inputs into single-precision results (always normalized).
|
||||||
|
* Zero inputs are also handled here.
|
||||||
|
*
|
||||||
|
* In a denormalized number the biased exponent is zero, and mantissa has on-zero bits.
|
||||||
|
* First, we shift mantissa into bits 0-9 of the 32-bit word.
|
||||||
|
*
|
||||||
|
* zeros | mantissa
|
||||||
|
* +---------------------------+------------+
|
||||||
|
* |0000 0000 0000 0000 0000 00|MM MMMM MMMM|
|
||||||
|
* +---------------------------+------------+
|
||||||
|
* Bits 10-31 0-9
|
||||||
|
*
|
||||||
|
* Now, remember that denormalized half-precision numbers are represented as:
|
||||||
|
* FP16 = mantissa * 2**(-24).
|
||||||
|
* The trick is to construct a normalized single-precision number with the same mantissa and thehalf-precision input
|
||||||
|
* and with an exponent which would scale the corresponding mantissa bits to 2**(-24).
|
||||||
|
* A normalized single-precision floating-point number is represented as:
|
||||||
|
* FP32 = (1 + mantissa * 2**(-23)) * 2**(exponent - 127)
|
||||||
|
* Therefore, when the biased exponent is 126, a unit change in the mantissa of the input denormalized half-precision
|
||||||
|
* number causes a change of the constructud single-precision number by 2**(-24), i.e. the same ammount.
|
||||||
|
*
|
||||||
|
* The last step is to adjust the bias of the constructed single-precision number. When the input half-precision number
|
||||||
|
* is zero, the constructed single-precision number has the value of
|
||||||
|
* FP32 = 1 * 2**(126 - 127) = 2**(-1) = 0.5
|
||||||
|
* Therefore, we need to subtract 0.5 from the constructed single-precision number to get the numerical equivalent of
|
||||||
|
* the input half-precision number.
|
||||||
|
*/
|
||||||
|
const uint32_t magic_mask = UINT32_C(126) << 23;
|
||||||
|
const float magic_bias = 0.5f;
|
||||||
|
const float denormalized_value = fp32_from_bits((two_w >> 17) | magic_mask) - magic_bias;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* - Choose either results of conversion of input as a normalized number, or as a denormalized number, depending on the
|
||||||
|
* input exponent. The variable two_w contains input exponent in bits 27-31, therefore if its smaller than 2**27, the
|
||||||
|
* input is either a denormal number, or zero.
|
||||||
|
* - Combine the result of conversion of exponent and mantissa with the sign of the input number.
|
||||||
|
*/
|
||||||
|
const uint32_t denormalized_cutoff = UINT32_C(1) << 27;
|
||||||
|
const uint32_t result = sign |
|
||||||
|
(two_w < denormalized_cutoff ? fp32_to_bits(denormalized_value) : fp32_to_bits(normalized_value));
|
||||||
|
return fp32_from_bits(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a 32-bit floating-point number in IEEE single-precision format to a 16-bit floating-point number in
|
||||||
|
* ARM alternative half-precision format, in bit representation.
|
||||||
|
*
|
||||||
|
* @note The implementation relies on IEEE-like (no assumption about rounding mode and no operations on denormals)
|
||||||
|
* floating-point operations and bitcasts between integer and floating-point variables.
|
||||||
|
*/
|
||||||
|
static inline uint16_t fp16_alt_from_fp32_value(float f) {
|
||||||
|
const uint32_t w = fp32_to_bits(f);
|
||||||
|
const uint32_t sign = w & UINT32_C(0x80000000);
|
||||||
|
const uint32_t shl1_w = w + w;
|
||||||
|
|
||||||
|
const uint32_t shl1_max_fp16_fp32 = UINT32_C(0x8FFFC000);
|
||||||
|
const uint32_t shl1_base = shl1_w > shl1_max_fp16_fp32 ? shl1_max_fp16_fp32 : shl1_w;
|
||||||
|
uint32_t shl1_bias = shl1_base & UINT32_C(0xFF000000);
|
||||||
|
const uint32_t exp_difference = 23 - 10;
|
||||||
|
const uint32_t shl1_bias_min = (127 - 1 - exp_difference) << 24;
|
||||||
|
if (shl1_bias < shl1_bias_min) {
|
||||||
|
shl1_bias = shl1_bias_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float bias = fp32_from_bits((shl1_bias >> 1) + ((exp_difference + 2) << 23));
|
||||||
|
const float base = fp32_from_bits((shl1_base >> 1) + (2 << 23)) + bias;
|
||||||
|
|
||||||
|
const uint32_t exp_f = fp32_to_bits(base) >> 13;
|
||||||
|
return (sign >> 16) | ((exp_f & UINT32_C(0x00007C00)) + (fp32_to_bits(base) & UINT32_C(0x00000FFF)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FP16_FP16_H */
|
||||||
+69
-21
@@ -1,10 +1,45 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <ruby.h>
|
|
||||||
#include "rgb.h"
|
|
||||||
#include "etc.h"
|
|
||||||
#include "astc.h"
|
#include "astc.h"
|
||||||
#include "dxtc.h"
|
#include "dxtc.h"
|
||||||
|
#include "etc.h"
|
||||||
|
#include "rgb.h"
|
||||||
|
#include <ruby.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode image from A8 binary
|
||||||
|
*
|
||||||
|
* @param [String] rb_data binary to decode
|
||||||
|
* @param [Integer] size width * height
|
||||||
|
* @return [String] decoded rgb binary
|
||||||
|
*/
|
||||||
|
static VALUE rb_decode_a8(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_a8((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
|
||||||
|
*
|
||||||
|
* @param [String] rb_data binary to decode
|
||||||
|
* @param [Integer] size width * height
|
||||||
|
* @param [Boolean] big whether input data are big endian
|
||||||
|
* @return [String] decoded rgb binary
|
||||||
|
*/
|
||||||
|
static VALUE rb_decode_r16(VALUE self, VALUE rb_data, VALUE size, VALUE big)
|
||||||
|
{
|
||||||
|
if (RSTRING_LEN(rb_data) < FIX2LONG(size) * 2)
|
||||||
|
rb_raise(rb_eStandardError, "Data size is not enough.");
|
||||||
|
VALUE ret = rb_str_buf_new(FIX2LONG(size) * 3);
|
||||||
|
decode_r16((uint16_t*)RSTRING_PTR(rb_data), FIX2INT(size), RTEST(big), (uint8_t*)RSTRING_PTR(ret));
|
||||||
|
rb_str_set_len(ret, FIX2LONG(size) * 3);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode image from RGB565 binary
|
* Decode image from RGB565 binary
|
||||||
@@ -12,15 +47,15 @@
|
|||||||
* @param [String] rb_data binary to decode
|
* @param [String] rb_data binary to decode
|
||||||
* @param [Integer] size width * height
|
* @param [Integer] size width * height
|
||||||
* @param [Boolean] big whether input data are big endian
|
* @param [Boolean] big whether input data are big endian
|
||||||
* @return [String] decoded rgba binary
|
* @return [String] decoded rgb binary
|
||||||
*/
|
*/
|
||||||
static VALUE rb_decode_rgb565(VALUE self, VALUE rb_data, VALUE size, VALUE big) {
|
static VALUE rb_decode_rgb565(VALUE self, VALUE rb_data, VALUE size, VALUE big)
|
||||||
|
{
|
||||||
if (RSTRING_LEN(rb_data) < FIX2LONG(size) * 2)
|
if (RSTRING_LEN(rb_data) < FIX2LONG(size) * 2)
|
||||||
rb_raise(rb_eStandardError, "Data size is not enough.");
|
rb_raise(rb_eStandardError, "Data size is not enough.");
|
||||||
uint8_t *image = (uint8_t*)malloc(FIX2LONG(size) * 4);
|
VALUE ret = rb_str_buf_new(FIX2LONG(size) * 3);
|
||||||
decode_rgb565((uint16_t*)RSTRING_PTR(rb_data), FIX2INT(size), RTEST(big), image);
|
decode_rgb565((uint16_t*)RSTRING_PTR(rb_data), FIX2INT(size), RTEST(big), (uint8_t*)RSTRING_PTR(ret));
|
||||||
VALUE ret = rb_str_new((char*)image, FIX2LONG(size) * 4);
|
rb_str_set_len(ret, FIX2LONG(size) * 3);
|
||||||
free(image);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +67,8 @@ static VALUE rb_decode_rgb565(VALUE self, VALUE rb_data, VALUE size, VALUE big)
|
|||||||
* @param [Integer] h image height
|
* @param [Integer] h image height
|
||||||
* @return [String] decoded rgba binary
|
* @return [String] decoded rgba binary
|
||||||
*/
|
*/
|
||||||
static VALUE rb_decode_etc1(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
static VALUE rb_decode_etc1(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));
|
||||||
@@ -50,7 +86,8 @@ static VALUE rb_decode_etc1(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
|||||||
* @param [Integer] h image height
|
* @param [Integer] h image height
|
||||||
* @return [String] decoded rgba binary
|
* @return [String] decoded rgba binary
|
||||||
*/
|
*/
|
||||||
static VALUE rb_decode_etc2(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
static VALUE rb_decode_etc2(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));
|
||||||
@@ -68,11 +105,13 @@ static VALUE rb_decode_etc2(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
|||||||
* @param [Integer] h image height
|
* @param [Integer] h image height
|
||||||
* @return [String] decoded rgba binary
|
* @return [String] decoded rgba binary
|
||||||
*/
|
*/
|
||||||
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) * 9)
|
||||||
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), image);
|
decode_etc2a8((uint64_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;
|
||||||
@@ -86,11 +125,13 @@ static VALUE rb_decode_etc2a1(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
|||||||
* @param [Integer] h image height
|
* @param [Integer] h image height
|
||||||
* @return [String] decoded rgba binary
|
* @return [String] decoded rgba binary
|
||||||
*/
|
*/
|
||||||
static VALUE rb_decode_etc2a8(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
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), image);
|
decode_etc2a8((uint64_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;
|
||||||
@@ -106,7 +147,9 @@ static VALUE rb_decode_etc2a8(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
|||||||
* @param [Integer] bh block height
|
* @param [Integer] bh block height
|
||||||
* @return [String] decoded rgba binary
|
* @return [String] decoded rgba binary
|
||||||
*/
|
*/
|
||||||
static VALUE rb_decode_astc(VALUE self, VALUE rb_data, VALUE w, VALUE h, VALUE bw, VALUE bh) {
|
static VALUE rb_decode_astc(VALUE self, VALUE rb_data, VALUE w, VALUE h,
|
||||||
|
VALUE bw, VALUE bh)
|
||||||
|
{
|
||||||
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);
|
const uint8_t* data = (uint8_t*)RSTRING_PTR(rb_data);
|
||||||
@@ -125,7 +168,8 @@ static VALUE rb_decode_astc(VALUE self, VALUE rb_data, VALUE w, VALUE h, VALUE b
|
|||||||
* @param [Integer] h image height
|
* @param [Integer] h image height
|
||||||
* @return [String] decoded rgba binary
|
* @return [String] decoded rgba binary
|
||||||
*/
|
*/
|
||||||
static VALUE rb_decode_dxt1(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
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));
|
||||||
@@ -143,7 +187,8 @@ static VALUE rb_decode_dxt1(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
|||||||
* @param [Integer] h image height
|
* @param [Integer] h image height
|
||||||
* @return [String] decoded rgba binary
|
* @return [String] decoded rgba binary
|
||||||
*/
|
*/
|
||||||
static VALUE rb_decode_dxt5(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
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));
|
||||||
@@ -153,9 +198,12 @@ static VALUE rb_decode_dxt5(VALUE self, VALUE rb_data, VALUE w, VALUE h) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init_native() {
|
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_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);
|
||||||
rb_define_module_function(mDecodeHelper, "decode_etc2", rb_decode_etc2, 3);
|
rb_define_module_function(mDecodeHelper, "decode_etc2", rb_decode_etc2, 3);
|
||||||
|
|||||||
+49
-18
@@ -1,26 +1,57 @@
|
|||||||
|
#include "rgb.h"
|
||||||
|
#include "common.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
static inline int is_system_little() {
|
void decode_a8(const uint8_t* data, const int size, uint8_t* image)
|
||||||
int x = 1;
|
{
|
||||||
return *(char*)&x == 1;
|
const uint8_t *d = data, *d_end = data + size;
|
||||||
|
for (int i = 0; d < d_end; d++) {
|
||||||
|
image[i++] = *d;
|
||||||
|
image[i++] = *d;
|
||||||
|
image[i++] = *d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_rgb565(const uint16_t* data, const int size, const int is_big_endian, 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;
|
{
|
||||||
if (is_big_endian == is_system_little()) {
|
const uint16_t *d = data, *d_end = data + size;
|
||||||
uint8_t *p = image;
|
if (IS_LITTLE_ENDIAN == !endian_big) {
|
||||||
for (int i = 0; i < size; i++, d++, p += 4) {
|
// Same endian
|
||||||
uint_fast8_t r = *d & 0x00f8;
|
for (int i = 0; d < d_end; d++) {
|
||||||
uint_fast8_t g = (*d & 0x0007) << 5 | (*d & 0xe000) >> 11;
|
uint8_t c = *d >> 8;
|
||||||
uint_fast8_t b = (*d & 0x1f00) >> 5;
|
image[i++] = c;
|
||||||
p[0] = r | r >> 5;
|
image[i++] = c;
|
||||||
p[1] = g | g >> 6;
|
image[i++] = c;
|
||||||
p[2] = b | b >> 5;
|
|
||||||
p[3] = 255;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32_t *p = (uint32_t*)image;
|
// Different endian
|
||||||
for (int i = 0; i < size; i++, d++, p++)
|
for (int i = 0; d < d_end; d++) {
|
||||||
*p = (*d & 0xf800) >> 8 | *d >> 13 | (*d & 0x7e0) << 5 | (*d & 0x60) << 3 | *d << 19 | (*d & 0x1c) << 14 | 0xff000000;
|
uint8_t c = *d;
|
||||||
|
image[i++] = c;
|
||||||
|
image[i++] = c;
|
||||||
|
image[i++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void decode_rgb565(const uint16_t* data, const int size, const int endian_big, uint8_t* image)
|
||||||
|
{
|
||||||
|
const uint16_t *d = data, *d_end = data + size;
|
||||||
|
if (IS_LITTLE_ENDIAN == !endian_big) {
|
||||||
|
// Same endian
|
||||||
|
// RRRRR GGG | GGG BBBBB
|
||||||
|
for (int i = 0; d < d_end; d++) {
|
||||||
|
image[i++] = (*d >> 8 & 0xf8) | (*d >> 13);
|
||||||
|
image[i++] = (*d >> 3 & 0xfc) | (*d >> 9 & 3);
|
||||||
|
image[i++] = (*d << 3) | (*d >> 2 & 7);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Different endian
|
||||||
|
// GGG BBBBB | RRRRR GGG
|
||||||
|
for (int i = 0; d < d_end; d++) {
|
||||||
|
image[i++] = (*d & 0xf8) | (*d >> 5 & 7);
|
||||||
|
image[i++] = (*d << 5 & 0xe0) | (*d >> 11 & 0x1c) | (*d >> 1 & 3);
|
||||||
|
image[i++] = (*d >> 5 & 0xf8) | (*d >> 10 & 0x7);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void decode_a8(const uint8_t*, 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*);
|
||||||
|
|
||||||
#endif /* end of include guard: RGB_H */
|
#endif /* end of include guard: RGB_H */
|
||||||
|
|||||||
@@ -105,26 +105,19 @@ 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_r8(width, height, bin)
|
decode_a8(width, height, bin)
|
||||||
# when 64 # ETC_RGB4Crunched
|
# when 64 # ETC_RGB4Crunched
|
||||||
# when 65 # ETC2_RGBA8Crunched
|
# when 65 # ETC2_RGBA8Crunched
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Decode image from RGBA4444 binary
|
# Decode image from A8 binary
|
||||||
# @param [Integer] width image width
|
# @param [Integer] width image width
|
||||||
# @param [Integer] height image height
|
# @param [Integer] height image height
|
||||||
# @param [String] bin binary to decode
|
# @param [String] bin binary to decode
|
||||||
# @param [Symbol] endian endianness of binary
|
|
||||||
# @return [ChunkyPNG::Image] decoded image
|
# @return [ChunkyPNG::Image] decoded image
|
||||||
def self.decode_rgba4444(width, height, bin, endian = :big)
|
def self.decode_a8(width, height, bin)
|
||||||
mem = String.new(capacity: width * height * 4)
|
ChunkyPNG::Image.from_rgb_stream(width, height, DecodeHelper.decode_a8(bin, width * height)).flip
|
||||||
(width * height).times do |i|
|
|
||||||
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
|
|
||||||
c = ((c & 0xf000) << 12) | ((c & 0x0f00) << 8) | ((c & 0x00f0) << 4) | (c & 0x000f)
|
|
||||||
BinUtils.append_int32_be!(mem, c << 4 | c)
|
|
||||||
end
|
|
||||||
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Decode image from ARGB4444 binary
|
# Decode image from ARGB4444 binary
|
||||||
@@ -143,52 +136,6 @@ module Mikunyan
|
|||||||
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
|
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
|
||||||
end
|
end
|
||||||
|
|
||||||
# Decode image from RGB565 binary
|
|
||||||
# @param [Integer] width image width
|
|
||||||
# @param [Integer] height image height
|
|
||||||
# @param [String] bin binary to decode
|
|
||||||
# @param [Symbol] endian endianness of binary
|
|
||||||
# @return [ChunkyPNG::Image] decoded image
|
|
||||||
def self.decode_rgb565(width, height, bin, endian = :big)
|
|
||||||
ChunkyPNG::Image.from_rgba_stream(width, height, DecodeHelper.decode_rgb565(bin, width * height, endian == :big)).flip
|
|
||||||
end
|
|
||||||
|
|
||||||
# Decode image from A8 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_a8(width, height, bin)
|
|
||||||
mem = String.new(capacity: width * height * 3)
|
|
||||||
(width * height).times do |i|
|
|
||||||
c = BinUtils.get_int8(bin, i)
|
|
||||||
BinUtils.append_int8!(mem, c, c, c)
|
|
||||||
end
|
|
||||||
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
|
|
||||||
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)
|
|
||||||
decode_a8(width, height, bin)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Decode image from RG16 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_rg16(width, height, bin)
|
|
||||||
mem = String.new(capacity: width * height * 3)
|
|
||||||
(width * height).times do |i|
|
|
||||||
BinUtils.append_int16_int8_be!(mem, BinUtils.get_int16_be(bin, i * 2), 0)
|
|
||||||
end
|
|
||||||
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
|
|
||||||
end
|
|
||||||
|
|
||||||
# Decode image from RGB24 binary
|
# Decode image from RGB24 binary
|
||||||
# @param [Integer] width image width
|
# @param [Integer] width image width
|
||||||
# @param [Integer] height image height
|
# @param [Integer] height image height
|
||||||
@@ -221,6 +168,55 @@ module Mikunyan
|
|||||||
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
|
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Decode image from RGB565 binary
|
||||||
|
# @param [Integer] width image width
|
||||||
|
# @param [Integer] height image height
|
||||||
|
# @param [String] bin binary to decode
|
||||||
|
# @param [Symbol] endian endianness of binary
|
||||||
|
# @return [ChunkyPNG::Image] decoded image
|
||||||
|
def self.decode_rgb565(width, height, bin, endian = :big)
|
||||||
|
ChunkyPNG::Image.from_rgb_stream(width, height, DecodeHelper.decode_rgb565(bin, width * height, endian == :big)).flip
|
||||||
|
end
|
||||||
|
|
||||||
|
# Decode image from R16 binary
|
||||||
|
# @param [Integer] width image width
|
||||||
|
# @param [Integer] height image height
|
||||||
|
# @param [String] bin binary to decode
|
||||||
|
# @param [Symbol] endian endianness of binary
|
||||||
|
# @return [ChunkyPNG::Image] decoded image
|
||||||
|
def self.decode_r16(width, height, bin, endian = :big)
|
||||||
|
ChunkyPNG::Image.from_rgb_stream(width, height, DecodeHelper.decode_r16(bin, width * height, endian == :big)).flip
|
||||||
|
end
|
||||||
|
|
||||||
|
# Decode image from RGBA4444 binary
|
||||||
|
# @param [Integer] width image width
|
||||||
|
# @param [Integer] height image height
|
||||||
|
# @param [String] bin binary to decode
|
||||||
|
# @param [Symbol] endian endianness of binary
|
||||||
|
# @return [ChunkyPNG::Image] decoded image
|
||||||
|
def self.decode_rgba4444(width, height, bin, endian = :big)
|
||||||
|
mem = String.new(capacity: width * height * 4)
|
||||||
|
(width * height).times do |i|
|
||||||
|
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
|
||||||
|
c = ((c & 0xf000) << 12) | ((c & 0x0f00) << 8) | ((c & 0x00f0) << 4) | (c & 0x000f)
|
||||||
|
BinUtils.append_int32_be!(mem, c << 4 | c)
|
||||||
|
end
|
||||||
|
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
|
||||||
|
end
|
||||||
|
|
||||||
|
# Decode image from RG16 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_rg16(width, height, bin)
|
||||||
|
mem = String.new(capacity: width * height * 3)
|
||||||
|
(width * height).times do |i|
|
||||||
|
BinUtils.append_int16_int8_be!(mem, BinUtils.get_int16_be(bin, i * 2), 0)
|
||||||
|
end
|
||||||
|
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
|
||||||
|
end
|
||||||
|
|
||||||
# Decode image from BGRA32 binary
|
# Decode image from BGRA32 binary
|
||||||
# @param [Integer] width image width
|
# @param [Integer] width image width
|
||||||
# @param [Integer] height image height
|
# @param [Integer] height image height
|
||||||
@@ -235,22 +231,6 @@ module Mikunyan
|
|||||||
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
|
ChunkyPNG::Image.from_rgba_stream(width, height, mem).flip
|
||||||
end
|
end
|
||||||
|
|
||||||
# Decode image from R16 binary
|
|
||||||
# @param [Integer] width image width
|
|
||||||
# @param [Integer] height image height
|
|
||||||
# @param [String] bin binary to decode
|
|
||||||
# @param [Symbol] endian endianness of binary
|
|
||||||
# @return [ChunkyPNG::Image] decoded image
|
|
||||||
def self.decode_r16(width, height, bin, endian = :big)
|
|
||||||
mem = String.new(capacity: width * height * 3)
|
|
||||||
(width * height).times do |i|
|
|
||||||
c = endian == :little ? BinUtils.get_int16_le(bin, i * 2) : BinUtils.get_int16_be(bin, i * 2)
|
|
||||||
c = f2i(r / 65535.0)
|
|
||||||
BinUtils.append_int8!(mem, c, c, c)
|
|
||||||
end
|
|
||||||
ChunkyPNG::Image.from_rgb_stream(width, height, mem).flip
|
|
||||||
end
|
|
||||||
|
|
||||||
# Decode image from RGB9e5 binary
|
# Decode image from RGB9e5 binary
|
||||||
# @param [Integer] width image width
|
# @param [Integer] width image width
|
||||||
# @param [Integer] height image height
|
# @param [Integer] height image height
|
||||||
|
|||||||
Reference in New Issue
Block a user