| // basisu_transcoder.cpp |
| // Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "basisu_transcoder.h" |
| #include <limits.h> |
| #include "basisu_containers_impl.h" |
| |
| #ifndef BASISD_IS_BIG_ENDIAN |
| // TODO: This doesn't work on OSX. How can this be so difficult? |
| //#if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) || defined(BIG_ENDIAN) |
| // #define BASISD_IS_BIG_ENDIAN (1) |
| //#else |
| #define BASISD_IS_BIG_ENDIAN (0) |
| //#endif |
| #endif |
| |
| #ifndef BASISD_USE_UNALIGNED_WORD_READS |
| #ifdef __EMSCRIPTEN__ |
| // Can't use unaligned loads/stores with WebAssembly. |
| #define BASISD_USE_UNALIGNED_WORD_READS (0) |
| #elif defined(_M_AMD64) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__) |
| #define BASISD_USE_UNALIGNED_WORD_READS (1) |
| #else |
| #define BASISD_USE_UNALIGNED_WORD_READS (0) |
| #endif |
| #endif |
| |
| #define BASISD_SUPPORTED_BASIS_VERSION (0x13) |
| |
| #ifndef BASISD_SUPPORT_KTX2 |
| #error Must have defined BASISD_SUPPORT_KTX2 |
| #endif |
| |
| #ifndef BASISD_SUPPORT_KTX2_ZSTD |
| #error Must have defined BASISD_SUPPORT_KTX2_ZSTD |
| #endif |
| |
| // Set to 1 for fuzz testing. This will disable all CRC16 checks on headers and compressed data. |
| #ifndef BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS |
| #define BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS 0 |
| #endif |
| |
| #ifndef BASISD_SUPPORT_DXT1 |
| #define BASISD_SUPPORT_DXT1 1 |
| #endif |
| |
| #ifndef BASISD_SUPPORT_DXT5A |
| #define BASISD_SUPPORT_DXT5A 1 |
| #endif |
| |
| // Disable all BC7 transcoders if necessary (useful when cross compiling to Javascript) |
| #if defined(BASISD_SUPPORT_BC7) && !BASISD_SUPPORT_BC7 |
| #ifndef BASISD_SUPPORT_BC7_MODE5 |
| #define BASISD_SUPPORT_BC7_MODE5 0 |
| #endif |
| #endif // !BASISD_SUPPORT_BC7 |
| |
| // BC7 mode 5 supports both opaque and opaque+alpha textures, and uses less memory BC1. |
| #ifndef BASISD_SUPPORT_BC7_MODE5 |
| #define BASISD_SUPPORT_BC7_MODE5 1 |
| #endif |
| |
| #ifndef BASISD_SUPPORT_PVRTC1 |
| #define BASISD_SUPPORT_PVRTC1 1 |
| #endif |
| |
| #ifndef BASISD_SUPPORT_ETC2_EAC_A8 |
| #define BASISD_SUPPORT_ETC2_EAC_A8 1 |
| #endif |
| |
| // Set BASISD_SUPPORT_UASTC to 0 to completely disable support for transcoding UASTC files. |
| #ifndef BASISD_SUPPORT_UASTC |
| #define BASISD_SUPPORT_UASTC 1 |
| #endif |
| |
| #ifndef BASISD_SUPPORT_ASTC |
| #define BASISD_SUPPORT_ASTC 1 |
| #endif |
| |
| // Note that if BASISD_SUPPORT_ATC is enabled, BASISD_SUPPORT_DXT5A should also be enabled for alpha support. |
| #ifndef BASISD_SUPPORT_ATC |
| #define BASISD_SUPPORT_ATC 1 |
| #endif |
| |
| // Support for ETC2 EAC R11 and ETC2 EAC RG11 |
| #ifndef BASISD_SUPPORT_ETC2_EAC_RG11 |
| #define BASISD_SUPPORT_ETC2_EAC_RG11 1 |
| #endif |
| |
| // If BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY is 1, opaque blocks will be transcoded to ASTC at slightly higher quality (higher than BC1), but the transcoder tables will be 2x as large. |
| // This impacts grayscale and grayscale+alpha textures the most. |
| #ifndef BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY |
| #ifdef __EMSCRIPTEN__ |
| // Let's assume size matters more than quality when compiling with emscripten. |
| #define BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY 0 |
| #else |
| // Compiling native, so an extra 64K lookup table is probably acceptable. |
| #define BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY 1 |
| #endif |
| #endif |
| |
| #ifndef BASISD_SUPPORT_FXT1 |
| #define BASISD_SUPPORT_FXT1 1 |
| #endif |
| |
| #ifndef BASISD_SUPPORT_PVRTC2 |
| #define BASISD_SUPPORT_PVRTC2 1 |
| #endif |
| |
| #if BASISD_SUPPORT_PVRTC2 |
| #if !BASISD_SUPPORT_ATC |
| #error BASISD_SUPPORT_ATC must be 1 if BASISD_SUPPORT_PVRTC2 is 1 |
| #endif |
| #endif |
| |
| #if BASISD_SUPPORT_ATC |
| #if !BASISD_SUPPORT_DXT5A |
| #error BASISD_SUPPORT_DXT5A must be 1 if BASISD_SUPPORT_ATC is 1 |
| #endif |
| #endif |
| |
| #define BASISD_WRITE_NEW_BC7_MODE5_TABLES 0 |
| #define BASISD_WRITE_NEW_DXT1_TABLES 0 |
| #define BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES 0 |
| #define BASISD_WRITE_NEW_ASTC_TABLES 0 |
| #define BASISD_WRITE_NEW_ATC_TABLES 0 |
| #define BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES 0 |
| |
| #ifndef BASISD_ENABLE_DEBUG_FLAGS |
| #define BASISD_ENABLE_DEBUG_FLAGS 0 |
| #endif |
| |
| // If KTX2 support is enabled, we may need Zstd for decompression of supercompressed UASTC files. Include this header. |
| #if BASISD_SUPPORT_KTX2 |
| // If BASISD_SUPPORT_KTX2_ZSTD is 0, UASTC files compressed with Zstd cannot be loaded. |
| #if BASISD_SUPPORT_KTX2_ZSTD |
| // We only use two Zstd API's: ZSTD_decompress() and ZSTD_isError() |
| #include "../zstd/zstd.h" |
| #endif |
| #endif |
| |
| namespace basisu |
| { |
| bool g_debug_printf; |
| |
| void enable_debug_printf(bool enabled) |
| { |
| g_debug_printf = enabled; |
| } |
| |
| void debug_printf(const char* pFmt, ...) |
| { |
| #if BASISU_FORCE_DEVEL_MESSAGES |
| g_debug_printf = true; |
| #endif |
| if (g_debug_printf) |
| { |
| va_list args; |
| va_start(args, pFmt); |
| vprintf(pFmt, args); |
| va_end(args); |
| } |
| } |
| } // namespace basisu |
| |
| namespace basist |
| { |
| |
| #if BASISD_ENABLE_DEBUG_FLAGS |
| static uint32_t g_debug_flags = 0; |
| #endif |
| |
| uint32_t get_debug_flags() |
| { |
| #if BASISD_ENABLE_DEBUG_FLAGS |
| return g_debug_flags; |
| #else |
| return 0; |
| #endif |
| } |
| |
| void set_debug_flags(uint32_t f) |
| { |
| BASISU_NOTE_UNUSED(f); |
| #if BASISD_ENABLE_DEBUG_FLAGS |
| g_debug_flags = f; |
| #endif |
| } |
| |
| inline uint16_t byteswap_uint16(uint16_t v) |
| { |
| return static_cast<uint16_t>((v >> 8) | (v << 8)); |
| } |
| |
| static inline int32_t clampi(int32_t value, int32_t low, int32_t high) { if (value < low) value = low; else if (value > high) value = high; return value; } |
| static inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; } |
| static inline float saturate(float value) { return clampf(value, 0, 1.0f); } |
| |
| static inline uint8_t mul_8(uint32_t v, uint32_t q) { v = v * q + 128; return (uint8_t)((v + (v >> 8)) >> 8); } |
| |
| uint16_t crc16(const void* r, size_t size, uint16_t crc) |
| { |
| crc = ~crc; |
| |
| const uint8_t* p = static_cast<const uint8_t*>(r); |
| for (; size; --size) |
| { |
| const uint16_t q = *p++ ^ (crc >> 8); |
| uint16_t k = (q >> 4) ^ q; |
| crc = (((crc << 8) ^ k) ^ (k << 5)) ^ (k << 12); |
| } |
| |
| return static_cast<uint16_t>(~crc); |
| } |
| |
| enum etc_constants |
| { |
| cETC1BytesPerBlock = 8U, |
| |
| cETC1SelectorBits = 2U, |
| cETC1SelectorValues = 1U << cETC1SelectorBits, |
| cETC1SelectorMask = cETC1SelectorValues - 1U, |
| |
| cETC1BlockShift = 2U, |
| cETC1BlockSize = 1U << cETC1BlockShift, |
| |
| cETC1LSBSelectorIndicesBitOffset = 0, |
| cETC1MSBSelectorIndicesBitOffset = 16, |
| |
| cETC1FlipBitOffset = 32, |
| cETC1DiffBitOffset = 33, |
| |
| cETC1IntenModifierNumBits = 3, |
| cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits, |
| cETC1RightIntenModifierTableBitOffset = 34, |
| cETC1LeftIntenModifierTableBitOffset = 37, |
| |
| // Base+Delta encoding (5 bit bases, 3 bit delta) |
| cETC1BaseColorCompNumBits = 5, |
| cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits, |
| |
| cETC1DeltaColorCompNumBits = 3, |
| cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits, |
| cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits, |
| |
| cETC1BaseColor5RBitOffset = 59, |
| cETC1BaseColor5GBitOffset = 51, |
| cETC1BaseColor5BBitOffset = 43, |
| |
| cETC1DeltaColor3RBitOffset = 56, |
| cETC1DeltaColor3GBitOffset = 48, |
| cETC1DeltaColor3BBitOffset = 40, |
| |
| // Absolute (non-delta) encoding (two 4-bit per component bases) |
| cETC1AbsColorCompNumBits = 4, |
| cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits, |
| |
| cETC1AbsColor4R1BitOffset = 60, |
| cETC1AbsColor4G1BitOffset = 52, |
| cETC1AbsColor4B1BitOffset = 44, |
| |
| cETC1AbsColor4R2BitOffset = 56, |
| cETC1AbsColor4G2BitOffset = 48, |
| cETC1AbsColor4B2BitOffset = 40, |
| |
| cETC1ColorDeltaMin = -4, |
| cETC1ColorDeltaMax = 3, |
| |
| // Delta3: |
| // 0 1 2 3 4 5 6 7 |
| // 000 001 010 011 100 101 110 111 |
| // 0 1 2 3 -4 -3 -2 -1 |
| }; |
| |
| #define DECLARE_ETC1_INTEN_TABLE(name, N) \ |
| static const int name[cETC1IntenModifierValues][cETC1SelectorValues] = \ |
| { \ |
| { N * -8, N * -2, N * 2, N * 8 },{ N * -17, N * -5, N * 5, N * 17 },{ N * -29, N * -9, N * 9, N * 29 },{ N * -42, N * -13, N * 13, N * 42 }, \ |
| { N * -60, N * -18, N * 18, N * 60 },{ N * -80, N * -24, N * 24, N * 80 },{ N * -106, N * -33, N * 33, N * 106 },{ N * -183, N * -47, N * 47, N * 183 } \ |
| }; |
| |
| DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables, 1); |
| DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables16, 16); |
| DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables48, 3 * 16); |
| |
| //const uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 }; |
| const uint8_t g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 }; |
| |
| static const uint8_t g_etc_5_to_8[32] = { 0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255 }; |
| |
| struct decoder_etc_block |
| { |
| // big endian uint64: |
| // bit ofs: 56 48 40 32 24 16 8 0 |
| // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7 |
| union |
| { |
| uint64_t m_uint64; |
| |
| uint32_t m_uint32[2]; |
| |
| uint8_t m_bytes[8]; |
| |
| struct |
| { |
| signed m_dred2 : 3; |
| uint32_t m_red1 : 5; |
| |
| signed m_dgreen2 : 3; |
| uint32_t m_green1 : 5; |
| |
| signed m_dblue2 : 3; |
| uint32_t m_blue1 : 5; |
| |
| uint32_t m_flip : 1; |
| uint32_t m_diff : 1; |
| uint32_t m_cw2 : 3; |
| uint32_t m_cw1 : 3; |
| |
| uint32_t m_selectors; |
| } m_differential; |
| }; |
| |
| inline void clear() |
| { |
| assert(sizeof(*this) == 8); |
| basisu::clear_obj(*this); |
| } |
| |
| inline void set_byte_bits(uint32_t ofs, uint32_t num, uint32_t bits) |
| { |
| assert((ofs + num) <= 64U); |
| assert(num && (num < 32U)); |
| assert((ofs >> 3) == ((ofs + num - 1) >> 3)); |
| assert(bits < (1U << num)); |
| const uint32_t byte_ofs = 7 - (ofs >> 3); |
| const uint32_t byte_bit_ofs = ofs & 7; |
| const uint32_t mask = (1 << num) - 1; |
| m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs); |
| m_bytes[byte_ofs] |= (bits << byte_bit_ofs); |
| } |
| |
| inline void set_flip_bit(bool flip) |
| { |
| m_bytes[3] &= ~1; |
| m_bytes[3] |= static_cast<uint8_t>(flip); |
| } |
| |
| inline void set_diff_bit(bool diff) |
| { |
| m_bytes[3] &= ~2; |
| m_bytes[3] |= (static_cast<uint32_t>(diff) << 1); |
| } |
| |
| // Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1) |
| inline void set_inten_table(uint32_t subblock_id, uint32_t t) |
| { |
| assert(subblock_id < 2); |
| assert(t < 8); |
| const uint32_t ofs = subblock_id ? 2 : 5; |
| m_bytes[3] &= ~(7 << ofs); |
| m_bytes[3] |= (t << ofs); |
| } |
| |
| // Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables. |
| inline void set_selector(uint32_t x, uint32_t y, uint32_t val) |
| { |
| assert((x | y | val) < 4); |
| const uint32_t bit_index = x * 4 + y; |
| |
| uint8_t* p = &m_bytes[7 - (bit_index >> 3)]; |
| |
| const uint32_t byte_bit_ofs = bit_index & 7; |
| const uint32_t mask = 1 << byte_bit_ofs; |
| |
| static const uint8_t s_selector_index_to_etc1[4] = { 3, 2, 0, 1 }; |
| const uint32_t etc1_val = s_selector_index_to_etc1[val]; |
| |
| const uint32_t lsb = etc1_val & 1; |
| const uint32_t msb = etc1_val >> 1; |
| |
| p[0] &= ~mask; |
| p[0] |= (lsb << byte_bit_ofs); |
| |
| p[-2] &= ~mask; |
| p[-2] |= (msb << byte_bit_ofs); |
| } |
| |
| // Returned encoded selector value ranges from 0-3 (this is NOT a direct index into g_etc1_inten_tables, see get_selector()) |
| inline uint32_t get_raw_selector(uint32_t x, uint32_t y) const |
| { |
| assert((x | y) < 4); |
| |
| const uint32_t bit_index = x * 4 + y; |
| const uint32_t byte_bit_ofs = bit_index & 7; |
| const uint8_t* p = &m_bytes[7 - (bit_index >> 3)]; |
| const uint32_t lsb = (p[0] >> byte_bit_ofs) & 1; |
| const uint32_t msb = (p[-2] >> byte_bit_ofs) & 1; |
| const uint32_t val = lsb | (msb << 1); |
| |
| return val; |
| } |
| |
| // Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables. |
| inline uint32_t get_selector(uint32_t x, uint32_t y) const |
| { |
| static const uint8_t s_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 }; |
| return s_etc1_to_selector_index[get_raw_selector(x, y)]; |
| } |
| |
| inline void set_raw_selector_bits(uint32_t bits) |
| { |
| m_bytes[4] = static_cast<uint8_t>(bits); |
| m_bytes[5] = static_cast<uint8_t>(bits >> 8); |
| m_bytes[6] = static_cast<uint8_t>(bits >> 16); |
| m_bytes[7] = static_cast<uint8_t>(bits >> 24); |
| } |
| |
| inline bool are_all_selectors_the_same() const |
| { |
| uint32_t v = *reinterpret_cast<const uint32_t*>(&m_bytes[4]); |
| |
| if ((v == 0xFFFFFFFF) || (v == 0xFFFF) || (!v) || (v == 0xFFFF0000)) |
| return true; |
| |
| return false; |
| } |
| |
| inline void set_raw_selector_bits(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) |
| { |
| m_bytes[4] = byte0; |
| m_bytes[5] = byte1; |
| m_bytes[6] = byte2; |
| m_bytes[7] = byte3; |
| } |
| |
| inline uint32_t get_raw_selector_bits() const |
| { |
| return m_bytes[4] | (m_bytes[5] << 8) | (m_bytes[6] << 16) | (m_bytes[7] << 24); |
| } |
| |
| inline void set_base4_color(uint32_t idx, uint16_t c) |
| { |
| if (idx) |
| { |
| set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15); |
| set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15); |
| set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15); |
| } |
| else |
| { |
| set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15); |
| set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15); |
| set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15); |
| } |
| } |
| |
| inline void set_base5_color(uint16_t c) |
| { |
| set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31); |
| set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31); |
| set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31); |
| } |
| |
| void set_delta3_color(uint16_t c) |
| { |
| set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7); |
| set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7); |
| set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7); |
| } |
| |
| void set_block_color4(const color32& c0_unscaled, const color32& c1_unscaled) |
| { |
| set_diff_bit(false); |
| |
| set_base4_color(0, pack_color4(c0_unscaled, false)); |
| set_base4_color(1, pack_color4(c1_unscaled, false)); |
| } |
| |
| void set_block_color5(const color32& c0_unscaled, const color32& c1_unscaled) |
| { |
| set_diff_bit(true); |
| |
| set_base5_color(pack_color5(c0_unscaled, false)); |
| |
| int dr = c1_unscaled.r - c0_unscaled.r; |
| int dg = c1_unscaled.g - c0_unscaled.g; |
| int db = c1_unscaled.b - c0_unscaled.b; |
| |
| set_delta3_color(pack_delta3(dr, dg, db)); |
| } |
| |
| bool set_block_color5_check(const color32& c0_unscaled, const color32& c1_unscaled) |
| { |
| set_diff_bit(true); |
| |
| set_base5_color(pack_color5(c0_unscaled, false)); |
| |
| int dr = c1_unscaled.r - c0_unscaled.r; |
| int dg = c1_unscaled.g - c0_unscaled.g; |
| int db = c1_unscaled.b - c0_unscaled.b; |
| |
| if (((dr < cETC1ColorDeltaMin) || (dr > cETC1ColorDeltaMax)) || |
| ((dg < cETC1ColorDeltaMin) || (dg > cETC1ColorDeltaMax)) || |
| ((db < cETC1ColorDeltaMin) || (db > cETC1ColorDeltaMax))) |
| return false; |
| |
| set_delta3_color(pack_delta3(dr, dg, db)); |
| |
| return true; |
| } |
| |
| inline uint32_t get_byte_bits(uint32_t ofs, uint32_t num) const |
| { |
| assert((ofs + num) <= 64U); |
| assert(num && (num <= 8U)); |
| assert((ofs >> 3) == ((ofs + num - 1) >> 3)); |
| const uint32_t byte_ofs = 7 - (ofs >> 3); |
| const uint32_t byte_bit_ofs = ofs & 7; |
| return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1); |
| } |
| |
| inline uint16_t get_base5_color() const |
| { |
| const uint32_t r = get_byte_bits(cETC1BaseColor5RBitOffset, 5); |
| const uint32_t g = get_byte_bits(cETC1BaseColor5GBitOffset, 5); |
| const uint32_t b = get_byte_bits(cETC1BaseColor5BBitOffset, 5); |
| return static_cast<uint16_t>(b | (g << 5U) | (r << 10U)); |
| } |
| |
| inline uint16_t get_base4_color(uint32_t idx) const |
| { |
| uint32_t r, g, b; |
| if (idx) |
| { |
| r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4); |
| g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4); |
| b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4); |
| } |
| else |
| { |
| r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4); |
| g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4); |
| b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4); |
| } |
| return static_cast<uint16_t>(b | (g << 4U) | (r << 8U)); |
| } |
| |
| inline color32 get_base5_color_unscaled() const |
| { |
| return color32(m_differential.m_red1, m_differential.m_green1, m_differential.m_blue1, 255); |
| } |
| |
| inline bool get_flip_bit() const |
| { |
| return (m_bytes[3] & 1) != 0; |
| } |
| |
| inline bool get_diff_bit() const |
| { |
| return (m_bytes[3] & 2) != 0; |
| } |
| |
| inline uint32_t get_inten_table(uint32_t subblock_id) const |
| { |
| assert(subblock_id < 2); |
| const uint32_t ofs = subblock_id ? 2 : 5; |
| return (m_bytes[3] >> ofs) & 7; |
| } |
| |
| inline uint16_t get_delta3_color() const |
| { |
| const uint32_t r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3); |
| const uint32_t g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3); |
| const uint32_t b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3); |
| return static_cast<uint16_t>(b | (g << 3U) | (r << 6U)); |
| } |
| |
| void get_block_colors(color32* pBlock_colors, uint32_t subblock_index) const |
| { |
| color32 b; |
| |
| if (get_diff_bit()) |
| { |
| if (subblock_index) |
| unpack_color5(b, get_base5_color(), get_delta3_color(), true, 255); |
| else |
| unpack_color5(b, get_base5_color(), true); |
| } |
| else |
| { |
| b = unpack_color4(get_base4_color(subblock_index), true, 255); |
| } |
| |
| const int* pInten_table = g_etc1_inten_tables[get_inten_table(subblock_index)]; |
| |
| pBlock_colors[0].set_noclamp_rgba(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255); |
| pBlock_colors[1].set_noclamp_rgba(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255); |
| pBlock_colors[2].set_noclamp_rgba(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255); |
| pBlock_colors[3].set_noclamp_rgba(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255); |
| } |
| |
| static uint16_t pack_color4(const color32& color, bool scaled, uint32_t bias = 127U) |
| { |
| return pack_color4(color.r, color.g, color.b, scaled, bias); |
| } |
| |
| static uint16_t pack_color4(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias = 127U) |
| { |
| if (scaled) |
| { |
| r = (r * 15U + bias) / 255U; |
| g = (g * 15U + bias) / 255U; |
| b = (b * 15U + bias) / 255U; |
| } |
| |
| r = basisu::minimum(r, 15U); |
| g = basisu::minimum(g, 15U); |
| b = basisu::minimum(b, 15U); |
| |
| return static_cast<uint16_t>(b | (g << 4U) | (r << 8U)); |
| } |
| |
| static uint16_t pack_color5(const color32& color, bool scaled, uint32_t bias = 127U) |
| { |
| return pack_color5(color.r, color.g, color.b, scaled, bias); |
| } |
| |
| static uint16_t pack_color5(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias = 127U) |
| { |
| if (scaled) |
| { |
| r = (r * 31U + bias) / 255U; |
| g = (g * 31U + bias) / 255U; |
| b = (b * 31U + bias) / 255U; |
| } |
| |
| r = basisu::minimum(r, 31U); |
| g = basisu::minimum(g, 31U); |
| b = basisu::minimum(b, 31U); |
| |
| return static_cast<uint16_t>(b | (g << 5U) | (r << 10U)); |
| } |
| |
| uint16_t pack_delta3(const color32& color) |
| { |
| return pack_delta3(color.r, color.g, color.b); |
| } |
| |
| uint16_t pack_delta3(int r, int g, int b) |
| { |
| assert((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax)); |
| assert((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax)); |
| assert((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax)); |
| if (r < 0) r += 8; |
| if (g < 0) g += 8; |
| if (b < 0) b += 8; |
| return static_cast<uint16_t>(b | (g << 3) | (r << 6)); |
| } |
| |
| static void unpack_delta3(int& r, int& g, int& b, uint16_t packed_delta3) |
| { |
| r = (packed_delta3 >> 6) & 7; |
| g = (packed_delta3 >> 3) & 7; |
| b = packed_delta3 & 7; |
| if (r >= 4) r -= 8; |
| if (g >= 4) g -= 8; |
| if (b >= 4) b -= 8; |
| } |
| |
| static color32 unpack_color5(uint16_t packed_color5, bool scaled, uint32_t alpha) |
| { |
| uint32_t b = packed_color5 & 31U; |
| uint32_t g = (packed_color5 >> 5U) & 31U; |
| uint32_t r = (packed_color5 >> 10U) & 31U; |
| |
| if (scaled) |
| { |
| b = (b << 3U) | (b >> 2U); |
| g = (g << 3U) | (g >> 2U); |
| r = (r << 3U) | (r >> 2U); |
| } |
| |
| assert(alpha <= 255); |
| |
| return color32(cNoClamp, r, g, b, alpha); |
| } |
| |
| static void unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color5, bool scaled) |
| { |
| color32 c(unpack_color5(packed_color5, scaled, 0)); |
| r = c.r; |
| g = c.g; |
| b = c.b; |
| } |
| |
| static void unpack_color5(color32& result, uint16_t packed_color5, bool scaled) |
| { |
| result = unpack_color5(packed_color5, scaled, 255); |
| } |
| |
| static bool unpack_color5(color32& result, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha) |
| { |
| int dr, dg, db; |
| unpack_delta3(dr, dg, db, packed_delta3); |
| |
| int r = ((packed_color5 >> 10U) & 31U) + dr; |
| int g = ((packed_color5 >> 5U) & 31U) + dg; |
| int b = (packed_color5 & 31U) + db; |
| |
| bool success = true; |
| if (static_cast<uint32_t>(r | g | b) > 31U) |
| { |
| success = false; |
| r = basisu::clamp<int>(r, 0, 31); |
| g = basisu::clamp<int>(g, 0, 31); |
| b = basisu::clamp<int>(b, 0, 31); |
| } |
| |
| if (scaled) |
| { |
| b = (b << 3U) | (b >> 2U); |
| g = (g << 3U) | (g >> 2U); |
| r = (r << 3U) | (r >> 2U); |
| } |
| |
| result.set_noclamp_rgba(r, g, b, basisu::minimum(alpha, 255U)); |
| return success; |
| } |
| |
| static color32 unpack_color4(uint16_t packed_color4, bool scaled, uint32_t alpha) |
| { |
| uint32_t b = packed_color4 & 15U; |
| uint32_t g = (packed_color4 >> 4U) & 15U; |
| uint32_t r = (packed_color4 >> 8U) & 15U; |
| |
| if (scaled) |
| { |
| b = (b << 4U) | b; |
| g = (g << 4U) | g; |
| r = (r << 4U) | r; |
| } |
| |
| return color32(cNoClamp, r, g, b, basisu::minimum(alpha, 255U)); |
| } |
| |
| static void unpack_color4(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color4, bool scaled) |
| { |
| color32 c(unpack_color4(packed_color4, scaled, 0)); |
| r = c.r; |
| g = c.g; |
| b = c.b; |
| } |
| |
| static void get_diff_subblock_colors(color32* pDst, uint16_t packed_color5, uint32_t table_idx) |
| { |
| assert(table_idx < cETC1IntenModifierValues); |
| const int* pInten_modifer_table = &g_etc1_inten_tables[table_idx][0]; |
| |
| uint32_t r, g, b; |
| unpack_color5(r, g, b, packed_color5, true); |
| |
| const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b); |
| |
| const int y0 = pInten_modifer_table[0]; |
| pDst[0].set(clamp255(ir + y0), clamp255(ig + y0), clamp255(ib + y0), 255); |
| |
| const int y1 = pInten_modifer_table[1]; |
| pDst[1].set(clamp255(ir + y1), clamp255(ig + y1), clamp255(ib + y1), 255); |
| |
| const int y2 = pInten_modifer_table[2]; |
| pDst[2].set(clamp255(ir + y2), clamp255(ig + y2), clamp255(ib + y2), 255); |
| |
| const int y3 = pInten_modifer_table[3]; |
| pDst[3].set(clamp255(ir + y3), clamp255(ig + y3), clamp255(ib + y3), 255); |
| } |
| |
| static int clamp255(int x) |
| { |
| if (x & 0xFFFFFF00) |
| { |
| if (x < 0) |
| x = 0; |
| else if (x > 255) |
| x = 255; |
| } |
| |
| return x; |
| } |
| |
| static void get_block_colors5(color32* pBlock_colors, const color32& base_color5, uint32_t inten_table) |
| { |
| color32 b(base_color5); |
| |
| b.r = (b.r << 3) | (b.r >> 2); |
| b.g = (b.g << 3) | (b.g >> 2); |
| b.b = (b.b << 3) | (b.b >> 2); |
| |
| const int* pInten_table = g_etc1_inten_tables[inten_table]; |
| |
| pBlock_colors[0].set(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255); |
| pBlock_colors[1].set(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255); |
| pBlock_colors[2].set(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255); |
| pBlock_colors[3].set(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255); |
| } |
| |
| static void get_block_color5(const color32& base_color5, uint32_t inten_table, uint32_t index, uint32_t& r, uint32_t &g, uint32_t &b) |
| { |
| assert(index < 4); |
| |
| uint32_t br = (base_color5.r << 3) | (base_color5.r >> 2); |
| uint32_t bg = (base_color5.g << 3) | (base_color5.g >> 2); |
| uint32_t bb = (base_color5.b << 3) | (base_color5.b >> 2); |
| |
| const int* pInten_table = g_etc1_inten_tables[inten_table]; |
| |
| r = clamp255(br + pInten_table[index]); |
| g = clamp255(bg + pInten_table[index]); |
| b = clamp255(bb + pInten_table[index]); |
| } |
| |
| static void get_block_color5_r(const color32& base_color5, uint32_t inten_table, uint32_t index, uint32_t &r) |
| { |
| assert(index < 4); |
| |
| uint32_t br = (base_color5.r << 3) | (base_color5.r >> 2); |
| |
| const int* pInten_table = g_etc1_inten_tables[inten_table]; |
| |
| r = clamp255(br + pInten_table[index]); |
| } |
| |
| static void get_block_colors5_g(int* pBlock_colors, const color32& base_color5, uint32_t inten_table) |
| { |
| const int g = (base_color5.g << 3) | (base_color5.g >> 2); |
| |
| const int* pInten_table = g_etc1_inten_tables[inten_table]; |
| |
| pBlock_colors[0] = clamp255(g + pInten_table[0]); |
| pBlock_colors[1] = clamp255(g + pInten_table[1]); |
| pBlock_colors[2] = clamp255(g + pInten_table[2]); |
| pBlock_colors[3] = clamp255(g + pInten_table[3]); |
| } |
| |
| static void get_block_colors5_bounds(color32* pBlock_colors, const color32& base_color5, uint32_t inten_table, uint32_t l = 0, uint32_t h = 3) |
| { |
| color32 b(base_color5); |
| |
| b.r = (b.r << 3) | (b.r >> 2); |
| b.g = (b.g << 3) | (b.g >> 2); |
| b.b = (b.b << 3) | (b.b >> 2); |
| |
| const int* pInten_table = g_etc1_inten_tables[inten_table]; |
| |
| pBlock_colors[0].set(clamp255(b.r + pInten_table[l]), clamp255(b.g + pInten_table[l]), clamp255(b.b + pInten_table[l]), 255); |
| pBlock_colors[1].set(clamp255(b.r + pInten_table[h]), clamp255(b.g + pInten_table[h]), clamp255(b.b + pInten_table[h]), 255); |
| } |
| |
| static void get_block_colors5_bounds_g(uint32_t* pBlock_colors, const color32& base_color5, uint32_t inten_table, uint32_t l = 0, uint32_t h = 3) |
| { |
| color32 b(base_color5); |
| |
| b.g = (b.g << 3) | (b.g >> 2); |
| |
| const int* pInten_table = g_etc1_inten_tables[inten_table]; |
| |
| pBlock_colors[0] = clamp255(b.g + pInten_table[l]); |
| pBlock_colors[1] = clamp255(b.g + pInten_table[h]); |
| } |
| }; |
| |
| enum dxt_constants |
| { |
| cDXT1SelectorBits = 2U, cDXT1SelectorValues = 1U << cDXT1SelectorBits, cDXT1SelectorMask = cDXT1SelectorValues - 1U, |
| cDXT5SelectorBits = 3U, cDXT5SelectorValues = 1U << cDXT5SelectorBits, cDXT5SelectorMask = cDXT5SelectorValues - 1U, |
| }; |
| |
| static const uint8_t g_etc1_x_selector_unpack[4][256] = |
| { |
| { |
| 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, |
| 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, |
| 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, |
| 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, |
| 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, |
| 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, |
| 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, |
| 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, |
| }, |
| { |
| 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, |
| 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, |
| 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, |
| 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, |
| 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, |
| 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, |
| 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, |
| 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, |
| }, |
| |
| { |
| 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, |
| 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, |
| 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, |
| 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, |
| 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, |
| 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, |
| 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, |
| 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, |
| }, |
| |
| { |
| 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, |
| 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, |
| 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, |
| 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, |
| 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, |
| 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, |
| 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, |
| 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, |
| } |
| }; |
| |
| struct dxt1_block |
| { |
| enum { cTotalEndpointBytes = 2, cTotalSelectorBytes = 4 }; |
| |
| uint8_t m_low_color[cTotalEndpointBytes]; |
| uint8_t m_high_color[cTotalEndpointBytes]; |
| uint8_t m_selectors[cTotalSelectorBytes]; |
| |
| inline void clear() { basisu::clear_obj(*this); } |
| |
| inline uint32_t get_high_color() const { return m_high_color[0] | (m_high_color[1] << 8U); } |
| inline uint32_t get_low_color() const { return m_low_color[0] | (m_low_color[1] << 8U); } |
| inline void set_low_color(uint16_t c) { m_low_color[0] = static_cast<uint8_t>(c & 0xFF); m_low_color[1] = static_cast<uint8_t>((c >> 8) & 0xFF); } |
| inline void set_high_color(uint16_t c) { m_high_color[0] = static_cast<uint8_t>(c & 0xFF); m_high_color[1] = static_cast<uint8_t>((c >> 8) & 0xFF); } |
| inline uint32_t get_selector(uint32_t x, uint32_t y) const { assert((x < 4U) && (y < 4U)); return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask; } |
| inline void set_selector(uint32_t x, uint32_t y, uint32_t val) { assert((x < 4U) && (y < 4U) && (val < 4U)); m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits))); m_selectors[y] |= (val << (x * cDXT1SelectorBits)); } |
| |
| static uint16_t pack_color(const color32& color, bool scaled, uint32_t bias = 127U) |
| { |
| uint32_t r = color.r, g = color.g, b = color.b; |
| if (scaled) |
| { |
| r = (r * 31U + bias) / 255U; |
| g = (g * 63U + bias) / 255U; |
| b = (b * 31U + bias) / 255U; |
| } |
| return static_cast<uint16_t>(basisu::minimum(b, 31U) | (basisu::minimum(g, 63U) << 5U) | (basisu::minimum(r, 31U) << 11U)); |
| } |
| |
| static uint16_t pack_unscaled_color(uint32_t r, uint32_t g, uint32_t b) { return static_cast<uint16_t>(b | (g << 5U) | (r << 11U)); } |
| }; |
| |
| struct dxt_selector_range |
| { |
| uint32_t m_low; |
| uint32_t m_high; |
| }; |
| |
| struct etc1_to_dxt1_56_solution |
| { |
| uint8_t m_lo; |
| uint8_t m_hi; |
| uint16_t m_err; |
| }; |
| |
| #if BASISD_SUPPORT_DXT1 |
| static dxt_selector_range g_etc1_to_dxt1_selector_ranges[] = |
| { |
| { 0, 3 }, |
| |
| { 1, 3 }, |
| { 0, 2 }, |
| |
| { 1, 2 }, |
| |
| { 2, 3 }, |
| { 0, 1 }, |
| }; |
| |
| const uint32_t NUM_ETC1_TO_DXT1_SELECTOR_RANGES = sizeof(g_etc1_to_dxt1_selector_ranges) / sizeof(g_etc1_to_dxt1_selector_ranges[0]); |
| |
| static uint32_t g_etc1_to_dxt1_selector_range_index[4][4]; |
| |
| const uint32_t NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS = 10; |
| static const uint8_t g_etc1_to_dxt1_selector_mappings[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][4] = |
| { |
| { 0, 0, 1, 1 }, |
| { 0, 0, 1, 2 }, |
| { 0, 0, 1, 3 }, |
| { 0, 0, 2, 3 }, |
| { 0, 1, 1, 1 }, |
| { 0, 1, 2, 2 }, |
| { 0, 1, 2, 3 }, |
| { 0, 2, 3, 3 }, |
| { 1, 2, 2, 2 }, |
| { 1, 2, 3, 3 }, |
| }; |
| |
| static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256]; |
| static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256]; |
| |
| static const etc1_to_dxt1_56_solution g_etc1_to_dxt_6[32 * 8 * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS * NUM_ETC1_TO_DXT1_SELECTOR_RANGES] = { |
| #include "basisu_transcoder_tables_dxt1_6.inc" |
| }; |
| |
| static const etc1_to_dxt1_56_solution g_etc1_to_dxt_5[32 * 8 * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS * NUM_ETC1_TO_DXT1_SELECTOR_RANGES] = { |
| #include "basisu_transcoder_tables_dxt1_5.inc" |
| }; |
| #endif // BASISD_SUPPORT_DXT1 |
| |
| #if BASISD_SUPPORT_DXT1 || BASISD_SUPPORT_UASTC |
| // First saw the idea for optimal BC1 single-color block encoding using lookup tables in ryg_dxt. |
| struct bc1_match_entry |
| { |
| uint8_t m_hi; |
| uint8_t m_lo; |
| }; |
| static bc1_match_entry g_bc1_match5_equals_1[256], g_bc1_match6_equals_1[256]; // selector 1, allow equals hi/lo |
| static bc1_match_entry g_bc1_match5_equals_0[256], g_bc1_match6_equals_0[256]; // selector 0, allow equals hi/lo |
| |
| static void prepare_bc1_single_color_table(bc1_match_entry* pTable, const uint8_t* pExpand, int size0, int size1, int sel) |
| { |
| for (int i = 0; i < 256; i++) |
| { |
| int lowest_e = 256; |
| for (int lo = 0; lo < size0; lo++) |
| { |
| for (int hi = 0; hi < size1; hi++) |
| { |
| const int lo_e = pExpand[lo], hi_e = pExpand[hi]; |
| int e; |
| |
| if (sel == 1) |
| { |
| // Selector 1 |
| e = basisu::iabs(((hi_e * 2 + lo_e) / 3) - i); |
| e += (basisu::iabs(hi_e - lo_e) * 3) / 100; |
| } |
| else |
| { |
| assert(sel == 0); |
| |
| // Selector 0 |
| e = basisu::iabs(hi_e - i); |
| } |
| |
| if (e < lowest_e) |
| { |
| pTable[i].m_hi = static_cast<uint8_t>(hi); |
| pTable[i].m_lo = static_cast<uint8_t>(lo); |
| |
| lowest_e = e; |
| } |
| |
| } // hi |
| } // lo |
| } |
| } |
| #endif |
| |
| #if BASISD_WRITE_NEW_DXT1_TABLES |
| static void create_etc1_to_dxt1_5_conversion_table() |
| { |
| FILE* pFile = nullptr; |
| fopen_s(&pFile, "basisu_transcoder_tables_dxt1_5.inc", "w"); |
| |
| uint32_t n = 0; |
| |
| for (int inten = 0; inten < 8; inten++) |
| { |
| for (uint32_t g = 0; g < 32; g++) |
| { |
| color32 block_colors[4]; |
| decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten); |
| |
| for (uint32_t sr = 0; sr < NUM_ETC1_TO_DXT1_SELECTOR_RANGES; sr++) |
| { |
| const uint32_t low_selector = g_etc1_to_dxt1_selector_ranges[sr].m_low; |
| const uint32_t high_selector = g_etc1_to_dxt1_selector_ranges[sr].m_high; |
| |
| for (uint32_t m = 0; m < NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS; m++) |
| { |
| uint32_t best_lo = 0; |
| uint32_t best_hi = 0; |
| uint64_t best_err = UINT64_MAX; |
| |
| for (uint32_t hi = 0; hi <= 31; hi++) |
| { |
| for (uint32_t lo = 0; lo <= 31; lo++) |
| { |
| //if (lo == hi) continue; |
| |
| uint32_t colors[4]; |
| |
| colors[0] = (lo << 3) | (lo >> 2); |
| colors[3] = (hi << 3) | (hi >> 2); |
| |
| colors[1] = (colors[0] * 2 + colors[3]) / 3; |
| colors[2] = (colors[3] * 2 + colors[0]) / 3; |
| |
| uint64_t total_err = 0; |
| |
| for (uint32_t s = low_selector; s <= high_selector; s++) |
| { |
| int err = block_colors[s].g - colors[g_etc1_to_dxt1_selector_mappings[m][s]]; |
| |
| total_err += err * err; |
| } |
| |
| if (total_err < best_err) |
| { |
| best_err = total_err; |
| best_lo = lo; |
| best_hi = hi; |
| } |
| } |
| } |
| |
| assert(best_err <= 0xFFFF); |
| |
| //table[g + inten * 32].m_solutions[sr][m].m_lo = static_cast<uint8_t>(best_lo); |
| //table[g + inten * 32].m_solutions[sr][m].m_hi = static_cast<uint8_t>(best_hi); |
| //table[g + inten * 32].m_solutions[sr][m].m_err = static_cast<uint16_t>(best_err); |
| |
| //assert(best_lo != best_hi); |
| fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err); |
| n++; |
| if ((n & 31) == 31) |
| fprintf(pFile, "\n"); |
| } // m |
| } // sr |
| } // g |
| } // inten |
| |
| fclose(pFile); |
| } |
| |
| static void create_etc1_to_dxt1_6_conversion_table() |
| { |
| FILE* pFile = nullptr; |
| fopen_s(&pFile, "basisu_transcoder_tables_dxt1_6.inc", "w"); |
| |
| uint32_t n = 0; |
| |
| for (int inten = 0; inten < 8; inten++) |
| { |
| for (uint32_t g = 0; g < 32; g++) |
| { |
| color32 block_colors[4]; |
| decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten); |
| |
| for (uint32_t sr = 0; sr < NUM_ETC1_TO_DXT1_SELECTOR_RANGES; sr++) |
| { |
| const uint32_t low_selector = g_etc1_to_dxt1_selector_ranges[sr].m_low; |
| const uint32_t high_selector = g_etc1_to_dxt1_selector_ranges[sr].m_high; |
| |
| for (uint32_t m = 0; m < NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS; m++) |
| { |
| uint32_t best_lo = 0; |
| uint32_t best_hi = 0; |
| uint64_t best_err = UINT64_MAX; |
| |
| for (uint32_t hi = 0; hi <= 63; hi++) |
| { |
| for (uint32_t lo = 0; lo <= 63; lo++) |
| { |
| //if (lo == hi) continue; |
| |
| uint32_t colors[4]; |
| |
| colors[0] = (lo << 2) | (lo >> 4); |
| colors[3] = (hi << 2) | (hi >> 4); |
| |
| colors[1] = (colors[0] * 2 + colors[3]) / 3; |
| colors[2] = (colors[3] * 2 + colors[0]) / 3; |
| |
| uint64_t total_err = 0; |
| |
| for (uint32_t s = low_selector; s <= high_selector; s++) |
| { |
| int err = block_colors[s].g - colors[g_etc1_to_dxt1_selector_mappings[m][s]]; |
| |
| total_err += err * err; |
| } |
| |
| if (total_err < best_err) |
| { |
| best_err = total_err; |
| best_lo = lo; |
| best_hi = hi; |
| } |
| } |
| } |
| |
| assert(best_err <= 0xFFFF); |
| |
| //table[g + inten * 32].m_solutions[sr][m].m_lo = static_cast<uint8_t>(best_lo); |
| //table[g + inten * 32].m_solutions[sr][m].m_hi = static_cast<uint8_t>(best_hi); |
| //table[g + inten * 32].m_solutions[sr][m].m_err = static_cast<uint16_t>(best_err); |
| |
| //assert(best_lo != best_hi); |
| fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err); |
| n++; |
| if ((n & 31) == 31) |
| fprintf(pFile, "\n"); |
| |
| } // m |
| } // sr |
| } // g |
| } // inten |
| |
| fclose(pFile); |
| } |
| #endif |
| |
| |
| #if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11 |
| static const int8_t g_eac_modifier_table[16][8] = |
| { |
| { -3, -6, -9, -15, 2, 5, 8, 14 }, |
| { -3, -7, -10, -13, 2, 6, 9, 12 }, |
| { -2, -5, -8, -13, 1, 4, 7, 12 }, |
| { -2, -4, -6, -13, 1, 3, 5, 12 }, |
| { -3, -6, -8, -12, 2, 5, 7, 11 }, |
| { -3, -7, -9, -11, 2, 6, 8, 10 }, |
| { -4, -7, -8, -11, 3, 6, 7, 10 }, |
| { -3, -5, -8, -11, 2, 4, 7, 10 }, |
| |
| { -2, -6, -8, -10, 1, 5, 7, 9 }, |
| { -2, -5, -8, -10, 1, 4, 7, 9 }, |
| { -2, -4, -8, -10, 1, 3, 7, 9 }, |
| { -2, -5, -7, -10, 1, 4, 6, 9 }, |
| { -3, -4, -7, -10, 2, 3, 6, 9 }, |
| { -1, -2, -3, -10, 0, 1, 2, 9 }, // entry 13 |
| { -4, -6, -8, -9, 3, 5, 7, 8 }, |
| { -3, -5, -7, -9, 2, 4, 6, 8 } |
| }; |
| |
| // Used by ETC2 EAC A8 and ETC2 EAC R11/RG11. |
| struct eac_block |
| { |
| uint16_t m_base : 8; |
| |
| uint16_t m_table : 4; |
| uint16_t m_multiplier : 4; |
| |
| uint8_t m_selectors[6]; |
| |
| uint32_t get_selector(uint32_t x, uint32_t y) const |
| { |
| assert((x < 4) && (y < 4)); |
| |
| const uint32_t ofs = 45 - (y + x * 4) * 3; |
| |
| const uint64_t pixels = get_selector_bits(); |
| |
| return (pixels >> ofs) & 7; |
| } |
| |
| void set_selector(uint32_t x, uint32_t y, uint32_t s) |
| { |
| assert((x < 4) && (y < 4) && (s < 8)); |
| |
| const uint32_t ofs = 45 - (y + x * 4) * 3; |
| |
| uint64_t pixels = get_selector_bits(); |
| |
| pixels &= ~(7ULL << ofs); |
| pixels |= (static_cast<uint64_t>(s) << ofs); |
| |
| set_selector_bits(pixels); |
| } |
| |
| uint64_t get_selector_bits() const |
| { |
| uint64_t pixels = ((uint64_t)m_selectors[0] << 40) | ((uint64_t)m_selectors[1] << 32) | |
| ((uint64_t)m_selectors[2] << 24) | |
| ((uint64_t)m_selectors[3] << 16) | ((uint64_t)m_selectors[4] << 8) | m_selectors[5]; |
| return pixels; |
| } |
| |
| void set_selector_bits(uint64_t pixels) |
| { |
| m_selectors[0] = (uint8_t)(pixels >> 40); |
| m_selectors[1] = (uint8_t)(pixels >> 32); |
| m_selectors[2] = (uint8_t)(pixels >> 24); |
| m_selectors[3] = (uint8_t)(pixels >> 16); |
| m_selectors[4] = (uint8_t)(pixels >> 8); |
| m_selectors[5] = (uint8_t)(pixels); |
| } |
| }; |
| |
| #endif // #if BASISD_SUPPORT_UASTC BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11 |
| |
| #if BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11 |
| static const dxt_selector_range s_etc2_eac_selector_ranges[] = |
| { |
| { 0, 3 }, |
| |
| { 1, 3 }, |
| { 0, 2 }, |
| |
| { 1, 2 }, |
| }; |
| |
| const uint32_t NUM_ETC2_EAC_SELECTOR_RANGES = sizeof(s_etc2_eac_selector_ranges) / sizeof(s_etc2_eac_selector_ranges[0]); |
| |
| struct etc1_g_to_eac_conversion |
| { |
| uint8_t m_base; |
| uint8_t m_table_mul; // mul*16+table |
| uint16_t m_trans; // translates ETC1 selectors to ETC2_EAC_A8 |
| }; |
| #endif // BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG11 |
| |
| #if BASISD_SUPPORT_ETC2_EAC_A8 |
| |
| #if BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES |
| struct pack_eac_a8_results |
| { |
| uint32_t m_base; |
| uint32_t m_table; |
| uint32_t m_multiplier; |
| basisu::vector<uint8_t> m_selectors; |
| basisu::vector<uint8_t> m_selectors_temp; |
| }; |
| |
| static uint64_t pack_eac_a8_exhaustive(pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels) |
| { |
| results.m_selectors.resize(num_pixels); |
| results.m_selectors_temp.resize(num_pixels); |
| |
| uint64_t best_err = UINT64_MAX; |
| |
| for (uint32_t base_color = 0; base_color < 256; base_color++) |
| { |
| for (uint32_t multiplier = 1; multiplier < 16; multiplier++) |
| { |
| for (uint32_t table = 0; table < 16; table++) |
| { |
| uint64_t total_err = 0; |
| |
| for (uint32_t i = 0; i < num_pixels; i++) |
| { |
| const int a = pPixels[i]; |
| |
| uint32_t best_s_err = UINT32_MAX; |
| uint32_t best_s = 0; |
| for (uint32_t s = 0; s < 8; s++) |
| { |
| int v = (int)multiplier * g_eac_modifier_table[table][s] + (int)base_color; |
| if (v < 0) |
| v = 0; |
| else if (v > 255) |
| v = 255; |
| |
| uint32_t err = abs(a - v); |
| if (err < best_s_err) |
| { |
| best_s_err = err; |
| best_s = s; |
| } |
| } |
| |
| results.m_selectors_temp[i] = static_cast<uint8_t>(best_s); |
| |
| total_err += best_s_err * best_s_err; |
| if (total_err >= best_err) |
| break; |
| } |
| |
| if (total_err < best_err) |
| { |
| best_err = total_err; |
| results.m_base = base_color; |
| results.m_multiplier = multiplier; |
| results.m_table = table; |
| results.m_selectors.swap(results.m_selectors_temp); |
| } |
| |
| } // table |
| |
| } // multiplier |
| |
| } // base_color |
| |
| return best_err; |
| } |
| #endif // BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES |
| |
| static |
| #if !BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES |
| const |
| #endif |
| etc1_g_to_eac_conversion s_etc1_g_to_etc2_a8[32 * 8][NUM_ETC2_EAC_SELECTOR_RANGES] = |
| { |
| { { 0,1,3328 },{ 0,1,3328 },{ 0,1,256 },{ 0,1,256 } }, |
| { { 0,226,3936 },{ 0,226,3936 },{ 0,81,488 },{ 0,81,488 } }, |
| { { 6,178,4012 },{ 6,178,4008 },{ 0,146,501 },{ 0,130,496 } }, |
| { { 14,178,4012 },{ 14,178,4008 },{ 8,146,501 },{ 6,82,496 } }, |
| { { 23,178,4012 },{ 23,178,4008 },{ 17,146,501 },{ 3,228,496 } }, |
| { { 31,178,4012 },{ 31,178,4008 },{ 25,146,501 },{ 11,228,496 } }, |
| { { 39,178,4012 },{ 39,178,4008 },{ 33,146,501 },{ 19,228,496 } }, |
| { { 47,178,4012 },{ 47,178,4008 },{ 41,146,501 },{ 27,228,496 } }, |
| { { 56,178,4012 },{ 56,178,4008 },{ 50,146,501 },{ 36,228,496 } }, |
| { { 64,178,4012 },{ 64,178,4008 },{ 58,146,501 },{ 44,228,496 } }, |
| { { 72,178,4012 },{ 72,178,4008 },{ 66,146,501 },{ 52,228,496 } }, |
| { { 80,178,4012 },{ 80,178,4008 },{ 74,146,501 },{ 60,228,496 } }, |
| { { 89,178,4012 },{ 89,178,4008 },{ 83,146,501 },{ 69,228,496 } }, |
| { { 97,178,4012 },{ 97,178,4008 },{ 91,146,501 },{ 77,228,496 } }, |
| { { 105,178,4012 },{ 105,178,4008 },{ 99,146,501 },{ 85,228,496 } }, |
| { { 113,178,4012 },{ 113,178,4008 },{ 107,146,501 },{ 93,228,496 } }, |
| { { 122,178,4012 },{ 122,178,4008 },{ 116,146,501 },{ 102,228,496 } }, |
| { { 130,178,4012 },{ 130,178,4008 },{ 124,146,501 },{ 110,228,496 } }, |
| { { 138,178,4012 },{ 138,178,4008 },{ 132,146,501 },{ 118,228,496 } }, |
| { { 146,178,4012 },{ 146,178,4008 },{ 140,146,501 },{ 126,228,496 } }, |
| { { 155,178,4012 },{ 155,178,4008 },{ 149,146,501 },{ 135,228,496 } }, |
| { { 163,178,4012 },{ 163,178,4008 },{ 157,146,501 },{ 143,228,496 } }, |
| { { 171,178,4012 },{ 171,178,4008 },{ 165,146,501 },{ 151,228,496 } }, |
| { { 179,178,4012 },{ 179,178,4008 },{ 173,146,501 },{ 159,228,496 } }, |
| { { 188,178,4012 },{ 188,178,4008 },{ 182,146,501 },{ 168,228,496 } }, |
| { { 196,178,4012 },{ 196,178,4008 },{ 190,146,501 },{ 176,228,496 } }, |
| { { 204,178,4012 },{ 204,178,4008 },{ 198,146,501 },{ 184,228,496 } }, |
| { { 212,178,4012 },{ 212,178,4008 },{ 206,146,501 },{ 192,228,496 } }, |
| { { 221,178,4012 },{ 221,178,4008 },{ 215,146,501 },{ 201,228,496 } }, |
| { { 229,178,4012 },{ 229,178,4008 },{ 223,146,501 },{ 209,228,496 } }, |
| { { 235,66,4012 },{ 221,100,4008 },{ 231,146,501 },{ 217,228,496 } }, |
| { { 211,102,4085 },{ 118,31,4080 },{ 211,102,501 },{ 118,31,496 } }, |
| { { 1,2,3328 },{ 1,2,3328 },{ 0,1,320 },{ 0,1,320 } }, |
| { { 7,162,3905 },{ 7,162,3904 },{ 1,17,480 },{ 1,17,480 } }, |
| { { 15,162,3906 },{ 15,162,3904 },{ 1,117,352 },{ 1,117,352 } }, |
| { { 23,162,3906 },{ 23,162,3904 },{ 5,34,500 },{ 4,53,424 } }, |
| { { 32,162,3906 },{ 32,162,3904 },{ 14,34,500 },{ 3,69,424 } }, |
| { { 40,162,3906 },{ 40,162,3904 },{ 22,34,500 },{ 1,133,496 } }, |
| { { 48,162,3906 },{ 48,162,3904 },{ 30,34,500 },{ 4,85,496 } }, |
| { { 56,162,3906 },{ 56,162,3904 },{ 38,34,500 },{ 12,85,496 } }, |
| { { 65,162,3906 },{ 65,162,3904 },{ 47,34,500 },{ 1,106,424 } }, |
| { { 73,162,3906 },{ 73,162,3904 },{ 55,34,500 },{ 9,106,424 } }, |
| { { 81,162,3906 },{ 81,162,3904 },{ 63,34,500 },{ 7,234,496 } }, |
| { { 89,162,3906 },{ 89,162,3904 },{ 71,34,500 },{ 15,234,496 } }, |
| { { 98,162,3906 },{ 98,162,3904 },{ 80,34,500 },{ 24,234,496 } }, |
| { { 106,162,3906 },{ 106,162,3904 },{ 88,34,500 },{ 32,234,496 } }, |
| { { 114,162,3906 },{ 114,162,3904 },{ 96,34,500 },{ 40,234,496 } }, |
| { { 122,162,3906 },{ 122,162,3904 },{ 104,34,500 },{ 48,234,496 } }, |
| { { 131,162,3906 },{ 131,162,3904 },{ 113,34,500 },{ 57,234,496 } }, |
| { { 139,162,3906 },{ 139,162,3904 },{ 121,34,500 },{ 65,234,496 } }, |
| { { 147,162,3906 },{ 147,162,3904 },{ 129,34,500 },{ 73,234,496 } }, |
| { { 155,162,3906 },{ 155,162,3904 },{ 137,34,500 },{ 81,234,496 } }, |
| { { 164,162,3906 },{ 164,162,3904 },{ 146,34,500 },{ 90,234,496 } }, |
| { { 172,162,3906 },{ 172,162,3904 },{ 154,34,500 },{ 98,234,496 } }, |
| { { 180,162,3906 },{ 180,162,3904 },{ 162,34,500 },{ 106,234,496 } }, |
| { { 188,162,3906 },{ 188,162,3904 },{ 170,34,500 },{ 114,234,496 } }, |
| { { 197,162,3906 },{ 197,162,3904 },{ 179,34,500 },{ 123,234,496 } }, |
| { { 205,162,3906 },{ 205,162,3904 },{ 187,34,500 },{ 131,234,496 } }, |
| { { 213,162,3906 },{ 213,162,3904 },{ 195,34,500 },{ 139,234,496 } }, |
| { { 221,162,3906 },{ 221,162,3904 },{ 203,34,500 },{ 147,234,496 } }, |
| { { 230,162,3906 },{ 230,162,3904 },{ 212,34,500 },{ 156,234,496 } }, |
| { { 238,162,3906 },{ 174,106,4008 },{ 220,34,500 },{ 164,234,496 } }, |
| { { 240,178,4001 },{ 182,106,4008 },{ 228,34,500 },{ 172,234,496 } }, |
| { { 166,108,4085 },{ 115,31,4080 },{ 166,108,501 },{ 115,31,496 } }, |
| { { 1,68,3328 },{ 1,68,3328 },{ 0,17,384 },{ 0,17,384 } }, |
| { { 1,148,3904 },{ 1,148,3904 },{ 1,2,384 },{ 1,2,384 } }, |
| { { 21,18,3851 },{ 21,18,3848 },{ 1,50,488 },{ 1,50,488 } }, |
| { { 27,195,3851 },{ 29,18,3848 },{ 0,67,488 },{ 0,67,488 } }, |
| { { 34,195,3907 },{ 38,18,3848 },{ 20,66,482 },{ 0,3,496 } }, |
| { { 42,195,3907 },{ 46,18,3848 },{ 28,66,482 },{ 2,6,424 } }, |
| { { 50,195,3907 },{ 54,18,3848 },{ 36,66,482 },{ 4,22,424 } }, |
| { { 58,195,3907 },{ 62,18,3848 },{ 44,66,482 },{ 3,73,424 } }, |
| { { 67,195,3907 },{ 71,18,3848 },{ 53,66,482 },{ 3,22,496 } }, |
| { { 75,195,3907 },{ 79,18,3848 },{ 61,66,482 },{ 2,137,496 } }, |
| { { 83,195,3907 },{ 87,18,3848 },{ 69,66,482 },{ 1,89,496 } }, |
| { { 91,195,3907 },{ 95,18,3848 },{ 77,66,482 },{ 9,89,496 } }, |
| { { 100,195,3907 },{ 104,18,3848 },{ 86,66,482 },{ 18,89,496 } }, |
| { { 108,195,3907 },{ 112,18,3848 },{ 94,66,482 },{ 26,89,496 } }, |
| { { 116,195,3907 },{ 120,18,3848 },{ 102,66,482 },{ 34,89,496 } }, |
| { { 124,195,3907 },{ 128,18,3848 },{ 110,66,482 },{ 42,89,496 } }, |
| { { 133,195,3907 },{ 137,18,3848 },{ 119,66,482 },{ 51,89,496 } }, |
| { { 141,195,3907 },{ 145,18,3848 },{ 127,66,482 },{ 59,89,496 } }, |
| { { 149,195,3907 },{ 153,18,3848 },{ 135,66,482 },{ 67,89,496 } }, |
| { { 157,195,3907 },{ 161,18,3848 },{ 143,66,482 },{ 75,89,496 } }, |
| { { 166,195,3907 },{ 170,18,3848 },{ 152,66,482 },{ 84,89,496 } }, |
| { { 174,195,3907 },{ 178,18,3848 },{ 160,66,482 },{ 92,89,496 } }, |
| { { 182,195,3907 },{ 186,18,3848 },{ 168,66,482 },{ 100,89,496 } }, |
| { { 190,195,3907 },{ 194,18,3848 },{ 176,66,482 },{ 108,89,496 } }, |
| { { 199,195,3907 },{ 203,18,3848 },{ 185,66,482 },{ 117,89,496 } }, |
| { { 207,195,3907 },{ 211,18,3848 },{ 193,66,482 },{ 125,89,496 } }, |
| { { 215,195,3907 },{ 219,18,3848 },{ 201,66,482 },{ 133,89,496 } }, |
| { { 223,195,3907 },{ 227,18,3848 },{ 209,66,482 },{ 141,89,496 } }, |
| { { 231,195,3907 },{ 168,89,4008 },{ 218,66,482 },{ 150,89,496 } }, |
| { { 236,18,3907 },{ 176,89,4008 },{ 226,66,482 },{ 158,89,496 } }, |
| { { 158,90,4085 },{ 103,31,4080 },{ 158,90,501 },{ 103,31,496 } }, |
| { { 166,90,4085 },{ 111,31,4080 },{ 166,90,501 },{ 111,31,496 } }, |
| { { 0,70,3328 },{ 0,70,3328 },{ 0,45,256 },{ 0,45,256 } }, |
| { { 0,117,3904 },{ 0,117,3904 },{ 0,35,384 },{ 0,35,384 } }, |
| { { 13,165,3905 },{ 13,165,3904 },{ 3,221,416 },{ 3,221,416 } }, |
| { { 21,165,3906 },{ 21,165,3904 },{ 11,221,416 },{ 11,221,416 } }, |
| { { 30,165,3906 },{ 30,165,3904 },{ 7,61,352 },{ 7,61,352 } }, |
| { { 38,165,3906 },{ 38,165,3904 },{ 2,125,352 },{ 2,125,352 } }, |
| { { 46,165,3906 },{ 46,165,3904 },{ 2,37,500 },{ 10,125,352 } }, |
| { { 54,165,3906 },{ 54,165,3904 },{ 10,37,500 },{ 5,61,424 } }, |
| { { 63,165,3906 },{ 63,165,3904 },{ 19,37,500 },{ 1,189,424 } }, |
| { { 4,254,4012 },{ 71,165,3904 },{ 27,37,500 },{ 9,189,424 } }, |
| { { 12,254,4012 },{ 79,165,3904 },{ 35,37,500 },{ 4,77,424 } }, |
| { { 20,254,4012 },{ 87,165,3904 },{ 43,37,500 },{ 12,77,424 } }, |
| { { 29,254,4012 },{ 96,165,3904 },{ 52,37,500 },{ 8,93,424 } }, |
| { { 37,254,4012 },{ 104,165,3904 },{ 60,37,500 },{ 3,141,496 } }, |
| { { 45,254,4012 },{ 112,165,3904 },{ 68,37,500 },{ 11,141,496 } }, |
| { { 53,254,4012 },{ 120,165,3904 },{ 76,37,500 },{ 6,93,496 } }, |
| { { 62,254,4012 },{ 129,165,3904 },{ 85,37,500 },{ 15,93,496 } }, |
| { { 70,254,4012 },{ 137,165,3904 },{ 93,37,500 },{ 23,93,496 } }, |
| { { 78,254,4012 },{ 145,165,3904 },{ 101,37,500 },{ 31,93,496 } }, |
| { { 86,254,4012 },{ 153,165,3904 },{ 109,37,500 },{ 39,93,496 } }, |
| { { 95,254,4012 },{ 162,165,3904 },{ 118,37,500 },{ 48,93,496 } }, |
| { { 103,254,4012 },{ 170,165,3904 },{ 126,37,500 },{ 56,93,496 } }, |
| { { 111,254,4012 },{ 178,165,3904 },{ 134,37,500 },{ 64,93,496 } }, |
| { { 119,254,4012 },{ 186,165,3904 },{ 142,37,500 },{ 72,93,496 } }, |
| { { 128,254,4012 },{ 195,165,3904 },{ 151,37,500 },{ 81,93,496 } }, |
| { { 136,254,4012 },{ 203,165,3904 },{ 159,37,500 },{ 89,93,496 } }, |
| { { 212,165,3906 },{ 136,77,4008 },{ 167,37,500 },{ 97,93,496 } }, |
| { { 220,165,3394 },{ 131,93,4008 },{ 175,37,500 },{ 105,93,496 } }, |
| { { 214,181,4001 },{ 140,93,4008 },{ 184,37,500 },{ 114,93,496 } }, |
| { { 222,181,4001 },{ 148,93,4008 },{ 192,37,500 },{ 122,93,496 } }, |
| { { 114,95,4085 },{ 99,31,4080 },{ 114,95,501 },{ 99,31,496 } }, |
| { { 122,95,4085 },{ 107,31,4080 },{ 122,95,501 },{ 107,31,496 } }, |
| { { 0,102,3840 },{ 0,102,3840 },{ 0,18,384 },{ 0,18,384 } }, |
| { { 5,167,3904 },{ 5,167,3904 },{ 0,13,256 },{ 0,13,256 } }, |
| { { 4,54,3968 },{ 4,54,3968 },{ 1,67,448 },{ 1,67,448 } }, |
| { { 30,198,3850 },{ 30,198,3848 },{ 0,3,480 },{ 0,3,480 } }, |
| { { 39,198,3850 },{ 39,198,3848 },{ 3,52,488 },{ 3,52,488 } }, |
| { { 47,198,3851 },{ 47,198,3848 },{ 3,4,488 },{ 3,4,488 } }, |
| { { 55,198,3851 },{ 55,198,3848 },{ 1,70,488 },{ 1,70,488 } }, |
| { { 54,167,3906 },{ 63,198,3848 },{ 3,22,488 },{ 3,22,488 } }, |
| { { 62,167,3906 },{ 72,198,3848 },{ 24,118,488 },{ 0,6,496 } }, |
| { { 70,167,3906 },{ 80,198,3848 },{ 32,118,488 },{ 2,89,488 } }, |
| { { 78,167,3906 },{ 88,198,3848 },{ 40,118,488 },{ 1,73,496 } }, |
| { { 86,167,3906 },{ 96,198,3848 },{ 48,118,488 },{ 0,28,424 } }, |
| { { 95,167,3906 },{ 105,198,3848 },{ 57,118,488 },{ 9,28,424 } }, |
| { { 103,167,3906 },{ 113,198,3848 },{ 65,118,488 },{ 5,108,496 } }, |
| { { 111,167,3906 },{ 121,198,3848 },{ 73,118,488 },{ 13,108,496 } }, |
| { { 119,167,3906 },{ 129,198,3848 },{ 81,118,488 },{ 21,108,496 } }, |
| { { 128,167,3906 },{ 138,198,3848 },{ 90,118,488 },{ 6,28,496 } }, |
| { { 136,167,3906 },{ 146,198,3848 },{ 98,118,488 },{ 14,28,496 } }, |
| { { 144,167,3906 },{ 154,198,3848 },{ 106,118,488 },{ 22,28,496 } }, |
| { { 152,167,3906 },{ 162,198,3848 },{ 114,118,488 },{ 30,28,496 } }, |
| { { 161,167,3906 },{ 171,198,3848 },{ 123,118,488 },{ 39,28,496 } }, |
| { { 169,167,3906 },{ 179,198,3848 },{ 131,118,488 },{ 47,28,496 } }, |
| { { 177,167,3906 },{ 187,198,3848 },{ 139,118,488 },{ 55,28,496 } }, |
| { { 185,167,3906 },{ 195,198,3848 },{ 147,118,488 },{ 63,28,496 } }, |
| { { 194,167,3906 },{ 120,12,4008 },{ 156,118,488 },{ 72,28,496 } }, |
| { { 206,198,3907 },{ 116,28,4008 },{ 164,118,488 },{ 80,28,496 } }, |
| { { 214,198,3907 },{ 124,28,4008 },{ 172,118,488 },{ 88,28,496 } }, |
| { { 222,198,3395 },{ 132,28,4008 },{ 180,118,488 },{ 96,28,496 } }, |
| { { 207,134,4001 },{ 141,28,4008 },{ 189,118,488 },{ 105,28,496 } }, |
| { { 95,30,4085 },{ 86,31,4080 },{ 95,30,501 },{ 86,31,496 } }, |
| { { 103,30,4085 },{ 94,31,4080 },{ 103,30,501 },{ 94,31,496 } }, |
| { { 111,30,4085 },{ 102,31,4080 },{ 111,30,501 },{ 102,31,496 } }, |
| { { 0,104,3840 },{ 0,104,3840 },{ 0,18,448 },{ 0,18,448 } }, |
| { { 4,39,3904 },{ 4,39,3904 },{ 0,4,384 },{ 0,4,384 } }, |
| { { 0,56,3968 },{ 0,56,3968 },{ 0,84,448 },{ 0,84,448 } }, |
| { { 6,110,3328 },{ 6,110,3328 },{ 0,20,448 },{ 0,20,448 } }, |
| { { 41,200,3850 },{ 41,200,3848 },{ 1,4,480 },{ 1,4,480 } }, |
| { { 49,200,3850 },{ 49,200,3848 },{ 1,8,416 },{ 1,8,416 } }, |
| { { 57,200,3851 },{ 57,200,3848 },{ 1,38,488 },{ 1,38,488 } }, |
| { { 65,200,3851 },{ 65,200,3848 },{ 1,120,488 },{ 1,120,488 } }, |
| { { 74,200,3851 },{ 74,200,3848 },{ 2,72,488 },{ 2,72,488 } }, |
| { { 69,6,3907 },{ 82,200,3848 },{ 2,24,488 },{ 2,24,488 } }, |
| { { 77,6,3907 },{ 90,200,3848 },{ 26,120,488 },{ 10,24,488 } }, |
| { { 97,63,3330 },{ 98,200,3848 },{ 34,120,488 },{ 2,8,496 } }, |
| { { 106,63,3330 },{ 107,200,3848 },{ 43,120,488 },{ 3,92,488 } }, |
| { { 114,63,3330 },{ 115,200,3848 },{ 51,120,488 },{ 11,92,488 } }, |
| { { 122,63,3330 },{ 123,200,3848 },{ 59,120,488 },{ 7,76,496 } }, |
| { { 130,63,3330 },{ 131,200,3848 },{ 67,120,488 },{ 15,76,496 } }, |
| { { 139,63,3330 },{ 140,200,3848 },{ 76,120,488 },{ 24,76,496 } }, |
| { { 147,63,3330 },{ 148,200,3848 },{ 84,120,488 },{ 32,76,496 } }, |
| { { 155,63,3330 },{ 156,200,3848 },{ 92,120,488 },{ 40,76,496 } }, |
| { { 163,63,3330 },{ 164,200,3848 },{ 100,120,488 },{ 48,76,496 } }, |
| { { 172,63,3330 },{ 173,200,3848 },{ 109,120,488 },{ 57,76,496 } }, |
| { { 184,6,3851 },{ 181,200,3848 },{ 117,120,488 },{ 65,76,496 } }, |
| { { 192,6,3851 },{ 133,28,3936 },{ 125,120,488 },{ 73,76,496 } }, |
| { { 189,200,3907 },{ 141,28,3936 },{ 133,120,488 },{ 81,76,496 } }, |
| { { 198,200,3907 },{ 138,108,4000 },{ 142,120,488 },{ 90,76,496 } }, |
| { { 206,200,3907 },{ 146,108,4000 },{ 150,120,488 },{ 98,76,496 } }, |
| { { 214,200,3395 },{ 154,108,4000 },{ 158,120,488 },{ 106,76,496 } }, |
| { { 190,136,4001 },{ 162,108,4000 },{ 166,120,488 },{ 114,76,496 } }, |
| { { 123,30,4076 },{ 87,15,4080 },{ 123,30,492 },{ 87,15,496 } }, |
| { { 117,110,4084 },{ 80,31,4080 },{ 117,110,500 },{ 80,31,496 } }, |
| { { 125,110,4084 },{ 88,31,4080 },{ 125,110,500 },{ 88,31,496 } }, |
| { { 133,110,4084 },{ 96,31,4080 },{ 133,110,500 },{ 96,31,496 } }, |
| { { 9,56,3904 },{ 9,56,3904 },{ 0,67,448 },{ 0,67,448 } }, |
| { { 1,8,3904 },{ 1,8,3904 },{ 1,84,448 },{ 1,84,448 } }, |
| { { 1,124,3904 },{ 1,124,3904 },{ 0,39,384 },{ 0,39,384 } }, |
| { { 9,124,3904 },{ 9,124,3904 },{ 1,4,448 },{ 1,4,448 } }, |
| { { 6,76,3904 },{ 6,76,3904 },{ 0,70,448 },{ 0,70,448 } }, |
| { { 62,6,3859 },{ 62,6,3856 },{ 2,38,480 },{ 2,38,480 } }, |
| { { 70,6,3859 },{ 70,6,3856 },{ 5,43,416 },{ 5,43,416 } }, |
| { { 78,6,3859 },{ 78,6,3856 },{ 2,11,416 },{ 2,11,416 } }, |
| { { 87,6,3859 },{ 87,6,3856 },{ 0,171,488 },{ 0,171,488 } }, |
| { { 67,8,3906 },{ 95,6,3856 },{ 8,171,488 },{ 8,171,488 } }, |
| { { 75,8,3907 },{ 103,6,3856 },{ 5,123,488 },{ 5,123,488 } }, |
| { { 83,8,3907 },{ 111,6,3856 },{ 2,75,488 },{ 2,75,488 } }, |
| { { 92,8,3907 },{ 120,6,3856 },{ 0,27,488 },{ 0,27,488 } }, |
| { { 100,8,3907 },{ 128,6,3856 },{ 8,27,488 },{ 8,27,488 } }, |
| { { 120,106,3843 },{ 136,6,3856 },{ 100,6,387 },{ 16,27,488 } }, |
| { { 128,106,3843 },{ 144,6,3856 },{ 108,6,387 },{ 2,11,496 } }, |
| { { 137,106,3843 },{ 153,6,3856 },{ 117,6,387 },{ 11,11,496 } }, |
| { { 145,106,3843 },{ 161,6,3856 },{ 125,6,387 },{ 19,11,496 } }, |
| { { 163,8,3851 },{ 137,43,3904 },{ 133,6,387 },{ 27,11,496 } }, |
| { { 171,8,3851 },{ 101,11,4000 },{ 141,6,387 },{ 35,11,496 } }, |
| { { 180,8,3851 },{ 110,11,4000 },{ 150,6,387 },{ 44,11,496 } }, |
| { { 188,8,3851 },{ 118,11,4000 },{ 158,6,387 },{ 52,11,496 } }, |
| { { 172,72,3907 },{ 126,11,4000 },{ 166,6,387 },{ 60,11,496 } }, |
| { { 174,6,3971 },{ 134,11,4000 },{ 174,6,387 },{ 68,11,496 } }, |
| { { 183,6,3971 },{ 143,11,4000 },{ 183,6,387 },{ 77,11,496 } }, |
| { { 191,6,3971 },{ 151,11,4000 },{ 191,6,387 },{ 85,11,496 } }, |
| { { 199,6,3971 },{ 159,11,4000 },{ 199,6,387 },{ 93,11,496 } }, |
| { { 92,12,4084 },{ 69,15,4080 },{ 92,12,500 },{ 69,15,496 } }, |
| { { 101,12,4084 },{ 78,15,4080 },{ 101,12,500 },{ 78,15,496 } }, |
| { { 109,12,4084 },{ 86,15,4080 },{ 109,12,500 },{ 86,15,496 } }, |
| { { 117,12,4084 },{ 79,31,4080 },{ 117,12,500 },{ 79,31,496 } }, |
| { { 125,12,4084 },{ 87,31,4080 },{ 125,12,500 },{ 87,31,496 } }, |
| { { 71,8,3602 },{ 71,8,3600 },{ 2,21,384 },{ 2,21,384 } }, |
| { { 79,8,3611 },{ 79,8,3608 },{ 0,69,448 },{ 0,69,448 } }, |
| { { 87,8,3611 },{ 87,8,3608 },{ 0,23,384 },{ 0,23,384 } }, |
| { { 95,8,3611 },{ 95,8,3608 },{ 1,5,448 },{ 1,5,448 } }, |
| { { 104,8,3611 },{ 104,8,3608 },{ 0,88,448 },{ 0,88,448 } }, |
| { { 112,8,3611 },{ 112,8,3608 },{ 0,72,448 },{ 0,72,448 } }, |
| { { 120,8,3611 },{ 121,8,3608 },{ 36,21,458 },{ 36,21,456 } }, |
| { { 133,47,3091 },{ 129,8,3608 },{ 44,21,458 },{ 44,21,456 } }, |
| { { 142,47,3091 },{ 138,8,3608 },{ 53,21,459 },{ 53,21,456 } }, |
| { { 98,12,3850 },{ 98,12,3848 },{ 61,21,459 },{ 61,21,456 } }, |
| { { 106,12,3850 },{ 106,12,3848 },{ 10,92,480 },{ 69,21,456 } }, |
| { { 114,12,3851 },{ 114,12,3848 },{ 18,92,480 },{ 77,21,456 } }, |
| { { 87,12,3906 },{ 87,12,3904 },{ 3,44,488 },{ 86,21,456 } }, |
| { { 95,12,3906 },{ 95,12,3904 },{ 11,44,488 },{ 94,21,456 } }, |
| { { 103,12,3906 },{ 103,12,3904 },{ 19,44,488 },{ 102,21,456 } }, |
| { { 111,12,3907 },{ 111,12,3904 },{ 27,44,489 },{ 110,21,456 } }, |
| { { 120,12,3907 },{ 120,12,3904 },{ 36,44,489 },{ 119,21,456 } }, |
| { { 128,12,3907 },{ 128,12,3904 },{ 44,44,489 },{ 127,21,456 } }, |
| { { 136,12,3907 },{ 136,12,3904 },{ 52,44,489 },{ 135,21,456 } }, |
| { { 144,12,3907 },{ 144,12,3904 },{ 60,44,489 },{ 143,21,456 } }, |
| { { 153,12,3907 },{ 153,12,3904 },{ 69,44,490 },{ 152,21,456 } }, |
| { { 161,12,3395 },{ 149,188,3968 },{ 77,44,490 },{ 160,21,456 } }, |
| { { 169,12,3395 },{ 198,21,3928 },{ 85,44,490 },{ 168,21,456 } }, |
| { { 113,95,4001 },{ 201,69,3992 },{ 125,8,483 },{ 176,21,456 } }, |
| { { 122,95,4001 },{ 200,21,3984 },{ 134,8,483 },{ 185,21,456 } }, |
| { { 142,8,4067 },{ 208,21,3984 },{ 142,8,483 },{ 193,21,456 } }, |
| { { 151,8,4067 },{ 47,15,4080 },{ 151,8,483 },{ 47,15,496 } }, |
| { { 159,8,4067 },{ 55,15,4080 },{ 159,8,483 },{ 55,15,496 } }, |
| { { 168,8,4067 },{ 64,15,4080 },{ 168,8,483 },{ 64,15,496 } }, |
| { { 160,40,4075 },{ 72,15,4080 },{ 160,40,491 },{ 72,15,496 } }, |
| { { 168,40,4075 },{ 80,15,4080 },{ 168,40,491 },{ 80,15,496 } }, |
| { { 144,8,4082 },{ 88,15,4080 },{ 144,8,498 },{ 88,15,496 } } |
| }; |
| #endif // BASISD_SUPPORT_ETC2_EAC_A8 |
| |
| #if BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES |
| static void create_etc2_eac_a8_conversion_table() |
| { |
| FILE* pFile = fopen("basisu_decoder_tables_etc2_eac_a8.inc", "w"); |
| |
| for (uint32_t inten = 0; inten < 8; inten++) |
| { |
| for (uint32_t base = 0; base < 32; base++) |
| { |
| color32 block_colors[4]; |
| decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(base, base, base, 255), false), inten); |
| |
| fprintf(pFile, "{"); |
| |
| for (uint32_t sel_range = 0; sel_range < NUM_ETC2_EAC_SELECTOR_RANGES; sel_range++) |
| { |
| const uint32_t low_selector = s_etc2_eac_selector_ranges[sel_range].m_low; |
| const uint32_t high_selector = s_etc2_eac_selector_ranges[sel_range].m_high; |
| |
| // We have a ETC1 base color and intensity, and a used selector range from low_selector-high_selector. |
| // Now find the best ETC2 EAC A8 base/table/multiplier that fits these colors. |
| |
| uint8_t pixels[4]; |
| uint32_t num_pixels = 0; |
| for (uint32_t s = low_selector; s <= high_selector; s++) |
| pixels[num_pixels++] = block_colors[s].g; |
| |
| pack_eac_a8_results pack_results; |
| pack_eac_a8_exhaustive(pack_results, pixels, num_pixels); |
| |
| etc1_g_to_eac_conversion& c = s_etc1_g_to_etc2_a8[base + inten * 32][sel_range]; |
| |
| c.m_base = pack_results.m_base; |
| c.m_table_mul = pack_results.m_table * 16 + pack_results.m_multiplier; |
| c.m_trans = 0; |
| |
| for (uint32_t s = 0; s < 4; s++) |
| { |
| if ((s < low_selector) || (s > high_selector)) |
| continue; |
| |
| uint32_t etc2_selector = pack_results.m_selectors[s - low_selector]; |
| |
| c.m_trans |= (etc2_selector << (s * 3)); |
| } |
| |
| fprintf(pFile, "{%u,%u,%u}", c.m_base, c.m_table_mul, c.m_trans); |
| if (sel_range < (NUM_ETC2_EAC_SELECTOR_RANGES - 1)) |
| fprintf(pFile, ","); |
| } |
| |
| fprintf(pFile, "},\n"); |
| } |
| } |
| |
| fclose(pFile); |
| } |
| #endif |
| |
| #if BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES |
| struct pack_eac_r11_results |
| { |
| uint32_t m_base; |
| uint32_t m_table; |
| uint32_t m_multiplier; |
| basisu::vector<uint8_t> m_selectors; |
| basisu::vector<uint8_t> m_selectors_temp; |
| }; |
| |
| static uint64_t pack_eac_r11_exhaustive(pack_eac_r11_results& results, const uint8_t* pPixels, uint32_t num_pixels) |
| { |
| results.m_selectors.resize(num_pixels); |
| results.m_selectors_temp.resize(num_pixels); |
| |
| uint64_t best_err = UINT64_MAX; |
| |
| for (uint32_t base_color = 0; base_color < 256; base_color++) |
| { |
| for (uint32_t multiplier = 0; multiplier < 16; multiplier++) |
| { |
| for (uint32_t table = 0; table < 16; table++) |
| { |
| uint64_t total_err = 0; |
| |
| for (uint32_t i = 0; i < num_pixels; i++) |
| { |
| // Convert 8-bit input to 11-bits |
| const int a = (pPixels[i] * 2047 + 128) / 255; |
| |
| uint32_t best_s_err = UINT32_MAX; |
| uint32_t best_s = 0; |
| for (uint32_t s = 0; s < 8; s++) |
| { |
| int v = (int)(multiplier ? (multiplier * 8) : 1) * g_eac_modifier_table[table][s] + (int)base_color * 8 + 4; |
| if (v < 0) |
| v = 0; |
| else if (v > 2047) |
| v = 2047; |
| |
| uint32_t err = abs(a - v); |
| if (err < best_s_err) |
| { |
| best_s_err = err; |
| best_s = s; |
| } |
| } |
| |
| results.m_selectors_temp[i] = static_cast<uint8_t>(best_s); |
| |
| total_err += best_s_err * best_s_err; |
| if (total_err >= best_err) |
| break; |
| } |
| |
| if (total_err < best_err) |
| { |
| best_err = total_err; |
| results.m_base = base_color; |
| results.m_multiplier = multiplier; |
| results.m_table = table; |
| results.m_selectors.swap(results.m_selectors_temp); |
| } |
| |
| } // table |
| |
| } // multiplier |
| |
| } // base_color |
| |
| return best_err; |
| } |
| |
| static void create_etc2_eac_r11_conversion_table() |
| { |
| FILE* pFile = nullptr; |
| fopen_s(&pFile, "basisu_decoder_tables_etc2_eac_r11.inc", "w"); |
| |
| for (uint32_t inten = 0; inten < 8; inten++) |
| { |
| for (uint32_t base = 0; base < 32; base++) |
| { |
| color32 block_colors[4]; |
| decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(base, base, base, 255), false), inten); |
| |
| fprintf(pFile, "{"); |
| |
| for (uint32_t sel_range = 0; sel_range < NUM_ETC2_EAC_SELECTOR_RANGES; sel_range++) |
| { |
| const uint32_t low_selector = s_etc2_eac_selector_ranges[sel_range].m_low; |
| const uint32_t high_selector = s_etc2_eac_selector_ranges[sel_range].m_high; |
| |
| // We have a ETC1 base color and intensity, and a used selector range from low_selector-high_selector. |
| // Now find the best ETC2 EAC R11 base/table/multiplier that fits these colors. |
| |
| uint8_t pixels[4]; |
| uint32_t num_pixels = 0; |
| for (uint32_t s = low_selector; s <= high_selector; s++) |
| pixels[num_pixels++] = block_colors[s].g; |
| |
| pack_eac_r11_results pack_results; |
| pack_eac_r11_exhaustive(pack_results, pixels, num_pixels); |
| |
| etc1_g_to_eac_conversion c; |
| |
| c.m_base = (uint8_t)pack_results.m_base; |
| c.m_table_mul = (uint8_t)(pack_results.m_table * 16 + pack_results.m_multiplier); |
| c.m_trans = 0; |
| |
| for (uint32_t s = 0; s < 4; s++) |
| { |
| if ((s < low_selector) || (s > high_selector)) |
| continue; |
| |
| uint32_t etc2_selector = pack_results.m_selectors[s - low_selector]; |
| |
| c.m_trans |= (etc2_selector << (s * 3)); |
| } |
| |
| fprintf(pFile, "{%u,%u,%u}", c.m_base, c.m_table_mul, c.m_trans); |
| if (sel_range < (NUM_ETC2_EAC_SELECTOR_RANGES - 1)) |
| fprintf(pFile, ","); |
| } |
| |
| fprintf(pFile, "},\n"); |
| } |
| } |
| |
| fclose(pFile); |
| } |
| #endif // BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES |
| |
| #if BASISD_WRITE_NEW_ASTC_TABLES |
| static void create_etc1_to_astc_conversion_table_0_47(); |
| static void create_etc1_to_astc_conversion_table_0_255(); |
| #endif |
| |
| #if BASISD_SUPPORT_ASTC |
| static void transcoder_init_astc(); |
| #endif |
| |
| #if BASISD_WRITE_NEW_BC7_MODE5_TABLES |
| static void create_etc1_to_bc7_m5_color_conversion_table(); |
| static void create_etc1_to_bc7_m5_alpha_conversion_table(); |
| #endif |
| |
| #if BASISD_SUPPORT_BC7_MODE5 |
| static void transcoder_init_bc7_mode5(); |
| #endif |
| |
| #if BASISD_WRITE_NEW_ATC_TABLES |
| static void create_etc1s_to_atc_conversion_tables(); |
| #endif |
| |
| #if BASISD_SUPPORT_ATC |
| static void transcoder_init_atc(); |
| #endif |
| |
| #if BASISD_SUPPORT_PVRTC2 |
| static void transcoder_init_pvrtc2(); |
| #endif |
| |
| #if BASISD_SUPPORT_UASTC |
| void uastc_init(); |
| #endif |
| |
| static bool g_transcoder_initialized; |
| |
| // Library global initialization. Requires ~9 milliseconds when compiled and executed natively on a Core i7 2.2 GHz. |
| // If this is too slow, these computed tables can easilky be moved to be compiled in. |
| void basisu_transcoder_init() |
| { |
| if (g_transcoder_initialized) |
| { |
| BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Called more than once\n"); |
| return; |
| } |
| |
| BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Initializing (this is not an error)\n"); |
| |
| #if BASISD_SUPPORT_UASTC |
| uastc_init(); |
| #endif |
| |
| #if BASISD_SUPPORT_ASTC |
| transcoder_init_astc(); |
| #endif |
| |
| #if BASISD_WRITE_NEW_ASTC_TABLES |
| create_etc1_to_astc_conversion_table_0_47(); |
| create_etc1_to_astc_conversion_table_0_255(); |
| exit(0); |
| #endif |
| |
| #if BASISD_WRITE_NEW_BC7_MODE5_TABLES |
| create_etc1_to_bc7_m5_color_conversion_table(); |
| create_etc1_to_bc7_m5_alpha_conversion_table(); |
| exit(0); |
| #endif |
| |
| #if BASISD_WRITE_NEW_DXT1_TABLES |
| create_etc1_to_dxt1_5_conversion_table(); |
| create_etc1_to_dxt1_6_conversion_table(); |
| exit(0); |
| #endif |
| |
| #if BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES |
| create_etc2_eac_a8_conversion_table(); |
| exit(0); |
| #endif |
| |
| #if BASISD_WRITE_NEW_ATC_TABLES |
| create_etc1s_to_atc_conversion_tables(); |
| exit(0); |
| #endif |
| |
| #if BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES |
| create_etc2_eac_r11_conversion_table(); |
| exit(0); |
| #endif |
| |
| #if BASISD_SUPPORT_DXT1 || BASISD_SUPPORT_UASTC |
| uint8_t bc1_expand5[32]; |
| for (int i = 0; i < 32; i++) |
| bc1_expand5[i] = static_cast<uint8_t>((i << 3) | (i >> 2)); |
| prepare_bc1_single_color_table(g_bc1_match5_equals_1, bc1_expand5, 32, 32, 1); |
| prepare_bc1_single_color_table(g_bc1_match5_equals_0, bc1_expand5, 1, 32, 0); |
| |
| uint8_t bc1_expand6[64]; |
| for (int i = 0; i < 64; i++) |
| bc1_expand6[i] = static_cast<uint8_t>((i << 2) | (i >> 4)); |
| prepare_bc1_single_color_table(g_bc1_match6_equals_1, bc1_expand6, 64, 64, 1); |
| prepare_bc1_single_color_table(g_bc1_match6_equals_0, bc1_expand6, 1, 64, 0); |
|