CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/ext/basis_universal/basisu_transcoder.cpp
Views: 1401
// basisu_transcoder.cpp1// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.1415#include "basisu_transcoder.h"16#include <limits.h>17#include "basisu_containers_impl.h"1819#ifndef BASISD_IS_BIG_ENDIAN20// TODO: This doesn't work on OSX. How can this be so difficult?21//#if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) || defined(BIG_ENDIAN)22// #define BASISD_IS_BIG_ENDIAN (1)23//#else24#define BASISD_IS_BIG_ENDIAN (0)25//#endif26#endif2728#ifndef BASISD_USE_UNALIGNED_WORD_READS29#ifdef __EMSCRIPTEN__30// Can't use unaligned loads/stores with WebAssembly.31#define BASISD_USE_UNALIGNED_WORD_READS (0)32#elif defined(_M_AMD64) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)33#define BASISD_USE_UNALIGNED_WORD_READS (1)34#else35#define BASISD_USE_UNALIGNED_WORD_READS (0)36#endif37#endif3839// Using unaligned loads and stores causes errors when using UBSan. Jam it off.40#if defined(__has_feature)41#if __has_feature(undefined_behavior_sanitizer)42#undef BASISD_USE_UNALIGNED_WORD_READS43#define BASISD_USE_UNALIGNED_WORD_READS 044#endif45#endif4647#define BASISD_SUPPORTED_BASIS_VERSION (0x13)4849#ifndef BASISD_SUPPORT_KTX250#error Must have defined BASISD_SUPPORT_KTX251#endif5253#ifndef BASISD_SUPPORT_KTX2_ZSTD54#error Must have defined BASISD_SUPPORT_KTX2_ZSTD55#endif5657// Set to 1 for fuzz testing. This will disable all CRC16 checks on headers and compressed data.58#ifndef BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS59#define BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS 060#endif6162#ifndef BASISD_SUPPORT_DXT163#define BASISD_SUPPORT_DXT1 164#endif6566#ifndef BASISD_SUPPORT_DXT5A67#define BASISD_SUPPORT_DXT5A 168#endif6970// Disable all BC7 transcoders if necessary (useful when cross compiling to Javascript)71#if defined(BASISD_SUPPORT_BC7) && !BASISD_SUPPORT_BC772#ifndef BASISD_SUPPORT_BC7_MODE573#define BASISD_SUPPORT_BC7_MODE5 074#endif75#endif // !BASISD_SUPPORT_BC77677// BC7 mode 5 supports both opaque and opaque+alpha textures, and uses less memory BC1.78#ifndef BASISD_SUPPORT_BC7_MODE579#define BASISD_SUPPORT_BC7_MODE5 180#endif8182#ifndef BASISD_SUPPORT_PVRTC183#define BASISD_SUPPORT_PVRTC1 184#endif8586#ifndef BASISD_SUPPORT_ETC2_EAC_A887#define BASISD_SUPPORT_ETC2_EAC_A8 188#endif8990// Set BASISD_SUPPORT_UASTC to 0 to completely disable support for transcoding UASTC files.91#ifndef BASISD_SUPPORT_UASTC92#define BASISD_SUPPORT_UASTC 193#endif9495#ifndef BASISD_SUPPORT_ASTC96#define BASISD_SUPPORT_ASTC 197#endif9899// Note that if BASISD_SUPPORT_ATC is enabled, BASISD_SUPPORT_DXT5A should also be enabled for alpha support.100#ifndef BASISD_SUPPORT_ATC101#define BASISD_SUPPORT_ATC 1102#endif103104// Support for ETC2 EAC R11 and ETC2 EAC RG11105#ifndef BASISD_SUPPORT_ETC2_EAC_RG11106#define BASISD_SUPPORT_ETC2_EAC_RG11 1107#endif108109// 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.110// This impacts grayscale and grayscale+alpha textures the most.111#ifndef BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY112#ifdef __EMSCRIPTEN__113// Let's assume size matters more than quality when compiling with emscripten.114#define BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY 0115#else116// Compiling native, so an extra 64K lookup table is probably acceptable.117#define BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY 1118#endif119#endif120121#ifndef BASISD_SUPPORT_FXT1122#define BASISD_SUPPORT_FXT1 1123#endif124125#ifndef BASISD_SUPPORT_PVRTC2126#define BASISD_SUPPORT_PVRTC2 1127#endif128129#if BASISD_SUPPORT_PVRTC2130#if !BASISD_SUPPORT_ATC131#error BASISD_SUPPORT_ATC must be 1 if BASISD_SUPPORT_PVRTC2 is 1132#endif133#endif134135#if BASISD_SUPPORT_ATC136#if !BASISD_SUPPORT_DXT5A137#error BASISD_SUPPORT_DXT5A must be 1 if BASISD_SUPPORT_ATC is 1138#endif139#endif140141#define BASISD_WRITE_NEW_BC7_MODE5_TABLES 0142#define BASISD_WRITE_NEW_DXT1_TABLES 0143#define BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES 0144#define BASISD_WRITE_NEW_ASTC_TABLES 0145#define BASISD_WRITE_NEW_ATC_TABLES 0146#define BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES 0147148#ifndef BASISD_ENABLE_DEBUG_FLAGS149#define BASISD_ENABLE_DEBUG_FLAGS 0150#endif151152// If KTX2 support is enabled, we may need Zstd for decompression of supercompressed UASTC files. Include this header.153#if BASISD_SUPPORT_KTX2154// If BASISD_SUPPORT_KTX2_ZSTD is 0, UASTC files compressed with Zstd cannot be loaded.155#if BASISD_SUPPORT_KTX2_ZSTD156// We only use two Zstd API's: ZSTD_decompress() and ZSTD_isError()157#include <zstd.h>158#endif159#endif160161namespace basisu162{163bool g_debug_printf;164165void enable_debug_printf(bool enabled)166{167g_debug_printf = enabled;168}169170void debug_printf(const char* pFmt, ...)171{172#if BASISU_FORCE_DEVEL_MESSAGES173g_debug_printf = true;174#endif175if (g_debug_printf)176{177va_list args;178va_start(args, pFmt);179vprintf(pFmt, args);180va_end(args);181}182}183} // namespace basisu184185namespace basist186{187188#if BASISD_ENABLE_DEBUG_FLAGS189static uint32_t g_debug_flags = 0;190#endif191192uint32_t get_debug_flags()193{194#if BASISD_ENABLE_DEBUG_FLAGS195return g_debug_flags;196#else197return 0;198#endif199}200201void set_debug_flags(uint32_t f)202{203BASISU_NOTE_UNUSED(f);204#if BASISD_ENABLE_DEBUG_FLAGS205g_debug_flags = f;206#endif207}208209inline uint16_t byteswap_uint16(uint16_t v)210{211return static_cast<uint16_t>((v >> 8) | (v << 8));212}213214static 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; }215static inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; }216static inline float saturate(float value) { return clampf(value, 0, 1.0f); }217218static inline uint8_t mul_8(uint32_t v, uint32_t q) { v = v * q + 128; return (uint8_t)((v + (v >> 8)) >> 8); }219220uint16_t crc16(const void* r, size_t size, uint16_t crc)221{222crc = ~crc;223224const uint8_t* p = static_cast<const uint8_t*>(r);225for (; size; --size)226{227const uint16_t q = *p++ ^ (crc >> 8);228uint16_t k = (q >> 4) ^ q;229crc = (((crc << 8) ^ k) ^ (k << 5)) ^ (k << 12);230}231232return static_cast<uint16_t>(~crc);233}234235enum etc_constants236{237cETC1BytesPerBlock = 8U,238239cETC1SelectorBits = 2U,240cETC1SelectorValues = 1U << cETC1SelectorBits,241cETC1SelectorMask = cETC1SelectorValues - 1U,242243cETC1BlockShift = 2U,244cETC1BlockSize = 1U << cETC1BlockShift,245246cETC1LSBSelectorIndicesBitOffset = 0,247cETC1MSBSelectorIndicesBitOffset = 16,248249cETC1FlipBitOffset = 32,250cETC1DiffBitOffset = 33,251252cETC1IntenModifierNumBits = 3,253cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,254cETC1RightIntenModifierTableBitOffset = 34,255cETC1LeftIntenModifierTableBitOffset = 37,256257// Base+Delta encoding (5 bit bases, 3 bit delta)258cETC1BaseColorCompNumBits = 5,259cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,260261cETC1DeltaColorCompNumBits = 3,262cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,263cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,264265cETC1BaseColor5RBitOffset = 59,266cETC1BaseColor5GBitOffset = 51,267cETC1BaseColor5BBitOffset = 43,268269cETC1DeltaColor3RBitOffset = 56,270cETC1DeltaColor3GBitOffset = 48,271cETC1DeltaColor3BBitOffset = 40,272273// Absolute (non-delta) encoding (two 4-bit per component bases)274cETC1AbsColorCompNumBits = 4,275cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,276277cETC1AbsColor4R1BitOffset = 60,278cETC1AbsColor4G1BitOffset = 52,279cETC1AbsColor4B1BitOffset = 44,280281cETC1AbsColor4R2BitOffset = 56,282cETC1AbsColor4G2BitOffset = 48,283cETC1AbsColor4B2BitOffset = 40,284285cETC1ColorDeltaMin = -4,286cETC1ColorDeltaMax = 3,287288// Delta3:289// 0 1 2 3 4 5 6 7290// 000 001 010 011 100 101 110 111291// 0 1 2 3 -4 -3 -2 -1292};293294#define DECLARE_ETC1_INTEN_TABLE(name, N) \295static const int name[cETC1IntenModifierValues][cETC1SelectorValues] = \296{ \297{ 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 }, \298{ 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 } \299};300301DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables, 1);302DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables16, 16);303DECLARE_ETC1_INTEN_TABLE(g_etc1_inten_tables48, 3 * 16);304305//const uint8_t g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };306const uint8_t g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 };307308static 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 };309310struct decoder_etc_block311{312// big endian uint64:313// bit ofs: 56 48 40 32 24 16 8 0314// byte ofs: b0, b1, b2, b3, b4, b5, b6, b7315union316{317uint64_t m_uint64;318319uint32_t m_uint32[2];320321uint8_t m_bytes[8];322323struct324{325signed m_dred2 : 3;326uint32_t m_red1 : 5;327328signed m_dgreen2 : 3;329uint32_t m_green1 : 5;330331signed m_dblue2 : 3;332uint32_t m_blue1 : 5;333334uint32_t m_flip : 1;335uint32_t m_diff : 1;336uint32_t m_cw2 : 3;337uint32_t m_cw1 : 3;338339uint32_t m_selectors;340} m_differential;341};342343inline void clear()344{345assert(sizeof(*this) == 8);346basisu::clear_obj(*this);347}348349inline void set_byte_bits(uint32_t ofs, uint32_t num, uint32_t bits)350{351assert((ofs + num) <= 64U);352assert(num && (num < 32U));353assert((ofs >> 3) == ((ofs + num - 1) >> 3));354assert(bits < (1U << num));355const uint32_t byte_ofs = 7 - (ofs >> 3);356const uint32_t byte_bit_ofs = ofs & 7;357const uint32_t mask = (1 << num) - 1;358m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);359m_bytes[byte_ofs] |= (bits << byte_bit_ofs);360}361362inline void set_flip_bit(bool flip)363{364m_bytes[3] &= ~1;365m_bytes[3] |= static_cast<uint8_t>(flip);366}367368inline void set_diff_bit(bool diff)369{370m_bytes[3] &= ~2;371m_bytes[3] |= (static_cast<uint32_t>(diff) << 1);372}373374// Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)375inline void set_inten_table(uint32_t subblock_id, uint32_t t)376{377assert(subblock_id < 2);378assert(t < 8);379const uint32_t ofs = subblock_id ? 2 : 5;380m_bytes[3] &= ~(7 << ofs);381m_bytes[3] |= (t << ofs);382}383384// Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.385inline void set_selector(uint32_t x, uint32_t y, uint32_t val)386{387assert((x | y | val) < 4);388const uint32_t bit_index = x * 4 + y;389390uint8_t* p = &m_bytes[7 - (bit_index >> 3)];391392const uint32_t byte_bit_ofs = bit_index & 7;393const uint32_t mask = 1 << byte_bit_ofs;394395static const uint8_t s_selector_index_to_etc1[4] = { 3, 2, 0, 1 };396const uint32_t etc1_val = s_selector_index_to_etc1[val];397398const uint32_t lsb = etc1_val & 1;399const uint32_t msb = etc1_val >> 1;400401p[0] &= ~mask;402p[0] |= (lsb << byte_bit_ofs);403404p[-2] &= ~mask;405p[-2] |= (msb << byte_bit_ofs);406}407408// Returned encoded selector value ranges from 0-3 (this is NOT a direct index into g_etc1_inten_tables, see get_selector())409inline uint32_t get_raw_selector(uint32_t x, uint32_t y) const410{411assert((x | y) < 4);412413const uint32_t bit_index = x * 4 + y;414const uint32_t byte_bit_ofs = bit_index & 7;415const uint8_t* p = &m_bytes[7 - (bit_index >> 3)];416const uint32_t lsb = (p[0] >> byte_bit_ofs) & 1;417const uint32_t msb = (p[-2] >> byte_bit_ofs) & 1;418const uint32_t val = lsb | (msb << 1);419420return val;421}422423// Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.424inline uint32_t get_selector(uint32_t x, uint32_t y) const425{426static const uint8_t s_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };427return s_etc1_to_selector_index[get_raw_selector(x, y)];428}429430inline void set_raw_selector_bits(uint32_t bits)431{432m_bytes[4] = static_cast<uint8_t>(bits);433m_bytes[5] = static_cast<uint8_t>(bits >> 8);434m_bytes[6] = static_cast<uint8_t>(bits >> 16);435m_bytes[7] = static_cast<uint8_t>(bits >> 24);436}437438inline bool are_all_selectors_the_same() const439{440uint32_t v = *reinterpret_cast<const uint32_t*>(&m_bytes[4]);441442if ((v == 0xFFFFFFFF) || (v == 0xFFFF) || (!v) || (v == 0xFFFF0000))443return true;444445return false;446}447448inline void set_raw_selector_bits(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3)449{450m_bytes[4] = byte0;451m_bytes[5] = byte1;452m_bytes[6] = byte2;453m_bytes[7] = byte3;454}455456inline uint32_t get_raw_selector_bits() const457{458return m_bytes[4] | (m_bytes[5] << 8) | (m_bytes[6] << 16) | (m_bytes[7] << 24);459}460461inline void set_base4_color(uint32_t idx, uint16_t c)462{463if (idx)464{465set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);466set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);467set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);468}469else470{471set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);472set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);473set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);474}475}476477inline void set_base5_color(uint16_t c)478{479set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);480set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);481set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);482}483484void set_delta3_color(uint16_t c)485{486set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);487set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);488set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);489}490491void set_block_color4(const color32& c0_unscaled, const color32& c1_unscaled)492{493set_diff_bit(false);494495set_base4_color(0, pack_color4(c0_unscaled, false));496set_base4_color(1, pack_color4(c1_unscaled, false));497}498499void set_block_color5(const color32& c0_unscaled, const color32& c1_unscaled)500{501set_diff_bit(true);502503set_base5_color(pack_color5(c0_unscaled, false));504505int dr = c1_unscaled.r - c0_unscaled.r;506int dg = c1_unscaled.g - c0_unscaled.g;507int db = c1_unscaled.b - c0_unscaled.b;508509set_delta3_color(pack_delta3(dr, dg, db));510}511512bool set_block_color5_check(const color32& c0_unscaled, const color32& c1_unscaled)513{514set_diff_bit(true);515516set_base5_color(pack_color5(c0_unscaled, false));517518int dr = c1_unscaled.r - c0_unscaled.r;519int dg = c1_unscaled.g - c0_unscaled.g;520int db = c1_unscaled.b - c0_unscaled.b;521522if (((dr < cETC1ColorDeltaMin) || (dr > cETC1ColorDeltaMax)) ||523((dg < cETC1ColorDeltaMin) || (dg > cETC1ColorDeltaMax)) ||524((db < cETC1ColorDeltaMin) || (db > cETC1ColorDeltaMax)))525return false;526527set_delta3_color(pack_delta3(dr, dg, db));528529return true;530}531532inline uint32_t get_byte_bits(uint32_t ofs, uint32_t num) const533{534assert((ofs + num) <= 64U);535assert(num && (num <= 8U));536assert((ofs >> 3) == ((ofs + num - 1) >> 3));537const uint32_t byte_ofs = 7 - (ofs >> 3);538const uint32_t byte_bit_ofs = ofs & 7;539return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);540}541542inline uint16_t get_base5_color() const543{544const uint32_t r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);545const uint32_t g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);546const uint32_t b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);547return static_cast<uint16_t>(b | (g << 5U) | (r << 10U));548}549550inline uint16_t get_base4_color(uint32_t idx) const551{552uint32_t r, g, b;553if (idx)554{555r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);556g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);557b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);558}559else560{561r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);562g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);563b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);564}565return static_cast<uint16_t>(b | (g << 4U) | (r << 8U));566}567568inline color32 get_base5_color_unscaled() const569{570return color32(m_differential.m_red1, m_differential.m_green1, m_differential.m_blue1, 255);571}572573inline bool get_flip_bit() const574{575return (m_bytes[3] & 1) != 0;576}577578inline bool get_diff_bit() const579{580return (m_bytes[3] & 2) != 0;581}582583inline uint32_t get_inten_table(uint32_t subblock_id) const584{585assert(subblock_id < 2);586const uint32_t ofs = subblock_id ? 2 : 5;587return (m_bytes[3] >> ofs) & 7;588}589590inline uint16_t get_delta3_color() const591{592const uint32_t r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);593const uint32_t g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);594const uint32_t b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);595return static_cast<uint16_t>(b | (g << 3U) | (r << 6U));596}597598void get_block_colors(color32* pBlock_colors, uint32_t subblock_index) const599{600color32 b;601602if (get_diff_bit())603{604if (subblock_index)605unpack_color5(b, get_base5_color(), get_delta3_color(), true, 255);606else607unpack_color5(b, get_base5_color(), true);608}609else610{611b = unpack_color4(get_base4_color(subblock_index), true, 255);612}613614const int* pInten_table = g_etc1_inten_tables[get_inten_table(subblock_index)];615616pBlock_colors[0].set_noclamp_rgba(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255);617pBlock_colors[1].set_noclamp_rgba(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255);618pBlock_colors[2].set_noclamp_rgba(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255);619pBlock_colors[3].set_noclamp_rgba(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255);620}621622static uint16_t pack_color4(const color32& color, bool scaled, uint32_t bias = 127U)623{624return pack_color4(color.r, color.g, color.b, scaled, bias);625}626627static uint16_t pack_color4(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias = 127U)628{629if (scaled)630{631r = (r * 15U + bias) / 255U;632g = (g * 15U + bias) / 255U;633b = (b * 15U + bias) / 255U;634}635636r = basisu::minimum(r, 15U);637g = basisu::minimum(g, 15U);638b = basisu::minimum(b, 15U);639640return static_cast<uint16_t>(b | (g << 4U) | (r << 8U));641}642643static uint16_t pack_color5(const color32& color, bool scaled, uint32_t bias = 127U)644{645return pack_color5(color.r, color.g, color.b, scaled, bias);646}647648static uint16_t pack_color5(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias = 127U)649{650if (scaled)651{652r = (r * 31U + bias) / 255U;653g = (g * 31U + bias) / 255U;654b = (b * 31U + bias) / 255U;655}656657r = basisu::minimum(r, 31U);658g = basisu::minimum(g, 31U);659b = basisu::minimum(b, 31U);660661return static_cast<uint16_t>(b | (g << 5U) | (r << 10U));662}663664uint16_t pack_delta3(const color32& color)665{666return pack_delta3(color.r, color.g, color.b);667}668669uint16_t pack_delta3(int r, int g, int b)670{671assert((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax));672assert((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax));673assert((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax));674if (r < 0) r += 8;675if (g < 0) g += 8;676if (b < 0) b += 8;677return static_cast<uint16_t>(b | (g << 3) | (r << 6));678}679680static void unpack_delta3(int& r, int& g, int& b, uint16_t packed_delta3)681{682r = (packed_delta3 >> 6) & 7;683g = (packed_delta3 >> 3) & 7;684b = packed_delta3 & 7;685if (r >= 4) r -= 8;686if (g >= 4) g -= 8;687if (b >= 4) b -= 8;688}689690static color32 unpack_color5(uint16_t packed_color5, bool scaled, uint32_t alpha)691{692uint32_t b = packed_color5 & 31U;693uint32_t g = (packed_color5 >> 5U) & 31U;694uint32_t r = (packed_color5 >> 10U) & 31U;695696if (scaled)697{698b = (b << 3U) | (b >> 2U);699g = (g << 3U) | (g >> 2U);700r = (r << 3U) | (r >> 2U);701}702703assert(alpha <= 255);704705return color32(cNoClamp, r, g, b, alpha);706}707708static void unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color5, bool scaled)709{710color32 c(unpack_color5(packed_color5, scaled, 0));711r = c.r;712g = c.g;713b = c.b;714}715716static void unpack_color5(color32& result, uint16_t packed_color5, bool scaled)717{718result = unpack_color5(packed_color5, scaled, 255);719}720721static bool unpack_color5(color32& result, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha)722{723int dr, dg, db;724unpack_delta3(dr, dg, db, packed_delta3);725726int r = ((packed_color5 >> 10U) & 31U) + dr;727int g = ((packed_color5 >> 5U) & 31U) + dg;728int b = (packed_color5 & 31U) + db;729730bool success = true;731if (static_cast<uint32_t>(r | g | b) > 31U)732{733success = false;734r = basisu::clamp<int>(r, 0, 31);735g = basisu::clamp<int>(g, 0, 31);736b = basisu::clamp<int>(b, 0, 31);737}738739if (scaled)740{741b = (b << 3U) | (b >> 2U);742g = (g << 3U) | (g >> 2U);743r = (r << 3U) | (r >> 2U);744}745746result.set_noclamp_rgba(r, g, b, basisu::minimum(alpha, 255U));747return success;748}749750static color32 unpack_color4(uint16_t packed_color4, bool scaled, uint32_t alpha)751{752uint32_t b = packed_color4 & 15U;753uint32_t g = (packed_color4 >> 4U) & 15U;754uint32_t r = (packed_color4 >> 8U) & 15U;755756if (scaled)757{758b = (b << 4U) | b;759g = (g << 4U) | g;760r = (r << 4U) | r;761}762763return color32(cNoClamp, r, g, b, basisu::minimum(alpha, 255U));764}765766static void unpack_color4(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color4, bool scaled)767{768color32 c(unpack_color4(packed_color4, scaled, 0));769r = c.r;770g = c.g;771b = c.b;772}773774static void get_diff_subblock_colors(color32* pDst, uint16_t packed_color5, uint32_t table_idx)775{776assert(table_idx < cETC1IntenModifierValues);777const int* pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];778779uint32_t r, g, b;780unpack_color5(r, g, b, packed_color5, true);781782const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);783784const int y0 = pInten_modifer_table[0];785pDst[0].set(clamp255(ir + y0), clamp255(ig + y0), clamp255(ib + y0), 255);786787const int y1 = pInten_modifer_table[1];788pDst[1].set(clamp255(ir + y1), clamp255(ig + y1), clamp255(ib + y1), 255);789790const int y2 = pInten_modifer_table[2];791pDst[2].set(clamp255(ir + y2), clamp255(ig + y2), clamp255(ib + y2), 255);792793const int y3 = pInten_modifer_table[3];794pDst[3].set(clamp255(ir + y3), clamp255(ig + y3), clamp255(ib + y3), 255);795}796797static int clamp255(int x)798{799if (x & 0xFFFFFF00)800{801if (x < 0)802x = 0;803else if (x > 255)804x = 255;805}806807return x;808}809810static void get_block_colors5(color32* pBlock_colors, const color32& base_color5, uint32_t inten_table)811{812color32 b(base_color5);813814b.r = (b.r << 3) | (b.r >> 2);815b.g = (b.g << 3) | (b.g >> 2);816b.b = (b.b << 3) | (b.b >> 2);817818const int* pInten_table = g_etc1_inten_tables[inten_table];819820pBlock_colors[0].set(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255);821pBlock_colors[1].set(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255);822pBlock_colors[2].set(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255);823pBlock_colors[3].set(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255);824}825826static void get_block_color5(const color32& base_color5, uint32_t inten_table, uint32_t index, uint32_t& r, uint32_t &g, uint32_t &b)827{828assert(index < 4);829830uint32_t br = (base_color5.r << 3) | (base_color5.r >> 2);831uint32_t bg = (base_color5.g << 3) | (base_color5.g >> 2);832uint32_t bb = (base_color5.b << 3) | (base_color5.b >> 2);833834const int* pInten_table = g_etc1_inten_tables[inten_table];835836r = clamp255(br + pInten_table[index]);837g = clamp255(bg + pInten_table[index]);838b = clamp255(bb + pInten_table[index]);839}840841static void get_block_color5_r(const color32& base_color5, uint32_t inten_table, uint32_t index, uint32_t &r)842{843assert(index < 4);844845uint32_t br = (base_color5.r << 3) | (base_color5.r >> 2);846847const int* pInten_table = g_etc1_inten_tables[inten_table];848849r = clamp255(br + pInten_table[index]);850}851852static void get_block_colors5_g(int* pBlock_colors, const color32& base_color5, uint32_t inten_table)853{854const int g = (base_color5.g << 3) | (base_color5.g >> 2);855856const int* pInten_table = g_etc1_inten_tables[inten_table];857858pBlock_colors[0] = clamp255(g + pInten_table[0]);859pBlock_colors[1] = clamp255(g + pInten_table[1]);860pBlock_colors[2] = clamp255(g + pInten_table[2]);861pBlock_colors[3] = clamp255(g + pInten_table[3]);862}863864static void get_block_colors5_bounds(color32* pBlock_colors, const color32& base_color5, uint32_t inten_table, uint32_t l = 0, uint32_t h = 3)865{866color32 b(base_color5);867868b.r = (b.r << 3) | (b.r >> 2);869b.g = (b.g << 3) | (b.g >> 2);870b.b = (b.b << 3) | (b.b >> 2);871872const int* pInten_table = g_etc1_inten_tables[inten_table];873874pBlock_colors[0].set(clamp255(b.r + pInten_table[l]), clamp255(b.g + pInten_table[l]), clamp255(b.b + pInten_table[l]), 255);875pBlock_colors[1].set(clamp255(b.r + pInten_table[h]), clamp255(b.g + pInten_table[h]), clamp255(b.b + pInten_table[h]), 255);876}877878static 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)879{880color32 b(base_color5);881882b.g = (b.g << 3) | (b.g >> 2);883884const int* pInten_table = g_etc1_inten_tables[inten_table];885886pBlock_colors[0] = clamp255(b.g + pInten_table[l]);887pBlock_colors[1] = clamp255(b.g + pInten_table[h]);888}889};890891enum dxt_constants892{893cDXT1SelectorBits = 2U, cDXT1SelectorValues = 1U << cDXT1SelectorBits, cDXT1SelectorMask = cDXT1SelectorValues - 1U,894cDXT5SelectorBits = 3U, cDXT5SelectorValues = 1U << cDXT5SelectorBits, cDXT5SelectorMask = cDXT5SelectorValues - 1U,895};896897static const uint8_t g_etc1_x_selector_unpack[4][256] =898{899{9000, 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,9010, 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,9020, 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,9030, 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,9040, 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,9050, 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,9060, 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,9070, 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,908},909{9100, 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,9112, 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,9120, 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,9132, 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,9140, 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,9152, 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,9160, 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,9172, 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,918},919920{9210, 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,9220, 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,9232, 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,9242, 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,9250, 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,9260, 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,9272, 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,9282, 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,929},930931{9320, 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,9330, 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,9340, 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,9350, 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,9362, 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,9372, 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,9382, 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,9392, 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,940}941};942943struct dxt1_block944{945enum { cTotalEndpointBytes = 2, cTotalSelectorBytes = 4 };946947uint8_t m_low_color[cTotalEndpointBytes];948uint8_t m_high_color[cTotalEndpointBytes];949uint8_t m_selectors[cTotalSelectorBytes];950951inline void clear() { basisu::clear_obj(*this); }952953inline uint32_t get_high_color() const { return m_high_color[0] | (m_high_color[1] << 8U); }954inline uint32_t get_low_color() const { return m_low_color[0] | (m_low_color[1] << 8U); }955inline 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); }956inline 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); }957inline uint32_t get_selector(uint32_t x, uint32_t y) const { assert((x < 4U) && (y < 4U)); return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask; }958inline 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)); }959960static uint16_t pack_color(const color32& color, bool scaled, uint32_t bias = 127U)961{962uint32_t r = color.r, g = color.g, b = color.b;963if (scaled)964{965r = (r * 31U + bias) / 255U;966g = (g * 63U + bias) / 255U;967b = (b * 31U + bias) / 255U;968}969return static_cast<uint16_t>(basisu::minimum(b, 31U) | (basisu::minimum(g, 63U) << 5U) | (basisu::minimum(r, 31U) << 11U));970}971972static uint16_t pack_unscaled_color(uint32_t r, uint32_t g, uint32_t b) { return static_cast<uint16_t>(b | (g << 5U) | (r << 11U)); }973};974975struct dxt_selector_range976{977uint32_t m_low;978uint32_t m_high;979};980981struct etc1_to_dxt1_56_solution982{983uint8_t m_lo;984uint8_t m_hi;985uint16_t m_err;986};987988#if BASISD_SUPPORT_DXT1989static dxt_selector_range g_etc1_to_dxt1_selector_ranges[] =990{991{ 0, 3 },992993{ 1, 3 },994{ 0, 2 },995996{ 1, 2 },997998{ 2, 3 },999{ 0, 1 },1000};10011002const uint32_t NUM_ETC1_TO_DXT1_SELECTOR_RANGES = sizeof(g_etc1_to_dxt1_selector_ranges) / sizeof(g_etc1_to_dxt1_selector_ranges[0]);10031004static uint32_t g_etc1_to_dxt1_selector_range_index[4][4];10051006const uint32_t NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS = 10;1007static const uint8_t g_etc1_to_dxt1_selector_mappings[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][4] =1008{1009{ 0, 0, 1, 1 },1010{ 0, 0, 1, 2 },1011{ 0, 0, 1, 3 },1012{ 0, 0, 2, 3 },1013{ 0, 1, 1, 1 },1014{ 0, 1, 2, 2 },1015{ 0, 1, 2, 3 },1016{ 0, 2, 3, 3 },1017{ 1, 2, 2, 2 },1018{ 1, 2, 3, 3 },1019};10201021static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256];1022static uint8_t g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS][256];10231024static 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] = {1025#include "basisu_transcoder_tables_dxt1_6.inc"1026};10271028static 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] = {1029#include "basisu_transcoder_tables_dxt1_5.inc"1030};1031#endif // BASISD_SUPPORT_DXT110321033#if BASISD_SUPPORT_DXT1 || BASISD_SUPPORT_UASTC1034// First saw the idea for optimal BC1 single-color block encoding using lookup tables in ryg_dxt.1035struct bc1_match_entry1036{1037uint8_t m_hi;1038uint8_t m_lo;1039};1040static bc1_match_entry g_bc1_match5_equals_1[256], g_bc1_match6_equals_1[256]; // selector 1, allow equals hi/lo1041static bc1_match_entry g_bc1_match5_equals_0[256], g_bc1_match6_equals_0[256]; // selector 0, allow equals hi/lo10421043static void prepare_bc1_single_color_table(bc1_match_entry* pTable, const uint8_t* pExpand, int size0, int size1, int sel)1044{1045for (int i = 0; i < 256; i++)1046{1047int lowest_e = 256;1048for (int lo = 0; lo < size0; lo++)1049{1050for (int hi = 0; hi < size1; hi++)1051{1052const int lo_e = pExpand[lo], hi_e = pExpand[hi];1053int e;10541055if (sel == 1)1056{1057// Selector 11058e = basisu::iabs(((hi_e * 2 + lo_e) / 3) - i);1059e += (basisu::iabs(hi_e - lo_e) * 3) / 100;1060}1061else1062{1063assert(sel == 0);10641065// Selector 01066e = basisu::iabs(hi_e - i);1067}10681069if (e < lowest_e)1070{1071pTable[i].m_hi = static_cast<uint8_t>(hi);1072pTable[i].m_lo = static_cast<uint8_t>(lo);10731074lowest_e = e;1075}10761077} // hi1078} // lo1079}1080}1081#endif10821083#if BASISD_WRITE_NEW_DXT1_TABLES1084static void create_etc1_to_dxt1_5_conversion_table()1085{1086FILE* pFile = nullptr;1087fopen_s(&pFile, "basisu_transcoder_tables_dxt1_5.inc", "w");10881089uint32_t n = 0;10901091for (int inten = 0; inten < 8; inten++)1092{1093for (uint32_t g = 0; g < 32; g++)1094{1095color32 block_colors[4];1096decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);10971098for (uint32_t sr = 0; sr < NUM_ETC1_TO_DXT1_SELECTOR_RANGES; sr++)1099{1100const uint32_t low_selector = g_etc1_to_dxt1_selector_ranges[sr].m_low;1101const uint32_t high_selector = g_etc1_to_dxt1_selector_ranges[sr].m_high;11021103for (uint32_t m = 0; m < NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS; m++)1104{1105uint32_t best_lo = 0;1106uint32_t best_hi = 0;1107uint64_t best_err = UINT64_MAX;11081109for (uint32_t hi = 0; hi <= 31; hi++)1110{1111for (uint32_t lo = 0; lo <= 31; lo++)1112{1113//if (lo == hi) continue;11141115uint32_t colors[4];11161117colors[0] = (lo << 3) | (lo >> 2);1118colors[3] = (hi << 3) | (hi >> 2);11191120colors[1] = (colors[0] * 2 + colors[3]) / 3;1121colors[2] = (colors[3] * 2 + colors[0]) / 3;11221123uint64_t total_err = 0;11241125for (uint32_t s = low_selector; s <= high_selector; s++)1126{1127int err = block_colors[s].g - colors[g_etc1_to_dxt1_selector_mappings[m][s]];11281129total_err += err * err;1130}11311132if (total_err < best_err)1133{1134best_err = total_err;1135best_lo = lo;1136best_hi = hi;1137}1138}1139}11401141assert(best_err <= 0xFFFF);11421143//table[g + inten * 32].m_solutions[sr][m].m_lo = static_cast<uint8_t>(best_lo);1144//table[g + inten * 32].m_solutions[sr][m].m_hi = static_cast<uint8_t>(best_hi);1145//table[g + inten * 32].m_solutions[sr][m].m_err = static_cast<uint16_t>(best_err);11461147//assert(best_lo != best_hi);1148fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);1149n++;1150if ((n & 31) == 31)1151fprintf(pFile, "\n");1152} // m1153} // sr1154} // g1155} // inten11561157fclose(pFile);1158}11591160static void create_etc1_to_dxt1_6_conversion_table()1161{1162FILE* pFile = nullptr;1163fopen_s(&pFile, "basisu_transcoder_tables_dxt1_6.inc", "w");11641165uint32_t n = 0;11661167for (int inten = 0; inten < 8; inten++)1168{1169for (uint32_t g = 0; g < 32; g++)1170{1171color32 block_colors[4];1172decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);11731174for (uint32_t sr = 0; sr < NUM_ETC1_TO_DXT1_SELECTOR_RANGES; sr++)1175{1176const uint32_t low_selector = g_etc1_to_dxt1_selector_ranges[sr].m_low;1177const uint32_t high_selector = g_etc1_to_dxt1_selector_ranges[sr].m_high;11781179for (uint32_t m = 0; m < NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS; m++)1180{1181uint32_t best_lo = 0;1182uint32_t best_hi = 0;1183uint64_t best_err = UINT64_MAX;11841185for (uint32_t hi = 0; hi <= 63; hi++)1186{1187for (uint32_t lo = 0; lo <= 63; lo++)1188{1189//if (lo == hi) continue;11901191uint32_t colors[4];11921193colors[0] = (lo << 2) | (lo >> 4);1194colors[3] = (hi << 2) | (hi >> 4);11951196colors[1] = (colors[0] * 2 + colors[3]) / 3;1197colors[2] = (colors[3] * 2 + colors[0]) / 3;11981199uint64_t total_err = 0;12001201for (uint32_t s = low_selector; s <= high_selector; s++)1202{1203int err = block_colors[s].g - colors[g_etc1_to_dxt1_selector_mappings[m][s]];12041205total_err += err * err;1206}12071208if (total_err < best_err)1209{1210best_err = total_err;1211best_lo = lo;1212best_hi = hi;1213}1214}1215}12161217assert(best_err <= 0xFFFF);12181219//table[g + inten * 32].m_solutions[sr][m].m_lo = static_cast<uint8_t>(best_lo);1220//table[g + inten * 32].m_solutions[sr][m].m_hi = static_cast<uint8_t>(best_hi);1221//table[g + inten * 32].m_solutions[sr][m].m_err = static_cast<uint16_t>(best_err);12221223//assert(best_lo != best_hi);1224fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);1225n++;1226if ((n & 31) == 31)1227fprintf(pFile, "\n");12281229} // m1230} // sr1231} // g1232} // inten12331234fclose(pFile);1235}1236#endif123712381239#if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG111240static const int8_t g_eac_modifier_table[16][8] =1241{1242{ -3, -6, -9, -15, 2, 5, 8, 14 },1243{ -3, -7, -10, -13, 2, 6, 9, 12 },1244{ -2, -5, -8, -13, 1, 4, 7, 12 },1245{ -2, -4, -6, -13, 1, 3, 5, 12 },1246{ -3, -6, -8, -12, 2, 5, 7, 11 },1247{ -3, -7, -9, -11, 2, 6, 8, 10 },1248{ -4, -7, -8, -11, 3, 6, 7, 10 },1249{ -3, -5, -8, -11, 2, 4, 7, 10 },12501251{ -2, -6, -8, -10, 1, 5, 7, 9 },1252{ -2, -5, -8, -10, 1, 4, 7, 9 },1253{ -2, -4, -8, -10, 1, 3, 7, 9 },1254{ -2, -5, -7, -10, 1, 4, 6, 9 },1255{ -3, -4, -7, -10, 2, 3, 6, 9 },1256{ -1, -2, -3, -10, 0, 1, 2, 9 }, // entry 131257{ -4, -6, -8, -9, 3, 5, 7, 8 },1258{ -3, -5, -7, -9, 2, 4, 6, 8 }1259};12601261// Used by ETC2 EAC A8 and ETC2 EAC R11/RG11.1262struct eac_block1263{1264uint16_t m_base : 8;12651266uint16_t m_table : 4;1267uint16_t m_multiplier : 4;12681269uint8_t m_selectors[6];12701271uint32_t get_selector(uint32_t x, uint32_t y) const1272{1273assert((x < 4) && (y < 4));12741275const uint32_t ofs = 45 - (y + x * 4) * 3;12761277const uint64_t pixels = get_selector_bits();12781279return (pixels >> ofs) & 7;1280}12811282void set_selector(uint32_t x, uint32_t y, uint32_t s)1283{1284assert((x < 4) && (y < 4) && (s < 8));12851286const uint32_t ofs = 45 - (y + x * 4) * 3;12871288uint64_t pixels = get_selector_bits();12891290pixels &= ~(7ULL << ofs);1291pixels |= (static_cast<uint64_t>(s) << ofs);12921293set_selector_bits(pixels);1294}12951296uint64_t get_selector_bits() const1297{1298uint64_t pixels = ((uint64_t)m_selectors[0] << 40) | ((uint64_t)m_selectors[1] << 32) |1299((uint64_t)m_selectors[2] << 24) |1300((uint64_t)m_selectors[3] << 16) | ((uint64_t)m_selectors[4] << 8) | m_selectors[5];1301return pixels;1302}13031304void set_selector_bits(uint64_t pixels)1305{1306m_selectors[0] = (uint8_t)(pixels >> 40);1307m_selectors[1] = (uint8_t)(pixels >> 32);1308m_selectors[2] = (uint8_t)(pixels >> 24);1309m_selectors[3] = (uint8_t)(pixels >> 16);1310m_selectors[4] = (uint8_t)(pixels >> 8);1311m_selectors[5] = (uint8_t)(pixels);1312}1313};13141315#endif // #if BASISD_SUPPORT_UASTC BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG1113161317#if BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG111318static const dxt_selector_range s_etc2_eac_selector_ranges[] =1319{1320{ 0, 3 },13211322{ 1, 3 },1323{ 0, 2 },13241325{ 1, 2 },1326};13271328const uint32_t NUM_ETC2_EAC_SELECTOR_RANGES = sizeof(s_etc2_eac_selector_ranges) / sizeof(s_etc2_eac_selector_ranges[0]);13291330struct etc1_g_to_eac_conversion1331{1332uint8_t m_base;1333uint8_t m_table_mul; // mul*16+table1334uint16_t m_trans; // translates ETC1 selectors to ETC2_EAC_A81335};1336#endif // BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_ETC2_EAC_RG1113371338#if BASISD_SUPPORT_ETC2_EAC_A813391340#if BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES1341struct pack_eac_a8_results1342{1343uint32_t m_base;1344uint32_t m_table;1345uint32_t m_multiplier;1346basisu::vector<uint8_t> m_selectors;1347basisu::vector<uint8_t> m_selectors_temp;1348};13491350static uint64_t pack_eac_a8_exhaustive(pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels)1351{1352results.m_selectors.resize(num_pixels);1353results.m_selectors_temp.resize(num_pixels);13541355uint64_t best_err = UINT64_MAX;13561357for (uint32_t base_color = 0; base_color < 256; base_color++)1358{1359for (uint32_t multiplier = 1; multiplier < 16; multiplier++)1360{1361for (uint32_t table = 0; table < 16; table++)1362{1363uint64_t total_err = 0;13641365for (uint32_t i = 0; i < num_pixels; i++)1366{1367const int a = pPixels[i];13681369uint32_t best_s_err = UINT32_MAX;1370uint32_t best_s = 0;1371for (uint32_t s = 0; s < 8; s++)1372{1373int v = (int)multiplier * g_eac_modifier_table[table][s] + (int)base_color;1374if (v < 0)1375v = 0;1376else if (v > 255)1377v = 255;13781379uint32_t err = abs(a - v);1380if (err < best_s_err)1381{1382best_s_err = err;1383best_s = s;1384}1385}13861387results.m_selectors_temp[i] = static_cast<uint8_t>(best_s);13881389total_err += best_s_err * best_s_err;1390if (total_err >= best_err)1391break;1392}13931394if (total_err < best_err)1395{1396best_err = total_err;1397results.m_base = base_color;1398results.m_multiplier = multiplier;1399results.m_table = table;1400results.m_selectors.swap(results.m_selectors_temp);1401}14021403} // table14041405} // multiplier14061407} // base_color14081409return best_err;1410}1411#endif // BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES14121413static1414#if !BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES1415const1416#endif1417etc1_g_to_eac_conversion s_etc1_g_to_etc2_a8[32 * 8][NUM_ETC2_EAC_SELECTOR_RANGES] =1418{1419{ { 0,1,3328 },{ 0,1,3328 },{ 0,1,256 },{ 0,1,256 } },1420{ { 0,226,3936 },{ 0,226,3936 },{ 0,81,488 },{ 0,81,488 } },1421{ { 6,178,4012 },{ 6,178,4008 },{ 0,146,501 },{ 0,130,496 } },1422{ { 14,178,4012 },{ 14,178,4008 },{ 8,146,501 },{ 6,82,496 } },1423{ { 23,178,4012 },{ 23,178,4008 },{ 17,146,501 },{ 3,228,496 } },1424{ { 31,178,4012 },{ 31,178,4008 },{ 25,146,501 },{ 11,228,496 } },1425{ { 39,178,4012 },{ 39,178,4008 },{ 33,146,501 },{ 19,228,496 } },1426{ { 47,178,4012 },{ 47,178,4008 },{ 41,146,501 },{ 27,228,496 } },1427{ { 56,178,4012 },{ 56,178,4008 },{ 50,146,501 },{ 36,228,496 } },1428{ { 64,178,4012 },{ 64,178,4008 },{ 58,146,501 },{ 44,228,496 } },1429{ { 72,178,4012 },{ 72,178,4008 },{ 66,146,501 },{ 52,228,496 } },1430{ { 80,178,4012 },{ 80,178,4008 },{ 74,146,501 },{ 60,228,496 } },1431{ { 89,178,4012 },{ 89,178,4008 },{ 83,146,501 },{ 69,228,496 } },1432{ { 97,178,4012 },{ 97,178,4008 },{ 91,146,501 },{ 77,228,496 } },1433{ { 105,178,4012 },{ 105,178,4008 },{ 99,146,501 },{ 85,228,496 } },1434{ { 113,178,4012 },{ 113,178,4008 },{ 107,146,501 },{ 93,228,496 } },1435{ { 122,178,4012 },{ 122,178,4008 },{ 116,146,501 },{ 102,228,496 } },1436{ { 130,178,4012 },{ 130,178,4008 },{ 124,146,501 },{ 110,228,496 } },1437{ { 138,178,4012 },{ 138,178,4008 },{ 132,146,501 },{ 118,228,496 } },1438{ { 146,178,4012 },{ 146,178,4008 },{ 140,146,501 },{ 126,228,496 } },1439{ { 155,178,4012 },{ 155,178,4008 },{ 149,146,501 },{ 135,228,496 } },1440{ { 163,178,4012 },{ 163,178,4008 },{ 157,146,501 },{ 143,228,496 } },1441{ { 171,178,4012 },{ 171,178,4008 },{ 165,146,501 },{ 151,228,496 } },1442{ { 179,178,4012 },{ 179,178,4008 },{ 173,146,501 },{ 159,228,496 } },1443{ { 188,178,4012 },{ 188,178,4008 },{ 182,146,501 },{ 168,228,496 } },1444{ { 196,178,4012 },{ 196,178,4008 },{ 190,146,501 },{ 176,228,496 } },1445{ { 204,178,4012 },{ 204,178,4008 },{ 198,146,501 },{ 184,228,496 } },1446{ { 212,178,4012 },{ 212,178,4008 },{ 206,146,501 },{ 192,228,496 } },1447{ { 221,178,4012 },{ 221,178,4008 },{ 215,146,501 },{ 201,228,496 } },1448{ { 229,178,4012 },{ 229,178,4008 },{ 223,146,501 },{ 209,228,496 } },1449{ { 235,66,4012 },{ 221,100,4008 },{ 231,146,501 },{ 217,228,496 } },1450{ { 211,102,4085 },{ 118,31,4080 },{ 211,102,501 },{ 118,31,496 } },1451{ { 1,2,3328 },{ 1,2,3328 },{ 0,1,320 },{ 0,1,320 } },1452{ { 7,162,3905 },{ 7,162,3904 },{ 1,17,480 },{ 1,17,480 } },1453{ { 15,162,3906 },{ 15,162,3904 },{ 1,117,352 },{ 1,117,352 } },1454{ { 23,162,3906 },{ 23,162,3904 },{ 5,34,500 },{ 4,53,424 } },1455{ { 32,162,3906 },{ 32,162,3904 },{ 14,34,500 },{ 3,69,424 } },1456{ { 40,162,3906 },{ 40,162,3904 },{ 22,34,500 },{ 1,133,496 } },1457{ { 48,162,3906 },{ 48,162,3904 },{ 30,34,500 },{ 4,85,496 } },1458{ { 56,162,3906 },{ 56,162,3904 },{ 38,34,500 },{ 12,85,496 } },1459{ { 65,162,3906 },{ 65,162,3904 },{ 47,34,500 },{ 1,106,424 } },1460{ { 73,162,3906 },{ 73,162,3904 },{ 55,34,500 },{ 9,106,424 } },1461{ { 81,162,3906 },{ 81,162,3904 },{ 63,34,500 },{ 7,234,496 } },1462{ { 89,162,3906 },{ 89,162,3904 },{ 71,34,500 },{ 15,234,496 } },1463{ { 98,162,3906 },{ 98,162,3904 },{ 80,34,500 },{ 24,234,496 } },1464{ { 106,162,3906 },{ 106,162,3904 },{ 88,34,500 },{ 32,234,496 } },1465{ { 114,162,3906 },{ 114,162,3904 },{ 96,34,500 },{ 40,234,496 } },1466{ { 122,162,3906 },{ 122,162,3904 },{ 104,34,500 },{ 48,234,496 } },1467{ { 131,162,3906 },{ 131,162,3904 },{ 113,34,500 },{ 57,234,496 } },1468{ { 139,162,3906 },{ 139,162,3904 },{ 121,34,500 },{ 65,234,496 } },1469{ { 147,162,3906 },{ 147,162,3904 },{ 129,34,500 },{ 73,234,496 } },1470{ { 155,162,3906 },{ 155,162,3904 },{ 137,34,500 },{ 81,234,496 } },1471{ { 164,162,3906 },{ 164,162,3904 },{ 146,34,500 },{ 90,234,496 } },1472{ { 172,162,3906 },{ 172,162,3904 },{ 154,34,500 },{ 98,234,496 } },1473{ { 180,162,3906 },{ 180,162,3904 },{ 162,34,500 },{ 106,234,496 } },1474{ { 188,162,3906 },{ 188,162,3904 },{ 170,34,500 },{ 114,234,496 } },1475{ { 197,162,3906 },{ 197,162,3904 },{ 179,34,500 },{ 123,234,496 } },1476{ { 205,162,3906 },{ 205,162,3904 },{ 187,34,500 },{ 131,234,496 } },1477{ { 213,162,3906 },{ 213,162,3904 },{ 195,34,500 },{ 139,234,496 } },1478{ { 221,162,3906 },{ 221,162,3904 },{ 203,34,500 },{ 147,234,496 } },1479{ { 230,162,3906 },{ 230,162,3904 },{ 212,34,500 },{ 156,234,496 } },1480{ { 238,162,3906 },{ 174,106,4008 },{ 220,34,500 },{ 164,234,496 } },1481{ { 240,178,4001 },{ 182,106,4008 },{ 228,34,500 },{ 172,234,496 } },1482{ { 166,108,4085 },{ 115,31,4080 },{ 166,108,501 },{ 115,31,496 } },1483{ { 1,68,3328 },{ 1,68,3328 },{ 0,17,384 },{ 0,17,384 } },1484{ { 1,148,3904 },{ 1,148,3904 },{ 1,2,384 },{ 1,2,384 } },1485{ { 21,18,3851 },{ 21,18,3848 },{ 1,50,488 },{ 1,50,488 } },1486{ { 27,195,3851 },{ 29,18,3848 },{ 0,67,488 },{ 0,67,488 } },1487{ { 34,195,3907 },{ 38,18,3848 },{ 20,66,482 },{ 0,3,496 } },1488{ { 42,195,3907 },{ 46,18,3848 },{ 28,66,482 },{ 2,6,424 } },1489{ { 50,195,3907 },{ 54,18,3848 },{ 36,66,482 },{ 4,22,424 } },1490{ { 58,195,3907 },{ 62,18,3848 },{ 44,66,482 },{ 3,73,424 } },1491{ { 67,195,3907 },{ 71,18,3848 },{ 53,66,482 },{ 3,22,496 } },1492{ { 75,195,3907 },{ 79,18,3848 },{ 61,66,482 },{ 2,137,496 } },1493{ { 83,195,3907 },{ 87,18,3848 },{ 69,66,482 },{ 1,89,496 } },1494{ { 91,195,3907 },{ 95,18,3848 },{ 77,66,482 },{ 9,89,496 } },1495{ { 100,195,3907 },{ 104,18,3848 },{ 86,66,482 },{ 18,89,496 } },1496{ { 108,195,3907 },{ 112,18,3848 },{ 94,66,482 },{ 26,89,496 } },1497{ { 116,195,3907 },{ 120,18,3848 },{ 102,66,482 },{ 34,89,496 } },1498{ { 124,195,3907 },{ 128,18,3848 },{ 110,66,482 },{ 42,89,496 } },1499{ { 133,195,3907 },{ 137,18,3848 },{ 119,66,482 },{ 51,89,496 } },1500{ { 141,195,3907 },{ 145,18,3848 },{ 127,66,482 },{ 59,89,496 } },1501{ { 149,195,3907 },{ 153,18,3848 },{ 135,66,482 },{ 67,89,496 } },1502{ { 157,195,3907 },{ 161,18,3848 },{ 143,66,482 },{ 75,89,496 } },1503{ { 166,195,3907 },{ 170,18,3848 },{ 152,66,482 },{ 84,89,496 } },1504{ { 174,195,3907 },{ 178,18,3848 },{ 160,66,482 },{ 92,89,496 } },1505{ { 182,195,3907 },{ 186,18,3848 },{ 168,66,482 },{ 100,89,496 } },1506{ { 190,195,3907 },{ 194,18,3848 },{ 176,66,482 },{ 108,89,496 } },1507{ { 199,195,3907 },{ 203,18,3848 },{ 185,66,482 },{ 117,89,496 } },1508{ { 207,195,3907 },{ 211,18,3848 },{ 193,66,482 },{ 125,89,496 } },1509{ { 215,195,3907 },{ 219,18,3848 },{ 201,66,482 },{ 133,89,496 } },1510{ { 223,195,3907 },{ 227,18,3848 },{ 209,66,482 },{ 141,89,496 } },1511{ { 231,195,3907 },{ 168,89,4008 },{ 218,66,482 },{ 150,89,496 } },1512{ { 236,18,3907 },{ 176,89,4008 },{ 226,66,482 },{ 158,89,496 } },1513{ { 158,90,4085 },{ 103,31,4080 },{ 158,90,501 },{ 103,31,496 } },1514{ { 166,90,4085 },{ 111,31,4080 },{ 166,90,501 },{ 111,31,496 } },1515{ { 0,70,3328 },{ 0,70,3328 },{ 0,45,256 },{ 0,45,256 } },1516{ { 0,117,3904 },{ 0,117,3904 },{ 0,35,384 },{ 0,35,384 } },1517{ { 13,165,3905 },{ 13,165,3904 },{ 3,221,416 },{ 3,221,416 } },1518{ { 21,165,3906 },{ 21,165,3904 },{ 11,221,416 },{ 11,221,416 } },1519{ { 30,165,3906 },{ 30,165,3904 },{ 7,61,352 },{ 7,61,352 } },1520{ { 38,165,3906 },{ 38,165,3904 },{ 2,125,352 },{ 2,125,352 } },1521{ { 46,165,3906 },{ 46,165,3904 },{ 2,37,500 },{ 10,125,352 } },1522{ { 54,165,3906 },{ 54,165,3904 },{ 10,37,500 },{ 5,61,424 } },1523{ { 63,165,3906 },{ 63,165,3904 },{ 19,37,500 },{ 1,189,424 } },1524{ { 4,254,4012 },{ 71,165,3904 },{ 27,37,500 },{ 9,189,424 } },1525{ { 12,254,4012 },{ 79,165,3904 },{ 35,37,500 },{ 4,77,424 } },1526{ { 20,254,4012 },{ 87,165,3904 },{ 43,37,500 },{ 12,77,424 } },1527{ { 29,254,4012 },{ 96,165,3904 },{ 52,37,500 },{ 8,93,424 } },1528{ { 37,254,4012 },{ 104,165,3904 },{ 60,37,500 },{ 3,141,496 } },1529{ { 45,254,4012 },{ 112,165,3904 },{ 68,37,500 },{ 11,141,496 } },1530{ { 53,254,4012 },{ 120,165,3904 },{ 76,37,500 },{ 6,93,496 } },1531{ { 62,254,4012 },{ 129,165,3904 },{ 85,37,500 },{ 15,93,496 } },1532{ { 70,254,4012 },{ 137,165,3904 },{ 93,37,500 },{ 23,93,496 } },1533{ { 78,254,4012 },{ 145,165,3904 },{ 101,37,500 },{ 31,93,496 } },1534{ { 86,254,4012 },{ 153,165,3904 },{ 109,37,500 },{ 39,93,496 } },1535{ { 95,254,4012 },{ 162,165,3904 },{ 118,37,500 },{ 48,93,496 } },1536{ { 103,254,4012 },{ 170,165,3904 },{ 126,37,500 },{ 56,93,496 } },1537{ { 111,254,4012 },{ 178,165,3904 },{ 134,37,500 },{ 64,93,496 } },1538{ { 119,254,4012 },{ 186,165,3904 },{ 142,37,500 },{ 72,93,496 } },1539{ { 128,254,4012 },{ 195,165,3904 },{ 151,37,500 },{ 81,93,496 } },1540{ { 136,254,4012 },{ 203,165,3904 },{ 159,37,500 },{ 89,93,496 } },1541{ { 212,165,3906 },{ 136,77,4008 },{ 167,37,500 },{ 97,93,496 } },1542{ { 220,165,3394 },{ 131,93,4008 },{ 175,37,500 },{ 105,93,496 } },1543{ { 214,181,4001 },{ 140,93,4008 },{ 184,37,500 },{ 114,93,496 } },1544{ { 222,181,4001 },{ 148,93,4008 },{ 192,37,500 },{ 122,93,496 } },1545{ { 114,95,4085 },{ 99,31,4080 },{ 114,95,501 },{ 99,31,496 } },1546{ { 122,95,4085 },{ 107,31,4080 },{ 122,95,501 },{ 107,31,496 } },1547{ { 0,102,3840 },{ 0,102,3840 },{ 0,18,384 },{ 0,18,384 } },1548{ { 5,167,3904 },{ 5,167,3904 },{ 0,13,256 },{ 0,13,256 } },1549{ { 4,54,3968 },{ 4,54,3968 },{ 1,67,448 },{ 1,67,448 } },1550{ { 30,198,3850 },{ 30,198,3848 },{ 0,3,480 },{ 0,3,480 } },1551{ { 39,198,3850 },{ 39,198,3848 },{ 3,52,488 },{ 3,52,488 } },1552{ { 47,198,3851 },{ 47,198,3848 },{ 3,4,488 },{ 3,4,488 } },1553{ { 55,198,3851 },{ 55,198,3848 },{ 1,70,488 },{ 1,70,488 } },1554{ { 54,167,3906 },{ 63,198,3848 },{ 3,22,488 },{ 3,22,488 } },1555{ { 62,167,3906 },{ 72,198,3848 },{ 24,118,488 },{ 0,6,496 } },1556{ { 70,167,3906 },{ 80,198,3848 },{ 32,118,488 },{ 2,89,488 } },1557{ { 78,167,3906 },{ 88,198,3848 },{ 40,118,488 },{ 1,73,496 } },1558{ { 86,167,3906 },{ 96,198,3848 },{ 48,118,488 },{ 0,28,424 } },1559{ { 95,167,3906 },{ 105,198,3848 },{ 57,118,488 },{ 9,28,424 } },1560{ { 103,167,3906 },{ 113,198,3848 },{ 65,118,488 },{ 5,108,496 } },1561{ { 111,167,3906 },{ 121,198,3848 },{ 73,118,488 },{ 13,108,496 } },1562{ { 119,167,3906 },{ 129,198,3848 },{ 81,118,488 },{ 21,108,496 } },1563{ { 128,167,3906 },{ 138,198,3848 },{ 90,118,488 },{ 6,28,496 } },1564{ { 136,167,3906 },{ 146,198,3848 },{ 98,118,488 },{ 14,28,496 } },1565{ { 144,167,3906 },{ 154,198,3848 },{ 106,118,488 },{ 22,28,496 } },1566{ { 152,167,3906 },{ 162,198,3848 },{ 114,118,488 },{ 30,28,496 } },1567{ { 161,167,3906 },{ 171,198,3848 },{ 123,118,488 },{ 39,28,496 } },1568{ { 169,167,3906 },{ 179,198,3848 },{ 131,118,488 },{ 47,28,496 } },1569{ { 177,167,3906 },{ 187,198,3848 },{ 139,118,488 },{ 55,28,496 } },1570{ { 185,167,3906 },{ 195,198,3848 },{ 147,118,488 },{ 63,28,496 } },1571{ { 194,167,3906 },{ 120,12,4008 },{ 156,118,488 },{ 72,28,496 } },1572{ { 206,198,3907 },{ 116,28,4008 },{ 164,118,488 },{ 80,28,496 } },1573{ { 214,198,3907 },{ 124,28,4008 },{ 172,118,488 },{ 88,28,496 } },1574{ { 222,198,3395 },{ 132,28,4008 },{ 180,118,488 },{ 96,28,496 } },1575{ { 207,134,4001 },{ 141,28,4008 },{ 189,118,488 },{ 105,28,496 } },1576{ { 95,30,4085 },{ 86,31,4080 },{ 95,30,501 },{ 86,31,496 } },1577{ { 103,30,4085 },{ 94,31,4080 },{ 103,30,501 },{ 94,31,496 } },1578{ { 111,30,4085 },{ 102,31,4080 },{ 111,30,501 },{ 102,31,496 } },1579{ { 0,104,3840 },{ 0,104,3840 },{ 0,18,448 },{ 0,18,448 } },1580{ { 4,39,3904 },{ 4,39,3904 },{ 0,4,384 },{ 0,4,384 } },1581{ { 0,56,3968 },{ 0,56,3968 },{ 0,84,448 },{ 0,84,448 } },1582{ { 6,110,3328 },{ 6,110,3328 },{ 0,20,448 },{ 0,20,448 } },1583{ { 41,200,3850 },{ 41,200,3848 },{ 1,4,480 },{ 1,4,480 } },1584{ { 49,200,3850 },{ 49,200,3848 },{ 1,8,416 },{ 1,8,416 } },1585{ { 57,200,3851 },{ 57,200,3848 },{ 1,38,488 },{ 1,38,488 } },1586{ { 65,200,3851 },{ 65,200,3848 },{ 1,120,488 },{ 1,120,488 } },1587{ { 74,200,3851 },{ 74,200,3848 },{ 2,72,488 },{ 2,72,488 } },1588{ { 69,6,3907 },{ 82,200,3848 },{ 2,24,488 },{ 2,24,488 } },1589{ { 77,6,3907 },{ 90,200,3848 },{ 26,120,488 },{ 10,24,488 } },1590{ { 97,63,3330 },{ 98,200,3848 },{ 34,120,488 },{ 2,8,496 } },1591{ { 106,63,3330 },{ 107,200,3848 },{ 43,120,488 },{ 3,92,488 } },1592{ { 114,63,3330 },{ 115,200,3848 },{ 51,120,488 },{ 11,92,488 } },1593{ { 122,63,3330 },{ 123,200,3848 },{ 59,120,488 },{ 7,76,496 } },1594{ { 130,63,3330 },{ 131,200,3848 },{ 67,120,488 },{ 15,76,496 } },1595{ { 139,63,3330 },{ 140,200,3848 },{ 76,120,488 },{ 24,76,496 } },1596{ { 147,63,3330 },{ 148,200,3848 },{ 84,120,488 },{ 32,76,496 } },1597{ { 155,63,3330 },{ 156,200,3848 },{ 92,120,488 },{ 40,76,496 } },1598{ { 163,63,3330 },{ 164,200,3848 },{ 100,120,488 },{ 48,76,496 } },1599{ { 172,63,3330 },{ 173,200,3848 },{ 109,120,488 },{ 57,76,496 } },1600{ { 184,6,3851 },{ 181,200,3848 },{ 117,120,488 },{ 65,76,496 } },1601{ { 192,6,3851 },{ 133,28,3936 },{ 125,120,488 },{ 73,76,496 } },1602{ { 189,200,3907 },{ 141,28,3936 },{ 133,120,488 },{ 81,76,496 } },1603{ { 198,200,3907 },{ 138,108,4000 },{ 142,120,488 },{ 90,76,496 } },1604{ { 206,200,3907 },{ 146,108,4000 },{ 150,120,488 },{ 98,76,496 } },1605{ { 214,200,3395 },{ 154,108,4000 },{ 158,120,488 },{ 106,76,496 } },1606{ { 190,136,4001 },{ 162,108,4000 },{ 166,120,488 },{ 114,76,496 } },1607{ { 123,30,4076 },{ 87,15,4080 },{ 123,30,492 },{ 87,15,496 } },1608{ { 117,110,4084 },{ 80,31,4080 },{ 117,110,500 },{ 80,31,496 } },1609{ { 125,110,4084 },{ 88,31,4080 },{ 125,110,500 },{ 88,31,496 } },1610{ { 133,110,4084 },{ 96,31,4080 },{ 133,110,500 },{ 96,31,496 } },1611{ { 9,56,3904 },{ 9,56,3904 },{ 0,67,448 },{ 0,67,448 } },1612{ { 1,8,3904 },{ 1,8,3904 },{ 1,84,448 },{ 1,84,448 } },1613{ { 1,124,3904 },{ 1,124,3904 },{ 0,39,384 },{ 0,39,384 } },1614{ { 9,124,3904 },{ 9,124,3904 },{ 1,4,448 },{ 1,4,448 } },1615{ { 6,76,3904 },{ 6,76,3904 },{ 0,70,448 },{ 0,70,448 } },1616{ { 62,6,3859 },{ 62,6,3856 },{ 2,38,480 },{ 2,38,480 } },1617{ { 70,6,3859 },{ 70,6,3856 },{ 5,43,416 },{ 5,43,416 } },1618{ { 78,6,3859 },{ 78,6,3856 },{ 2,11,416 },{ 2,11,416 } },1619{ { 87,6,3859 },{ 87,6,3856 },{ 0,171,488 },{ 0,171,488 } },1620{ { 67,8,3906 },{ 95,6,3856 },{ 8,171,488 },{ 8,171,488 } },1621{ { 75,8,3907 },{ 103,6,3856 },{ 5,123,488 },{ 5,123,488 } },1622{ { 83,8,3907 },{ 111,6,3856 },{ 2,75,488 },{ 2,75,488 } },1623{ { 92,8,3907 },{ 120,6,3856 },{ 0,27,488 },{ 0,27,488 } },1624{ { 100,8,3907 },{ 128,6,3856 },{ 8,27,488 },{ 8,27,488 } },1625{ { 120,106,3843 },{ 136,6,3856 },{ 100,6,387 },{ 16,27,488 } },1626{ { 128,106,3843 },{ 144,6,3856 },{ 108,6,387 },{ 2,11,496 } },1627{ { 137,106,3843 },{ 153,6,3856 },{ 117,6,387 },{ 11,11,496 } },1628{ { 145,106,3843 },{ 161,6,3856 },{ 125,6,387 },{ 19,11,496 } },1629{ { 163,8,3851 },{ 137,43,3904 },{ 133,6,387 },{ 27,11,496 } },1630{ { 171,8,3851 },{ 101,11,4000 },{ 141,6,387 },{ 35,11,496 } },1631{ { 180,8,3851 },{ 110,11,4000 },{ 150,6,387 },{ 44,11,496 } },1632{ { 188,8,3851 },{ 118,11,4000 },{ 158,6,387 },{ 52,11,496 } },1633{ { 172,72,3907 },{ 126,11,4000 },{ 166,6,387 },{ 60,11,496 } },1634{ { 174,6,3971 },{ 134,11,4000 },{ 174,6,387 },{ 68,11,496 } },1635{ { 183,6,3971 },{ 143,11,4000 },{ 183,6,387 },{ 77,11,496 } },1636{ { 191,6,3971 },{ 151,11,4000 },{ 191,6,387 },{ 85,11,496 } },1637{ { 199,6,3971 },{ 159,11,4000 },{ 199,6,387 },{ 93,11,496 } },1638{ { 92,12,4084 },{ 69,15,4080 },{ 92,12,500 },{ 69,15,496 } },1639{ { 101,12,4084 },{ 78,15,4080 },{ 101,12,500 },{ 78,15,496 } },1640{ { 109,12,4084 },{ 86,15,4080 },{ 109,12,500 },{ 86,15,496 } },1641{ { 117,12,4084 },{ 79,31,4080 },{ 117,12,500 },{ 79,31,496 } },1642{ { 125,12,4084 },{ 87,31,4080 },{ 125,12,500 },{ 87,31,496 } },1643{ { 71,8,3602 },{ 71,8,3600 },{ 2,21,384 },{ 2,21,384 } },1644{ { 79,8,3611 },{ 79,8,3608 },{ 0,69,448 },{ 0,69,448 } },1645{ { 87,8,3611 },{ 87,8,3608 },{ 0,23,384 },{ 0,23,384 } },1646{ { 95,8,3611 },{ 95,8,3608 },{ 1,5,448 },{ 1,5,448 } },1647{ { 104,8,3611 },{ 104,8,3608 },{ 0,88,448 },{ 0,88,448 } },1648{ { 112,8,3611 },{ 112,8,3608 },{ 0,72,448 },{ 0,72,448 } },1649{ { 120,8,3611 },{ 121,8,3608 },{ 36,21,458 },{ 36,21,456 } },1650{ { 133,47,3091 },{ 129,8,3608 },{ 44,21,458 },{ 44,21,456 } },1651{ { 142,47,3091 },{ 138,8,3608 },{ 53,21,459 },{ 53,21,456 } },1652{ { 98,12,3850 },{ 98,12,3848 },{ 61,21,459 },{ 61,21,456 } },1653{ { 106,12,3850 },{ 106,12,3848 },{ 10,92,480 },{ 69,21,456 } },1654{ { 114,12,3851 },{ 114,12,3848 },{ 18,92,480 },{ 77,21,456 } },1655{ { 87,12,3906 },{ 87,12,3904 },{ 3,44,488 },{ 86,21,456 } },1656{ { 95,12,3906 },{ 95,12,3904 },{ 11,44,488 },{ 94,21,456 } },1657{ { 103,12,3906 },{ 103,12,3904 },{ 19,44,488 },{ 102,21,456 } },1658{ { 111,12,3907 },{ 111,12,3904 },{ 27,44,489 },{ 110,21,456 } },1659{ { 120,12,3907 },{ 120,12,3904 },{ 36,44,489 },{ 119,21,456 } },1660{ { 128,12,3907 },{ 128,12,3904 },{ 44,44,489 },{ 127,21,456 } },1661{ { 136,12,3907 },{ 136,12,3904 },{ 52,44,489 },{ 135,21,456 } },1662{ { 144,12,3907 },{ 144,12,3904 },{ 60,44,489 },{ 143,21,456 } },1663{ { 153,12,3907 },{ 153,12,3904 },{ 69,44,490 },{ 152,21,456 } },1664{ { 161,12,3395 },{ 149,188,3968 },{ 77,44,490 },{ 160,21,456 } },1665{ { 169,12,3395 },{ 198,21,3928 },{ 85,44,490 },{ 168,21,456 } },1666{ { 113,95,4001 },{ 201,69,3992 },{ 125,8,483 },{ 176,21,456 } },1667{ { 122,95,4001 },{ 200,21,3984 },{ 134,8,483 },{ 185,21,456 } },1668{ { 142,8,4067 },{ 208,21,3984 },{ 142,8,483 },{ 193,21,456 } },1669{ { 151,8,4067 },{ 47,15,4080 },{ 151,8,483 },{ 47,15,496 } },1670{ { 159,8,4067 },{ 55,15,4080 },{ 159,8,483 },{ 55,15,496 } },1671{ { 168,8,4067 },{ 64,15,4080 },{ 168,8,483 },{ 64,15,496 } },1672{ { 160,40,4075 },{ 72,15,4080 },{ 160,40,491 },{ 72,15,496 } },1673{ { 168,40,4075 },{ 80,15,4080 },{ 168,40,491 },{ 80,15,496 } },1674{ { 144,8,4082 },{ 88,15,4080 },{ 144,8,498 },{ 88,15,496 } }1675};1676#endif // BASISD_SUPPORT_ETC2_EAC_A816771678#if BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES1679static void create_etc2_eac_a8_conversion_table()1680{1681FILE* pFile = fopen("basisu_decoder_tables_etc2_eac_a8.inc", "w");16821683for (uint32_t inten = 0; inten < 8; inten++)1684{1685for (uint32_t base = 0; base < 32; base++)1686{1687color32 block_colors[4];1688decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(base, base, base, 255), false), inten);16891690fprintf(pFile, "{");16911692for (uint32_t sel_range = 0; sel_range < NUM_ETC2_EAC_SELECTOR_RANGES; sel_range++)1693{1694const uint32_t low_selector = s_etc2_eac_selector_ranges[sel_range].m_low;1695const uint32_t high_selector = s_etc2_eac_selector_ranges[sel_range].m_high;16961697// We have a ETC1 base color and intensity, and a used selector range from low_selector-high_selector.1698// Now find the best ETC2 EAC A8 base/table/multiplier that fits these colors.16991700uint8_t pixels[4];1701uint32_t num_pixels = 0;1702for (uint32_t s = low_selector; s <= high_selector; s++)1703pixels[num_pixels++] = block_colors[s].g;17041705pack_eac_a8_results pack_results;1706pack_eac_a8_exhaustive(pack_results, pixels, num_pixels);17071708etc1_g_to_eac_conversion& c = s_etc1_g_to_etc2_a8[base + inten * 32][sel_range];17091710c.m_base = pack_results.m_base;1711c.m_table_mul = pack_results.m_table * 16 + pack_results.m_multiplier;1712c.m_trans = 0;17131714for (uint32_t s = 0; s < 4; s++)1715{1716if ((s < low_selector) || (s > high_selector))1717continue;17181719uint32_t etc2_selector = pack_results.m_selectors[s - low_selector];17201721c.m_trans |= (etc2_selector << (s * 3));1722}17231724fprintf(pFile, "{%u,%u,%u}", c.m_base, c.m_table_mul, c.m_trans);1725if (sel_range < (NUM_ETC2_EAC_SELECTOR_RANGES - 1))1726fprintf(pFile, ",");1727}17281729fprintf(pFile, "},\n");1730}1731}17321733fclose(pFile);1734}1735#endif17361737#if BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES1738struct pack_eac_r11_results1739{1740uint32_t m_base;1741uint32_t m_table;1742uint32_t m_multiplier;1743basisu::vector<uint8_t> m_selectors;1744basisu::vector<uint8_t> m_selectors_temp;1745};17461747static uint64_t pack_eac_r11_exhaustive(pack_eac_r11_results& results, const uint8_t* pPixels, uint32_t num_pixels)1748{1749results.m_selectors.resize(num_pixels);1750results.m_selectors_temp.resize(num_pixels);17511752uint64_t best_err = UINT64_MAX;17531754for (uint32_t base_color = 0; base_color < 256; base_color++)1755{1756for (uint32_t multiplier = 0; multiplier < 16; multiplier++)1757{1758for (uint32_t table = 0; table < 16; table++)1759{1760uint64_t total_err = 0;17611762for (uint32_t i = 0; i < num_pixels; i++)1763{1764// Convert 8-bit input to 11-bits1765const int a = (pPixels[i] * 2047 + 128) / 255;17661767uint32_t best_s_err = UINT32_MAX;1768uint32_t best_s = 0;1769for (uint32_t s = 0; s < 8; s++)1770{1771int v = (int)(multiplier ? (multiplier * 8) : 1) * g_eac_modifier_table[table][s] + (int)base_color * 8 + 4;1772if (v < 0)1773v = 0;1774else if (v > 2047)1775v = 2047;17761777uint32_t err = abs(a - v);1778if (err < best_s_err)1779{1780best_s_err = err;1781best_s = s;1782}1783}17841785results.m_selectors_temp[i] = static_cast<uint8_t>(best_s);17861787total_err += best_s_err * best_s_err;1788if (total_err >= best_err)1789break;1790}17911792if (total_err < best_err)1793{1794best_err = total_err;1795results.m_base = base_color;1796results.m_multiplier = multiplier;1797results.m_table = table;1798results.m_selectors.swap(results.m_selectors_temp);1799}18001801} // table18021803} // multiplier18041805} // base_color18061807return best_err;1808}18091810static void create_etc2_eac_r11_conversion_table()1811{1812FILE* pFile = nullptr;1813fopen_s(&pFile, "basisu_decoder_tables_etc2_eac_r11.inc", "w");18141815for (uint32_t inten = 0; inten < 8; inten++)1816{1817for (uint32_t base = 0; base < 32; base++)1818{1819color32 block_colors[4];1820decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(base, base, base, 255), false), inten);18211822fprintf(pFile, "{");18231824for (uint32_t sel_range = 0; sel_range < NUM_ETC2_EAC_SELECTOR_RANGES; sel_range++)1825{1826const uint32_t low_selector = s_etc2_eac_selector_ranges[sel_range].m_low;1827const uint32_t high_selector = s_etc2_eac_selector_ranges[sel_range].m_high;18281829// We have a ETC1 base color and intensity, and a used selector range from low_selector-high_selector.1830// Now find the best ETC2 EAC R11 base/table/multiplier that fits these colors.18311832uint8_t pixels[4];1833uint32_t num_pixels = 0;1834for (uint32_t s = low_selector; s <= high_selector; s++)1835pixels[num_pixels++] = block_colors[s].g;18361837pack_eac_r11_results pack_results;1838pack_eac_r11_exhaustive(pack_results, pixels, num_pixels);18391840etc1_g_to_eac_conversion c;18411842c.m_base = (uint8_t)pack_results.m_base;1843c.m_table_mul = (uint8_t)(pack_results.m_table * 16 + pack_results.m_multiplier);1844c.m_trans = 0;18451846for (uint32_t s = 0; s < 4; s++)1847{1848if ((s < low_selector) || (s > high_selector))1849continue;18501851uint32_t etc2_selector = pack_results.m_selectors[s - low_selector];18521853c.m_trans |= (etc2_selector << (s * 3));1854}18551856fprintf(pFile, "{%u,%u,%u}", c.m_base, c.m_table_mul, c.m_trans);1857if (sel_range < (NUM_ETC2_EAC_SELECTOR_RANGES - 1))1858fprintf(pFile, ",");1859}18601861fprintf(pFile, "},\n");1862}1863}18641865fclose(pFile);1866}1867#endif // BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES18681869#if BASISD_WRITE_NEW_ASTC_TABLES1870static void create_etc1_to_astc_conversion_table_0_47();1871static void create_etc1_to_astc_conversion_table_0_255();1872#endif18731874#if BASISD_SUPPORT_ASTC1875static void transcoder_init_astc();1876#endif18771878#if BASISD_WRITE_NEW_BC7_MODE5_TABLES1879static void create_etc1_to_bc7_m5_color_conversion_table();1880static void create_etc1_to_bc7_m5_alpha_conversion_table();1881#endif18821883#if BASISD_SUPPORT_BC7_MODE51884static void transcoder_init_bc7_mode5();1885#endif18861887#if BASISD_WRITE_NEW_ATC_TABLES1888static void create_etc1s_to_atc_conversion_tables();1889#endif18901891#if BASISD_SUPPORT_ATC1892static void transcoder_init_atc();1893#endif18941895#if BASISD_SUPPORT_PVRTC21896static void transcoder_init_pvrtc2();1897#endif18981899#if BASISD_SUPPORT_UASTC1900void uastc_init();1901#endif19021903static bool g_transcoder_initialized;19041905// Library global initialization. Requires ~9 milliseconds when compiled and executed natively on a Core i7 2.2 GHz.1906// If this is too slow, these computed tables can easilky be moved to be compiled in.1907void basisu_transcoder_init()1908{1909if (g_transcoder_initialized)1910{1911BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Called more than once\n");1912return;1913}19141915BASISU_DEVEL_ERROR("basisu_transcoder::basisu_transcoder_init: Initializing (this is not an error)\n");19161917#if BASISD_SUPPORT_UASTC1918uastc_init();1919#endif19201921#if BASISD_SUPPORT_ASTC1922transcoder_init_astc();1923#endif19241925#if BASISD_WRITE_NEW_ASTC_TABLES1926create_etc1_to_astc_conversion_table_0_47();1927create_etc1_to_astc_conversion_table_0_255();1928exit(0);1929#endif19301931#if BASISD_WRITE_NEW_BC7_MODE5_TABLES1932create_etc1_to_bc7_m5_color_conversion_table();1933create_etc1_to_bc7_m5_alpha_conversion_table();1934exit(0);1935#endif19361937#if BASISD_WRITE_NEW_DXT1_TABLES1938create_etc1_to_dxt1_5_conversion_table();1939create_etc1_to_dxt1_6_conversion_table();1940exit(0);1941#endif19421943#if BASISD_WRITE_NEW_ETC2_EAC_A8_TABLES1944create_etc2_eac_a8_conversion_table();1945exit(0);1946#endif19471948#if BASISD_WRITE_NEW_ATC_TABLES1949create_etc1s_to_atc_conversion_tables();1950exit(0);1951#endif19521953#if BASISD_WRITE_NEW_ETC2_EAC_R11_TABLES1954create_etc2_eac_r11_conversion_table();1955exit(0);1956#endif19571958#if BASISD_SUPPORT_DXT1 || BASISD_SUPPORT_UASTC1959uint8_t bc1_expand5[32];1960for (int i = 0; i < 32; i++)1961bc1_expand5[i] = static_cast<uint8_t>((i << 3) | (i >> 2));1962prepare_bc1_single_color_table(g_bc1_match5_equals_1, bc1_expand5, 32, 32, 1);1963prepare_bc1_single_color_table(g_bc1_match5_equals_0, bc1_expand5, 1, 32, 0);19641965uint8_t bc1_expand6[64];1966for (int i = 0; i < 64; i++)1967bc1_expand6[i] = static_cast<uint8_t>((i << 2) | (i >> 4));1968prepare_bc1_single_color_table(g_bc1_match6_equals_1, bc1_expand6, 64, 64, 1);1969prepare_bc1_single_color_table(g_bc1_match6_equals_0, bc1_expand6, 1, 64, 0);19701971#if 01972for (uint32_t i = 0; i < 256; i++)1973{1974printf("%u %u %u\n", i, (i * 63 + 127) / 255, g_bc1_match6_equals_0[i].m_hi);1975}1976exit(0);1977#endif19781979#endif19801981#if BASISD_SUPPORT_DXT11982for (uint32_t i = 0; i < NUM_ETC1_TO_DXT1_SELECTOR_RANGES; i++)1983{1984uint32_t l = g_etc1_to_dxt1_selector_ranges[i].m_low;1985uint32_t h = g_etc1_to_dxt1_selector_ranges[i].m_high;1986g_etc1_to_dxt1_selector_range_index[l][h] = i;1987}19881989for (uint32_t sm = 0; sm < NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS; sm++)1990{1991uint8_t etc1_to_dxt1_selector_mappings_raw_dxt1[4];1992uint8_t etc1_to_dxt1_selector_mappings_raw_dxt1_inv[4];19931994for (uint32_t j = 0; j < 4; j++)1995{1996static const uint8_t s_linear_dxt1_to_dxt1[4] = { 0, 2, 3, 1 };1997static const uint8_t s_dxt1_inverted_xlat[4] = { 1, 0, 3, 2 };19981999etc1_to_dxt1_selector_mappings_raw_dxt1[j] = (uint8_t)s_linear_dxt1_to_dxt1[g_etc1_to_dxt1_selector_mappings[sm][j]];2000etc1_to_dxt1_selector_mappings_raw_dxt1_inv[j] = (uint8_t)s_dxt1_inverted_xlat[etc1_to_dxt1_selector_mappings_raw_dxt1[j]];2001}20022003for (uint32_t i = 0; i < 256; i++)2004{2005uint32_t k = 0, k_inv = 0;2006for (uint32_t s = 0; s < 4; s++)2007{2008k |= (etc1_to_dxt1_selector_mappings_raw_dxt1[(i >> (s * 2)) & 3] << (s * 2));2009k_inv |= (etc1_to_dxt1_selector_mappings_raw_dxt1_inv[(i >> (s * 2)) & 3] << (s * 2));2010}2011g_etc1_to_dxt1_selector_mappings_raw_dxt1_256[sm][i] = (uint8_t)k;2012g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[sm][i] = (uint8_t)k_inv;2013}2014}2015#endif20162017#if BASISD_SUPPORT_BC7_MODE52018transcoder_init_bc7_mode5();2019#endif20202021#if BASISD_SUPPORT_ATC2022transcoder_init_atc();2023#endif20242025#if BASISD_SUPPORT_PVRTC22026transcoder_init_pvrtc2();2027#endif20282029g_transcoder_initialized = true;2030}20312032#if BASISD_SUPPORT_DXT12033static void convert_etc1s_to_dxt1(dxt1_block* pDst_block, const endpoint *pEndpoints, const selector* pSelector, bool use_threecolor_blocks)2034{2035#if !BASISD_WRITE_NEW_DXT1_TABLES2036const uint32_t low_selector = pSelector->m_lo_selector;2037const uint32_t high_selector = pSelector->m_hi_selector;20382039const color32& base_color = pEndpoints->m_color5;2040const uint32_t inten_table = pEndpoints->m_inten5;20412042if (low_selector == high_selector)2043{2044uint32_t r, g, b;2045decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b);20462047uint32_t mask = 0xAA;2048uint32_t max16 = (g_bc1_match5_equals_1[r].m_hi << 11) | (g_bc1_match6_equals_1[g].m_hi << 5) | g_bc1_match5_equals_1[b].m_hi;2049uint32_t min16 = (g_bc1_match5_equals_1[r].m_lo << 11) | (g_bc1_match6_equals_1[g].m_lo << 5) | g_bc1_match5_equals_1[b].m_lo;20502051if ((!use_threecolor_blocks) && (min16 == max16))2052{2053// This is an annoying edge case that impacts BC3.2054// This is to guarantee that BC3 blocks never use punchthrough alpha (3 color) mode, which isn't supported on some (all?) GPU's.2055mask = 0;20562057// Make l > h2058if (min16 > 0)2059min16--;2060else2061{2062// l = h = 02063assert(min16 == max16 && max16 == 0);20642065max16 = 1;2066min16 = 0;2067mask = 0x55;2068}20692070assert(max16 > min16);2071}20722073if (max16 < min16)2074{2075std::swap(max16, min16);2076mask ^= 0x55;2077}20782079pDst_block->set_low_color(static_cast<uint16_t>(max16));2080pDst_block->set_high_color(static_cast<uint16_t>(min16));2081pDst_block->m_selectors[0] = static_cast<uint8_t>(mask);2082pDst_block->m_selectors[1] = static_cast<uint8_t>(mask);2083pDst_block->m_selectors[2] = static_cast<uint8_t>(mask);2084pDst_block->m_selectors[3] = static_cast<uint8_t>(mask);20852086return;2087}2088else if ((inten_table >= 7) && (pSelector->m_num_unique_selectors == 2) && (pSelector->m_lo_selector == 0) && (pSelector->m_hi_selector == 3))2089{2090color32 block_colors[4];20912092decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table);20932094const uint32_t r0 = block_colors[0].r;2095const uint32_t g0 = block_colors[0].g;2096const uint32_t b0 = block_colors[0].b;20972098const uint32_t r1 = block_colors[3].r;2099const uint32_t g1 = block_colors[3].g;2100const uint32_t b1 = block_colors[3].b;21012102uint32_t max16 = (g_bc1_match5_equals_0[r0].m_hi << 11) | (g_bc1_match6_equals_0[g0].m_hi << 5) | g_bc1_match5_equals_0[b0].m_hi;2103uint32_t min16 = (g_bc1_match5_equals_0[r1].m_hi << 11) | (g_bc1_match6_equals_0[g1].m_hi << 5) | g_bc1_match5_equals_0[b1].m_hi;21042105uint32_t l = 0, h = 1;21062107if (min16 == max16)2108{2109// Make l > h2110if (min16 > 0)2111{2112min16--;21132114l = 0;2115h = 0;2116}2117else2118{2119// l = h = 02120assert(min16 == max16 && max16 == 0);21212122max16 = 1;2123min16 = 0;21242125l = 1;2126h = 1;2127}21282129assert(max16 > min16);2130}21312132if (max16 < min16)2133{2134std::swap(max16, min16);2135l = 1;2136h = 0;2137}21382139pDst_block->set_low_color((uint16_t)max16);2140pDst_block->set_high_color((uint16_t)min16);21412142for (uint32_t y = 0; y < 4; y++)2143{2144for (uint32_t x = 0; x < 4; x++)2145{2146uint32_t s = pSelector->get_selector(x, y);2147pDst_block->set_selector(x, y, (s == 3) ? h : l);2148}2149}21502151return;2152}21532154const uint32_t selector_range_table = g_etc1_to_dxt1_selector_range_index[low_selector][high_selector];21552156//[32][8][RANGES][MAPPING]2157const etc1_to_dxt1_56_solution* pTable_r = &g_etc1_to_dxt_5[(inten_table * 32 + base_color.r) * (NUM_ETC1_TO_DXT1_SELECTOR_RANGES * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS];2158const etc1_to_dxt1_56_solution* pTable_g = &g_etc1_to_dxt_6[(inten_table * 32 + base_color.g) * (NUM_ETC1_TO_DXT1_SELECTOR_RANGES * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS];2159const etc1_to_dxt1_56_solution* pTable_b = &g_etc1_to_dxt_5[(inten_table * 32 + base_color.b) * (NUM_ETC1_TO_DXT1_SELECTOR_RANGES * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS];21602161uint32_t best_err = UINT_MAX;2162uint32_t best_mapping = 0;21632164assert(NUM_ETC1_TO_DXT1_SELECTOR_MAPPINGS == 10);2165#define DO_ITER(m) { uint32_t total_err = pTable_r[m].m_err + pTable_g[m].m_err + pTable_b[m].m_err; if (total_err < best_err) { best_err = total_err; best_mapping = m; } }2166DO_ITER(0); DO_ITER(1); DO_ITER(2); DO_ITER(3); DO_ITER(4);2167DO_ITER(5); DO_ITER(6); DO_ITER(7); DO_ITER(8); DO_ITER(9);2168#undef DO_ITER21692170uint32_t l = dxt1_block::pack_unscaled_color(pTable_r[best_mapping].m_lo, pTable_g[best_mapping].m_lo, pTable_b[best_mapping].m_lo);2171uint32_t h = dxt1_block::pack_unscaled_color(pTable_r[best_mapping].m_hi, pTable_g[best_mapping].m_hi, pTable_b[best_mapping].m_hi);21722173const uint8_t* pSelectors_xlat_256 = &g_etc1_to_dxt1_selector_mappings_raw_dxt1_256[best_mapping][0];21742175if (l < h)2176{2177std::swap(l, h);2178pSelectors_xlat_256 = &g_etc1_to_dxt1_selector_mappings_raw_dxt1_inv_256[best_mapping][0];2179}21802181pDst_block->set_low_color(static_cast<uint16_t>(l));2182pDst_block->set_high_color(static_cast<uint16_t>(h));21832184if (l == h)2185{2186uint8_t mask = 0;21872188if (!use_threecolor_blocks)2189{2190// This is an annoying edge case that impacts BC3.21912192// Make l > h2193if (h > 0)2194h--;2195else2196{2197// l = h = 02198assert(l == h && h == 0);21992200h = 0;2201l = 1;2202mask = 0x55;2203}22042205assert(l > h);2206pDst_block->set_low_color(static_cast<uint16_t>(l));2207pDst_block->set_high_color(static_cast<uint16_t>(h));2208}22092210pDst_block->m_selectors[0] = mask;2211pDst_block->m_selectors[1] = mask;2212pDst_block->m_selectors[2] = mask;2213pDst_block->m_selectors[3] = mask;22142215return;2216}22172218pDst_block->m_selectors[0] = pSelectors_xlat_256[pSelector->m_selectors[0]];2219pDst_block->m_selectors[1] = pSelectors_xlat_256[pSelector->m_selectors[1]];2220pDst_block->m_selectors[2] = pSelectors_xlat_256[pSelector->m_selectors[2]];2221pDst_block->m_selectors[3] = pSelectors_xlat_256[pSelector->m_selectors[3]];2222#endif2223}22242225#if BASISD_ENABLE_DEBUG_FLAGS2226static void convert_etc1s_to_dxt1_vis(dxt1_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector, bool use_threecolor_blocks)2227{2228convert_etc1s_to_dxt1(pDst_block, pEndpoints, pSelector, use_threecolor_blocks);22292230if (g_debug_flags & cDebugFlagVisBC1Sels)2231{2232uint32_t l = dxt1_block::pack_unscaled_color(31, 63, 31);2233uint32_t h = dxt1_block::pack_unscaled_color(0, 0, 0);2234pDst_block->set_low_color(static_cast<uint16_t>(l));2235pDst_block->set_high_color(static_cast<uint16_t>(h));2236}2237else if (g_debug_flags & cDebugFlagVisBC1Endpoints)2238{2239for (uint32_t y = 0; y < 4; y++)2240for (uint32_t x = 0; x < 4; x++)2241pDst_block->set_selector(x, y, (y < 2) ? 0 : 1);2242}2243}2244#endif2245#endif22462247#if BASISD_SUPPORT_FXT12248struct fxt1_block2249{2250union2251{2252struct2253{2254uint64_t m_t00 : 2;2255uint64_t m_t01 : 2;2256uint64_t m_t02 : 2;2257uint64_t m_t03 : 2;2258uint64_t m_t04 : 2;2259uint64_t m_t05 : 2;2260uint64_t m_t06 : 2;2261uint64_t m_t07 : 2;2262uint64_t m_t08 : 2;2263uint64_t m_t09 : 2;2264uint64_t m_t10 : 2;2265uint64_t m_t11 : 2;2266uint64_t m_t12 : 2;2267uint64_t m_t13 : 2;2268uint64_t m_t14 : 2;2269uint64_t m_t15 : 2;2270uint64_t m_t16 : 2;2271uint64_t m_t17 : 2;2272uint64_t m_t18 : 2;2273uint64_t m_t19 : 2;2274uint64_t m_t20 : 2;2275uint64_t m_t21 : 2;2276uint64_t m_t22 : 2;2277uint64_t m_t23 : 2;2278uint64_t m_t24 : 2;2279uint64_t m_t25 : 2;2280uint64_t m_t26 : 2;2281uint64_t m_t27 : 2;2282uint64_t m_t28 : 2;2283uint64_t m_t29 : 2;2284uint64_t m_t30 : 2;2285uint64_t m_t31 : 2;2286} m_lo;2287uint64_t m_lo_bits;2288uint8_t m_sels[8];2289};2290union2291{2292struct2293{2294#ifdef BASISU_USE_ORIGINAL_3DFX_FXT1_ENCODING2295uint64_t m_b1 : 5;2296uint64_t m_g1 : 5;2297uint64_t m_r1 : 5;2298uint64_t m_b0 : 5;2299uint64_t m_g0 : 5;2300uint64_t m_r0 : 5;2301uint64_t m_b3 : 5;2302uint64_t m_g3 : 5;2303uint64_t m_r3 : 5;2304uint64_t m_b2 : 5;2305uint64_t m_g2 : 5;2306uint64_t m_r2 : 5;2307#else2308uint64_t m_b0 : 5;2309uint64_t m_g0 : 5;2310uint64_t m_r0 : 5;2311uint64_t m_b1 : 5;2312uint64_t m_g1 : 5;2313uint64_t m_r1 : 5;2314uint64_t m_b2 : 5;2315uint64_t m_g2 : 5;2316uint64_t m_r2 : 5;2317uint64_t m_b3 : 5;2318uint64_t m_g3 : 5;2319uint64_t m_r3 : 5;2320#endif2321uint64_t m_alpha : 1;2322uint64_t m_glsb : 2;2323uint64_t m_mode : 1;2324} m_hi;2325uint64_t m_hi_bits;2326};2327};23282329static uint8_t conv_dxt1_to_fxt1_sels(uint32_t sels)2330{2331static uint8_t s_conv_table[16] = { 0, 3, 1, 2, 12, 15, 13, 14, 4, 7, 5, 6, 8, 11, 9, 10 };2332return s_conv_table[sels & 15] | (s_conv_table[sels >> 4] << 4);2333}23342335static void convert_etc1s_to_fxt1(void *pDst, const endpoint *pEndpoints, const selector *pSelectors, uint32_t fxt1_subblock)2336{2337fxt1_block* pBlock = static_cast<fxt1_block*>(pDst);23382339// CC_MIXED is basically DXT1 with different encoding tricks.2340// So transcode ETC1S to DXT1, then transcode that to FXT1 which is easy and nearly lossless.2341// (It's not completely lossless because FXT1 rounds in its color lerps while DXT1 doesn't, but it should be good enough.)2342dxt1_block blk;2343convert_etc1s_to_dxt1(&blk, pEndpoints, pSelectors, false);23442345const uint32_t l = blk.get_low_color();2346const uint32_t h = blk.get_high_color();23472348color32 color0((l >> 11) & 31, (l >> 5) & 63, l & 31, 255);2349color32 color1((h >> 11) & 31, (h >> 5) & 63, h & 31, 255);23502351uint32_t g0 = color0.g & 1;2352uint32_t g1 = color1.g & 1;23532354color0.g >>= 1;2355color1.g >>= 1;23562357blk.m_selectors[0] = conv_dxt1_to_fxt1_sels(blk.m_selectors[0]);2358blk.m_selectors[1] = conv_dxt1_to_fxt1_sels(blk.m_selectors[1]);2359blk.m_selectors[2] = conv_dxt1_to_fxt1_sels(blk.m_selectors[2]);2360blk.m_selectors[3] = conv_dxt1_to_fxt1_sels(blk.m_selectors[3]);23612362if ((blk.get_selector(0, 0) >> 1) != (g0 ^ g1))2363{2364std::swap(color0, color1);2365std::swap(g0, g1);23662367blk.m_selectors[0] ^= 0xFF;2368blk.m_selectors[1] ^= 0xFF;2369blk.m_selectors[2] ^= 0xFF;2370blk.m_selectors[3] ^= 0xFF;2371}23722373if (fxt1_subblock == 0)2374{2375pBlock->m_hi.m_mode = 1;2376pBlock->m_hi.m_alpha = 0;2377pBlock->m_hi.m_glsb = g1 | (g1 << 1);2378pBlock->m_hi.m_r0 = color0.r;2379pBlock->m_hi.m_g0 = color0.g;2380pBlock->m_hi.m_b0 = color0.b;2381pBlock->m_hi.m_r1 = color1.r;2382pBlock->m_hi.m_g1 = color1.g;2383pBlock->m_hi.m_b1 = color1.b;2384pBlock->m_hi.m_r2 = color0.r;2385pBlock->m_hi.m_g2 = color0.g;2386pBlock->m_hi.m_b2 = color0.b;2387pBlock->m_hi.m_r3 = color1.r;2388pBlock->m_hi.m_g3 = color1.g;2389pBlock->m_hi.m_b3 = color1.b;2390pBlock->m_sels[0] = blk.m_selectors[0];2391pBlock->m_sels[1] = blk.m_selectors[1];2392pBlock->m_sels[2] = blk.m_selectors[2];2393pBlock->m_sels[3] = blk.m_selectors[3];23942395static const uint8_t s_border_dup[4] = { 0, 85, 170, 255 };2396pBlock->m_sels[4] = s_border_dup[blk.m_selectors[0] >> 6];2397pBlock->m_sels[5] = s_border_dup[blk.m_selectors[1] >> 6];2398pBlock->m_sels[6] = s_border_dup[blk.m_selectors[2] >> 6];2399pBlock->m_sels[7] = s_border_dup[blk.m_selectors[3] >> 6];2400}2401else2402{2403pBlock->m_hi.m_glsb = (pBlock->m_hi.m_glsb & 1) | (g1 << 1);2404pBlock->m_hi.m_r2 = color0.r;2405pBlock->m_hi.m_g2 = color0.g;2406pBlock->m_hi.m_b2 = color0.b;2407pBlock->m_hi.m_r3 = color1.r;2408pBlock->m_hi.m_g3 = color1.g;2409pBlock->m_hi.m_b3 = color1.b;2410pBlock->m_sels[4] = blk.m_selectors[0];2411pBlock->m_sels[5] = blk.m_selectors[1];2412pBlock->m_sels[6] = blk.m_selectors[2];2413pBlock->m_sels[7] = blk.m_selectors[3];2414}2415}2416#endif // BASISD_SUPPORT_FXT12417#if BASISD_SUPPORT_DXT5A2418static dxt_selector_range s_dxt5a_selector_ranges[] =2419{2420{ 0, 3 },24212422{ 1, 3 },2423{ 0, 2 },24242425{ 1, 2 },2426};24272428const uint32_t NUM_DXT5A_SELECTOR_RANGES = sizeof(s_dxt5a_selector_ranges) / sizeof(s_dxt5a_selector_ranges[0]);24292430struct etc1_g_to_dxt5a_conversion2431{2432uint8_t m_lo, m_hi;2433uint16_t m_trans;2434};24352436static etc1_g_to_dxt5a_conversion g_etc1_g_to_dxt5a[32 * 8][NUM_DXT5A_SELECTOR_RANGES] =2437{2438{ { 8, 0, 393 },{ 8, 0, 392 },{ 2, 0, 9 },{ 2, 0, 8 }, }, { { 6, 16, 710 },{ 16, 6, 328 },{ 0, 10, 96 },{ 10, 6, 8 }, },2439{ { 28, 5, 1327 },{ 24, 14, 328 },{ 8, 18, 96 },{ 18, 14, 8 }, }, { { 36, 13, 1327 },{ 32, 22, 328 },{ 16, 26, 96 },{ 26, 22, 8 }, },2440{ { 45, 22, 1327 },{ 41, 31, 328 },{ 25, 35, 96 },{ 35, 31, 8 }, }, { { 53, 30, 1327 },{ 49, 39, 328 },{ 33, 43, 96 },{ 43, 39, 8 }, },2441{ { 61, 38, 1327 },{ 57, 47, 328 },{ 41, 51, 96 },{ 51, 47, 8 }, }, { { 69, 46, 1327 },{ 65, 55, 328 },{ 49, 59, 96 },{ 59, 55, 8 }, },2442{ { 78, 55, 1327 },{ 74, 64, 328 },{ 58, 68, 96 },{ 68, 64, 8 }, }, { { 86, 63, 1327 },{ 82, 72, 328 },{ 66, 76, 96 },{ 76, 72, 8 }, },2443{ { 94, 71, 1327 },{ 90, 80, 328 },{ 74, 84, 96 },{ 84, 80, 8 }, }, { { 102, 79, 1327 },{ 98, 88, 328 },{ 82, 92, 96 },{ 92, 88, 8 }, },2444{ { 111, 88, 1327 },{ 107, 97, 328 },{ 91, 101, 96 },{ 101, 97, 8 }, }, { { 119, 96, 1327 },{ 115, 105, 328 },{ 99, 109, 96 },{ 109, 105, 8 }, },2445{ { 127, 104, 1327 },{ 123, 113, 328 },{ 107, 117, 96 },{ 117, 113, 8 }, }, { { 135, 112, 1327 },{ 131, 121, 328 },{ 115, 125, 96 },{ 125, 121, 8 }, },2446{ { 144, 121, 1327 },{ 140, 130, 328 },{ 124, 134, 96 },{ 134, 130, 8 }, }, { { 152, 129, 1327 },{ 148, 138, 328 },{ 132, 142, 96 },{ 142, 138, 8 }, },2447{ { 160, 137, 1327 },{ 156, 146, 328 },{ 140, 150, 96 },{ 150, 146, 8 }, }, { { 168, 145, 1327 },{ 164, 154, 328 },{ 148, 158, 96 },{ 158, 154, 8 }, },2448{ { 177, 154, 1327 },{ 173, 163, 328 },{ 157, 167, 96 },{ 167, 163, 8 }, }, { { 185, 162, 1327 },{ 181, 171, 328 },{ 165, 175, 96 },{ 175, 171, 8 }, },2449{ { 193, 170, 1327 },{ 189, 179, 328 },{ 173, 183, 96 },{ 183, 179, 8 }, }, { { 201, 178, 1327 },{ 197, 187, 328 },{ 181, 191, 96 },{ 191, 187, 8 }, },2450{ { 210, 187, 1327 },{ 206, 196, 328 },{ 190, 200, 96 },{ 200, 196, 8 }, }, { { 218, 195, 1327 },{ 214, 204, 328 },{ 198, 208, 96 },{ 208, 204, 8 }, },2451{ { 226, 203, 1327 },{ 222, 212, 328 },{ 206, 216, 96 },{ 216, 212, 8 }, }, { { 234, 211, 1327 },{ 230, 220, 328 },{ 214, 224, 96 },{ 224, 220, 8 }, },2452{ { 243, 220, 1327 },{ 239, 229, 328 },{ 223, 233, 96 },{ 233, 229, 8 }, }, { { 251, 228, 1327 },{ 247, 237, 328 },{ 231, 241, 96 },{ 241, 237, 8 }, },2453{ { 239, 249, 3680 },{ 245, 249, 3648 },{ 239, 249, 96 },{ 249, 245, 8 }, }, { { 247, 253, 4040 },{ 255, 253, 8 },{ 247, 253, 456 },{ 255, 253, 8 }, },2454{ { 5, 17, 566 },{ 5, 17, 560 },{ 5, 0, 9 },{ 5, 0, 8 }, }, { { 25, 0, 313 },{ 25, 3, 328 },{ 13, 0, 49 },{ 13, 3, 8 }, },2455{ { 39, 0, 1329 },{ 33, 11, 328 },{ 11, 21, 70 },{ 21, 11, 8 }, }, { { 47, 7, 1329 },{ 41, 19, 328 },{ 29, 7, 33 },{ 29, 19, 8 }, },2456{ { 50, 11, 239 },{ 50, 28, 328 },{ 38, 16, 33 },{ 38, 28, 8 }, }, { { 92, 13, 2423 },{ 58, 36, 328 },{ 46, 24, 33 },{ 46, 36, 8 }, },2457{ { 100, 21, 2423 },{ 66, 44, 328 },{ 54, 32, 33 },{ 54, 44, 8 }, }, { { 86, 7, 1253 },{ 74, 52, 328 },{ 62, 40, 33 },{ 62, 52, 8 }, },2458{ { 95, 16, 1253 },{ 83, 61, 328 },{ 71, 49, 33 },{ 71, 61, 8 }, }, { { 103, 24, 1253 },{ 91, 69, 328 },{ 79, 57, 33 },{ 79, 69, 8 }, },2459{ { 111, 32, 1253 },{ 99, 77, 328 },{ 87, 65, 33 },{ 87, 77, 8 }, }, { { 119, 40, 1253 },{ 107, 85, 328 },{ 95, 73, 33 },{ 95, 85, 8 }, },2460{ { 128, 49, 1253 },{ 116, 94, 328 },{ 104, 82, 33 },{ 104, 94, 8 }, }, { { 136, 57, 1253 },{ 124, 102, 328 },{ 112, 90, 33 },{ 112, 102, 8 }, },2461{ { 144, 65, 1253 },{ 132, 110, 328 },{ 120, 98, 33 },{ 120, 110, 8 }, }, { { 152, 73, 1253 },{ 140, 118, 328 },{ 128, 106, 33 },{ 128, 118, 8 }, },2462{ { 161, 82, 1253 },{ 149, 127, 328 },{ 137, 115, 33 },{ 137, 127, 8 }, }, { { 169, 90, 1253 },{ 157, 135, 328 },{ 145, 123, 33 },{ 145, 135, 8 }, },2463{ { 177, 98, 1253 },{ 165, 143, 328 },{ 153, 131, 33 },{ 153, 143, 8 }, }, { { 185, 106, 1253 },{ 173, 151, 328 },{ 161, 139, 33 },{ 161, 151, 8 }, },2464{ { 194, 115, 1253 },{ 182, 160, 328 },{ 170, 148, 33 },{ 170, 160, 8 }, }, { { 202, 123, 1253 },{ 190, 168, 328 },{ 178, 156, 33 },{ 178, 168, 8 }, },2465{ { 210, 131, 1253 },{ 198, 176, 328 },{ 186, 164, 33 },{ 186, 176, 8 }, }, { { 218, 139, 1253 },{ 206, 184, 328 },{ 194, 172, 33 },{ 194, 184, 8 }, },2466{ { 227, 148, 1253 },{ 215, 193, 328 },{ 203, 181, 33 },{ 203, 193, 8 }, }, { { 235, 156, 1253 },{ 223, 201, 328 },{ 211, 189, 33 },{ 211, 201, 8 }, },2467{ { 243, 164, 1253 },{ 231, 209, 328 },{ 219, 197, 33 },{ 219, 209, 8 }, }, { { 183, 239, 867 },{ 239, 217, 328 },{ 227, 205, 33 },{ 227, 217, 8 }, },2468{ { 254, 214, 1329 },{ 248, 226, 328 },{ 236, 214, 33 },{ 236, 226, 8 }, }, { { 222, 244, 3680 },{ 234, 244, 3648 },{ 244, 222, 33 },{ 244, 234, 8 }, },2469{ { 230, 252, 3680 },{ 242, 252, 3648 },{ 252, 230, 33 },{ 252, 242, 8 }, }, { { 238, 250, 4040 },{ 255, 250, 8 },{ 238, 250, 456 },{ 255, 250, 8 }, },2470{ { 9, 29, 566 },{ 9, 29, 560 },{ 9, 0, 9 },{ 9, 0, 8 }, }, { { 17, 37, 566 },{ 17, 37, 560 },{ 17, 0, 9 },{ 17, 0, 8 }, },2471{ { 45, 0, 313 },{ 45, 0, 312 },{ 25, 0, 49 },{ 25, 7, 8 }, }, { { 14, 63, 2758 },{ 5, 53, 784 },{ 15, 33, 70 },{ 33, 15, 8 }, },2472{ { 71, 6, 1329 },{ 72, 4, 1328 },{ 42, 4, 33 },{ 42, 24, 8 }, }, { { 70, 3, 239 },{ 70, 2, 232 },{ 50, 12, 33 },{ 50, 32, 8 }, },2473{ { 0, 98, 2842 },{ 78, 10, 232 },{ 58, 20, 33 },{ 58, 40, 8 }, }, { { 97, 27, 1329 },{ 86, 18, 232 },{ 66, 28, 33 },{ 66, 48, 8 }, },2474{ { 0, 94, 867 },{ 95, 27, 232 },{ 75, 37, 33 },{ 75, 57, 8 }, }, { { 8, 102, 867 },{ 103, 35, 232 },{ 83, 45, 33 },{ 83, 65, 8 }, },2475{ { 12, 112, 867 },{ 111, 43, 232 },{ 91, 53, 33 },{ 91, 73, 8 }, }, { { 139, 2, 1253 },{ 119, 51, 232 },{ 99, 61, 33 },{ 99, 81, 8 }, },2476{ { 148, 13, 1253 },{ 128, 60, 232 },{ 108, 70, 33 },{ 108, 90, 8 }, }, { { 156, 21, 1253 },{ 136, 68, 232 },{ 116, 78, 33 },{ 116, 98, 8 }, },2477{ { 164, 29, 1253 },{ 144, 76, 232 },{ 124, 86, 33 },{ 124, 106, 8 }, }, { { 172, 37, 1253 },{ 152, 84, 232 },{ 132, 94, 33 },{ 132, 114, 8 }, },2478{ { 181, 46, 1253 },{ 161, 93, 232 },{ 141, 103, 33 },{ 141, 123, 8 }, }, { { 189, 54, 1253 },{ 169, 101, 232 },{ 149, 111, 33 },{ 149, 131, 8 }, },2479{ { 197, 62, 1253 },{ 177, 109, 232 },{ 157, 119, 33 },{ 157, 139, 8 }, }, { { 205, 70, 1253 },{ 185, 117, 232 },{ 165, 127, 33 },{ 165, 147, 8 }, },2480{ { 214, 79, 1253 },{ 194, 126, 232 },{ 174, 136, 33 },{ 174, 156, 8 }, }, { { 222, 87, 1253 },{ 202, 134, 232 },{ 182, 144, 33 },{ 182, 164, 8 }, },2481{ { 230, 95, 1253 },{ 210, 142, 232 },{ 190, 152, 33 },{ 190, 172, 8 }, }, { { 238, 103, 1253 },{ 218, 150, 232 },{ 198, 160, 33 },{ 198, 180, 8 }, },2482{ { 247, 112, 1253 },{ 227, 159, 232 },{ 207, 169, 33 },{ 207, 189, 8 }, }, { { 255, 120, 1253 },{ 235, 167, 232 },{ 215, 177, 33 },{ 215, 197, 8 }, },2483{ { 146, 243, 867 },{ 243, 175, 232 },{ 223, 185, 33 },{ 223, 205, 8 }, }, { { 184, 231, 3682 },{ 203, 251, 784 },{ 231, 193, 33 },{ 231, 213, 8 }, },2484{ { 193, 240, 3682 },{ 222, 240, 3648 },{ 240, 202, 33 },{ 240, 222, 8 }, }, { { 255, 210, 169 },{ 230, 248, 3648 },{ 248, 210, 33 },{ 248, 230, 8 }, },2485{ { 218, 238, 4040 },{ 255, 238, 8 },{ 218, 238, 456 },{ 255, 238, 8 }, }, { { 226, 246, 4040 },{ 255, 246, 8 },{ 226, 246, 456 },{ 255, 246, 8 }, },2486{ { 13, 42, 566 },{ 13, 42, 560 },{ 13, 0, 9 },{ 13, 0, 8 }, }, { { 50, 0, 329 },{ 50, 0, 328 },{ 21, 0, 9 },{ 21, 0, 8 }, },2487{ { 29, 58, 566 },{ 67, 2, 1352 },{ 3, 29, 70 },{ 29, 3, 8 }, }, { { 10, 79, 2758 },{ 76, 11, 1352 },{ 11, 37, 70 },{ 37, 11, 8 }, },2488{ { 7, 75, 790 },{ 7, 75, 784 },{ 20, 46, 70 },{ 46, 20, 8 }, }, { { 15, 83, 790 },{ 97, 1, 1328 },{ 28, 54, 70 },{ 54, 28, 8 }, },2489{ { 101, 7, 1329 },{ 105, 9, 1328 },{ 62, 0, 39 },{ 62, 36, 8 }, }, { { 99, 1, 239 },{ 99, 3, 232 },{ 1, 71, 98 },{ 70, 44, 8 }, },2490{ { 107, 11, 239 },{ 108, 12, 232 },{ 10, 80, 98 },{ 79, 53, 8 }, }, { { 115, 19, 239 },{ 116, 20, 232 },{ 18, 88, 98 },{ 87, 61, 8 }, },2491{ { 123, 27, 239 },{ 124, 28, 232 },{ 26, 96, 98 },{ 95, 69, 8 }, }, { { 131, 35, 239 },{ 132, 36, 232 },{ 34, 104, 98 },{ 103, 77, 8 }, },2492{ { 140, 44, 239 },{ 141, 45, 232 },{ 43, 113, 98 },{ 112, 86, 8 }, }, { { 148, 52, 239 },{ 149, 53, 232 },{ 51, 121, 98 },{ 120, 94, 8 }, },2493{ { 156, 60, 239 },{ 157, 61, 232 },{ 59, 129, 98 },{ 128, 102, 8 }, }, { { 164, 68, 239 },{ 165, 69, 232 },{ 67, 137, 98 },{ 136, 110, 8 }, },2494{ { 173, 77, 239 },{ 174, 78, 232 },{ 76, 146, 98 },{ 145, 119, 8 }, }, { { 181, 85, 239 },{ 182, 86, 232 },{ 84, 154, 98 },{ 153, 127, 8 }, },2495{ { 189, 93, 239 },{ 190, 94, 232 },{ 92, 162, 98 },{ 161, 135, 8 }, }, { { 197, 101, 239 },{ 198, 102, 232 },{ 100, 170, 98 },{ 169, 143, 8 }, },2496{ { 206, 110, 239 },{ 207, 111, 232 },{ 109, 179, 98 },{ 178, 152, 8 }, }, { { 214, 118, 239 },{ 215, 119, 232 },{ 117, 187, 98 },{ 186, 160, 8 }, },2497{ { 222, 126, 239 },{ 223, 127, 232 },{ 125, 195, 98 },{ 194, 168, 8 }, }, { { 230, 134, 239 },{ 231, 135, 232 },{ 133, 203, 98 },{ 202, 176, 8 }, },2498{ { 239, 143, 239 },{ 240, 144, 232 },{ 142, 212, 98 },{ 211, 185, 8 }, }, { { 247, 151, 239 },{ 180, 248, 784 },{ 150, 220, 98 },{ 219, 193, 8 }, },2499{ { 159, 228, 3682 },{ 201, 227, 3648 },{ 158, 228, 98 },{ 227, 201, 8 }, }, { { 181, 249, 3928 },{ 209, 235, 3648 },{ 166, 236, 98 },{ 235, 209, 8 }, },2500{ { 255, 189, 169 },{ 218, 244, 3648 },{ 175, 245, 98 },{ 244, 218, 8 }, }, { { 197, 226, 4040 },{ 226, 252, 3648 },{ 183, 253, 98 },{ 252, 226, 8 }, },2501{ { 205, 234, 4040 },{ 255, 234, 8 },{ 205, 234, 456 },{ 255, 234, 8 }, }, { { 213, 242, 4040 },{ 255, 242, 8 },{ 213, 242, 456 },{ 255, 242, 8 }, },2502{ { 18, 60, 566 },{ 18, 60, 560 },{ 18, 0, 9 },{ 18, 0, 8 }, }, { { 26, 68, 566 },{ 26, 68, 560 },{ 26, 0, 9 },{ 26, 0, 8 }, },2503{ { 34, 76, 566 },{ 34, 76, 560 },{ 34, 0, 9 },{ 34, 0, 8 }, }, { { 5, 104, 2758 },{ 98, 5, 1352 },{ 42, 0, 57 },{ 42, 6, 8 }, },2504{ { 92, 0, 313 },{ 93, 1, 312 },{ 15, 51, 70 },{ 51, 15, 8 }, }, { { 3, 101, 790 },{ 3, 101, 784 },{ 0, 59, 88 },{ 59, 23, 8 }, },2505{ { 14, 107, 790 },{ 11, 109, 784 },{ 31, 67, 70 },{ 67, 31, 8 }, }, { { 19, 117, 790 },{ 19, 117, 784 },{ 39, 75, 70 },{ 75, 39, 8 }, },2506{ { 28, 126, 790 },{ 28, 126, 784 },{ 83, 5, 33 },{ 84, 48, 8 }, }, { { 132, 0, 239 },{ 36, 134, 784 },{ 91, 13, 33 },{ 92, 56, 8 }, },2507{ { 142, 4, 239 },{ 44, 142, 784 },{ 99, 21, 33 },{ 100, 64, 8 }, }, { { 150, 12, 239 },{ 52, 150, 784 },{ 107, 29, 33 },{ 108, 72, 8 }, },2508{ { 159, 21, 239 },{ 61, 159, 784 },{ 116, 38, 33 },{ 117, 81, 8 }, }, { { 167, 29, 239 },{ 69, 167, 784 },{ 124, 46, 33 },{ 125, 89, 8 }, },2509{ { 175, 37, 239 },{ 77, 175, 784 },{ 132, 54, 33 },{ 133, 97, 8 }, }, { { 183, 45, 239 },{ 85, 183, 784 },{ 140, 62, 33 },{ 141, 105, 8 }, },2510{ { 192, 54, 239 },{ 94, 192, 784 },{ 149, 71, 33 },{ 150, 114, 8 }, }, { { 200, 62, 239 },{ 102, 200, 784 },{ 157, 79, 33 },{ 158, 122, 8 }, },2511{ { 208, 70, 239 },{ 110, 208, 784 },{ 165, 87, 33 },{ 166, 130, 8 }, }, { { 216, 78, 239 },{ 118, 216, 784 },{ 173, 95, 33 },{ 174, 138, 8 }, },2512{ { 225, 87, 239 },{ 127, 225, 784 },{ 182, 104, 33 },{ 183, 147, 8 }, }, { { 233, 95, 239 },{ 135, 233, 784 },{ 190, 112, 33 },{ 191, 155, 8 }, },2513{ { 241, 103, 239 },{ 143, 241, 784 },{ 198, 120, 33 },{ 199, 163, 8 }, }, { { 111, 208, 3682 },{ 151, 249, 784 },{ 206, 128, 33 },{ 207, 171, 8 }, },2514{ { 120, 217, 3682 },{ 180, 216, 3648 },{ 215, 137, 33 },{ 216, 180, 8 }, }, { { 128, 225, 3682 },{ 188, 224, 3648 },{ 223, 145, 33 },{ 224, 188, 8 }, },2515{ { 155, 253, 3928 },{ 196, 232, 3648 },{ 231, 153, 33 },{ 232, 196, 8 }, }, { { 144, 241, 3682 },{ 204, 240, 3648 },{ 239, 161, 33 },{ 240, 204, 8 }, },2516{ { 153, 250, 3682 },{ 213, 249, 3648 },{ 248, 170, 33 },{ 249, 213, 8 }, }, { { 179, 221, 4040 },{ 255, 221, 8 },{ 179, 221, 456 },{ 255, 221, 8 }, },2517{ { 187, 229, 4040 },{ 255, 229, 8 },{ 187, 229, 456 },{ 255, 229, 8 }, }, { { 195, 237, 4040 },{ 255, 237, 8 },{ 195, 237, 456 },{ 255, 237, 8 }, },2518{ { 24, 80, 566 },{ 24, 80, 560 },{ 24, 0, 9 },{ 24, 0, 8 }, }, { { 32, 88, 566 },{ 32, 88, 560 },{ 32, 0, 9 },{ 32, 0, 8 }, },2519{ { 40, 96, 566 },{ 40, 96, 560 },{ 40, 0, 9 },{ 40, 0, 8 }, }, { { 48, 104, 566 },{ 48, 104, 560 },{ 48, 0, 9 },{ 48, 0, 8 }, },2520{ { 9, 138, 2758 },{ 130, 7, 1352 },{ 9, 57, 70 },{ 57, 9, 8 }, }, { { 119, 0, 313 },{ 120, 0, 312 },{ 17, 65, 70 },{ 65, 17, 8 }, },2521{ { 0, 128, 784 },{ 128, 6, 312 },{ 25, 73, 70 },{ 73, 25, 8 }, }, { { 6, 137, 790 },{ 5, 136, 784 },{ 33, 81, 70 },{ 81, 33, 8 }, },2522{ { 42, 171, 2758 },{ 14, 145, 784 },{ 42, 90, 70 },{ 90, 42, 8 }, }, { { 50, 179, 2758 },{ 22, 153, 784 },{ 50, 98, 70 },{ 98, 50, 8 }, },2523{ { 58, 187, 2758 },{ 30, 161, 784 },{ 58, 106, 70 },{ 106, 58, 8 }, }, { { 191, 18, 1329 },{ 38, 169, 784 },{ 112, 9, 33 },{ 114, 66, 8 }, },2524{ { 176, 0, 239 },{ 47, 178, 784 },{ 121, 18, 33 },{ 123, 75, 8 }, }, { { 187, 1, 239 },{ 55, 186, 784 },{ 129, 26, 33 },{ 131, 83, 8 }, },2525{ { 195, 10, 239 },{ 63, 194, 784 },{ 137, 34, 33 },{ 139, 91, 8 }, }, { { 203, 18, 239 },{ 71, 202, 784 },{ 145, 42, 33 },{ 147, 99, 8 }, },2526{ { 212, 27, 239 },{ 80, 211, 784 },{ 154, 51, 33 },{ 156, 108, 8 }, }, { { 220, 35, 239 },{ 88, 219, 784 },{ 162, 59, 33 },{ 164, 116, 8 }, },2527{ { 228, 43, 239 },{ 96, 227, 784 },{ 170, 67, 33 },{ 172, 124, 8 }, }, { { 236, 51, 239 },{ 104, 235, 784 },{ 178, 75, 33 },{ 180, 132, 8 }, },2528{ { 245, 60, 239 },{ 113, 244, 784 },{ 187, 84, 33 },{ 189, 141, 8 }, }, { { 91, 194, 3680 },{ 149, 197, 3648 },{ 195, 92, 33 },{ 197, 149, 8 }, },2529{ { 99, 202, 3680 },{ 157, 205, 3648 },{ 203, 100, 33 },{ 205, 157, 8 }, }, { { 107, 210, 3680 },{ 165, 213, 3648 },{ 211, 108, 33 },{ 213, 165, 8 }, },2530{ { 119, 249, 3928 },{ 174, 222, 3648 },{ 220, 117, 33 },{ 222, 174, 8 }, }, { { 127, 255, 856 },{ 182, 230, 3648 },{ 228, 125, 33 },{ 230, 182, 8 }, },2531{ { 255, 135, 169 },{ 190, 238, 3648 },{ 236, 133, 33 },{ 238, 190, 8 }, }, { { 140, 243, 3680 },{ 198, 246, 3648 },{ 244, 141, 33 },{ 246, 198, 8 }, },2532{ { 151, 207, 4040 },{ 255, 207, 8 },{ 151, 207, 456 },{ 255, 207, 8 }, }, { { 159, 215, 4040 },{ 255, 215, 8 },{ 159, 215, 456 },{ 255, 215, 8 }, },2533{ { 167, 223, 4040 },{ 255, 223, 8 },{ 167, 223, 456 },{ 255, 223, 8 }, }, { { 175, 231, 4040 },{ 255, 231, 8 },{ 175, 231, 456 },{ 255, 231, 8 }, },2534{ { 33, 106, 566 },{ 33, 106, 560 },{ 33, 0, 9 },{ 33, 0, 8 }, }, { { 41, 114, 566 },{ 41, 114, 560 },{ 41, 0, 9 },{ 41, 0, 8 }, },2535{ { 49, 122, 566 },{ 49, 122, 560 },{ 49, 0, 9 },{ 49, 0, 8 }, }, { { 57, 130, 566 },{ 57, 130, 560 },{ 57, 0, 9 },{ 57, 0, 8 }, },2536{ { 66, 139, 566 },{ 66, 139, 560 },{ 66, 0, 9 },{ 66, 0, 8 }, }, { { 74, 147, 566 },{ 170, 7, 1352 },{ 8, 74, 70 },{ 74, 8, 8 }, },2537{ { 152, 0, 313 },{ 178, 15, 1352 },{ 0, 82, 80 },{ 82, 16, 8 }, }, { { 162, 0, 313 },{ 186, 23, 1352 },{ 24, 90, 70 },{ 90, 24, 8 }, },2538{ { 0, 171, 784 },{ 195, 32, 1352 },{ 33, 99, 70 },{ 99, 33, 8 }, }, { { 6, 179, 790 },{ 203, 40, 1352 },{ 41, 107, 70 },{ 107, 41, 8 }, },2539{ { 15, 187, 790 },{ 211, 48, 1352 },{ 115, 0, 41 },{ 115, 49, 8 }, }, { { 61, 199, 710 },{ 219, 56, 1352 },{ 57, 123, 70 },{ 123, 57, 8 }, },2540{ { 70, 208, 710 },{ 228, 65, 1352 },{ 66, 132, 70 },{ 132, 66, 8 }, }, { { 78, 216, 710 },{ 236, 73, 1352 },{ 74, 140, 70 },{ 140, 74, 8 }, },2541{ { 86, 224, 710 },{ 244, 81, 1352 },{ 145, 7, 33 },{ 148, 82, 8 }, }, { { 222, 8, 233 },{ 252, 89, 1352 },{ 153, 15, 33 },{ 156, 90, 8 }, },2542{ { 235, 0, 239 },{ 241, 101, 328 },{ 166, 6, 39 },{ 165, 99, 8 }, }, { { 32, 170, 3680 },{ 249, 109, 328 },{ 0, 175, 98 },{ 173, 107, 8 }, },2543{ { 40, 178, 3680 },{ 115, 181, 3648 },{ 8, 183, 98 },{ 181, 115, 8 }, }, { { 48, 186, 3680 },{ 123, 189, 3648 },{ 16, 191, 98 },{ 189, 123, 8 }, },2544{ { 57, 195, 3680 },{ 132, 198, 3648 },{ 25, 200, 98 },{ 198, 132, 8 }, }, { { 67, 243, 3928 },{ 140, 206, 3648 },{ 33, 208, 98 },{ 206, 140, 8 }, },2545{ { 76, 251, 3928 },{ 148, 214, 3648 },{ 41, 216, 98 },{ 214, 148, 8 }, }, { { 86, 255, 856 },{ 156, 222, 3648 },{ 49, 224, 98 },{ 222, 156, 8 }, },2546{ { 255, 93, 169 },{ 165, 231, 3648 },{ 58, 233, 98 },{ 231, 165, 8 }, }, { { 98, 236, 3680 },{ 173, 239, 3648 },{ 66, 241, 98 },{ 239, 173, 8 }, },2547{ { 108, 181, 4040 },{ 181, 247, 3648 },{ 74, 249, 98 },{ 247, 181, 8 }, }, { { 116, 189, 4040 },{ 255, 189, 8 },{ 116, 189, 456 },{ 255, 189, 8 }, },2548{ { 125, 198, 4040 },{ 255, 198, 8 },{ 125, 198, 456 },{ 255, 198, 8 }, }, { { 133, 206, 4040 },{ 255, 206, 8 },{ 133, 206, 456 },{ 255, 206, 8 }, },2549{ { 141, 214, 4040 },{ 255, 214, 8 },{ 141, 214, 456 },{ 255, 214, 8 }, }, { { 149, 222, 4040 },{ 255, 222, 8 },{ 149, 222, 456 },{ 255, 222, 8 }, },2550{ { 47, 183, 566 },{ 47, 183, 560 },{ 47, 0, 9 },{ 47, 0, 8 }, }, { { 55, 191, 566 },{ 55, 191, 560 },{ 55, 0, 9 },{ 55, 0, 8 }, },2551{ { 63, 199, 566 },{ 63, 199, 560 },{ 63, 0, 9 },{ 63, 0, 8 }, }, { { 71, 207, 566 },{ 71, 207, 560 },{ 71, 0, 9 },{ 71, 0, 8 }, },2552{ { 80, 216, 566 },{ 80, 216, 560 },{ 80, 0, 9 },{ 80, 0, 8 }, }, { { 88, 224, 566 },{ 88, 224, 560 },{ 88, 0, 9 },{ 88, 0, 8 }, },2553{ { 3, 233, 710 },{ 3, 233, 704 },{ 2, 96, 70 },{ 96, 2, 8 }, }, { { 11, 241, 710 },{ 11, 241, 704 },{ 10, 104, 70 },{ 104, 10, 8 }, },2554{ { 20, 250, 710 },{ 20, 250, 704 },{ 19, 113, 70 },{ 113, 19, 8 }, }, { { 27, 121, 3654 },{ 27, 121, 3648 },{ 27, 121, 70 },{ 121, 27, 8 }, },2555{ { 35, 129, 3654 },{ 35, 129, 3648 },{ 35, 129, 70 },{ 129, 35, 8 }, }, { { 43, 137, 3654 },{ 43, 137, 3648 },{ 43, 137, 70 },{ 137, 43, 8 }, },2556{ { 52, 146, 3654 },{ 52, 146, 3648 },{ 52, 146, 70 },{ 146, 52, 8 }, }, { { 60, 154, 3654 },{ 60, 154, 3648 },{ 60, 154, 70 },{ 154, 60, 8 }, },2557{ { 68, 162, 3654 },{ 68, 162, 3648 },{ 68, 162, 70 },{ 162, 68, 8 }, }, { { 76, 170, 3654 },{ 76, 170, 3648 },{ 76, 170, 70 },{ 170, 76, 8 }, },2558{ { 85, 179, 3654 },{ 85, 179, 3648 },{ 85, 179, 70 },{ 179, 85, 8 }, }, { { 93, 187, 3654 },{ 93, 187, 3648 },{ 93, 187, 70 },{ 187, 93, 8 }, },2559{ { 101, 195, 3654 },{ 101, 195, 3648 },{ 101, 195, 70 },{ 195, 101, 8 }, }, { { 109, 203, 3654 },{ 109, 203, 3648 },{ 109, 203, 70 },{ 203, 109, 8 }, },2560{ { 118, 212, 3654 },{ 118, 212, 3648 },{ 118, 212, 70 },{ 212, 118, 8 }, }, { { 126, 220, 3654 },{ 126, 220, 3648 },{ 126, 220, 70 },{ 220, 126, 8 }, },2561{ { 134, 228, 3654 },{ 134, 228, 3648 },{ 134, 228, 70 },{ 228, 134, 8 }, }, { { 5, 236, 3680 },{ 142, 236, 3648 },{ 5, 236, 96 },{ 236, 142, 8 }, },2562{ { 14, 245, 3680 },{ 151, 245, 3648 },{ 14, 245, 96 },{ 245, 151, 8 }, }, { { 23, 159, 4040 },{ 159, 253, 3648 },{ 23, 159, 456 },{ 253, 159, 8 }, },2563{ { 31, 167, 4040 },{ 255, 167, 8 },{ 31, 167, 456 },{ 255, 167, 8 }, }, { { 39, 175, 4040 },{ 255, 175, 8 },{ 39, 175, 456 },{ 255, 175, 8 }, },2564{ { 48, 184, 4040 },{ 255, 184, 8 },{ 48, 184, 456 },{ 255, 184, 8 }, }, { { 56, 192, 4040 },{ 255, 192, 8 },{ 56, 192, 456 },{ 255, 192, 8 }, },2565{ { 64, 200, 4040 },{ 255, 200, 8 },{ 64, 200, 456 },{ 255, 200, 8 }, },{ { 72, 208, 4040 },{ 255, 208, 8 },{ 72, 208, 456 },{ 255, 208, 8 }, },25662567};25682569struct dxt5a_block2570{2571uint8_t m_endpoints[2];25722573enum { cTotalSelectorBytes = 6 };2574uint8_t m_selectors[cTotalSelectorBytes];25752576inline void clear()2577{2578basisu::clear_obj(*this);2579}25802581inline uint32_t get_low_alpha() const2582{2583return m_endpoints[0];2584}25852586inline uint32_t get_high_alpha() const2587{2588return m_endpoints[1];2589}25902591inline void set_low_alpha(uint32_t i)2592{2593assert(i <= UINT8_MAX);2594m_endpoints[0] = static_cast<uint8_t>(i);2595}25962597inline void set_high_alpha(uint32_t i)2598{2599assert(i <= UINT8_MAX);2600m_endpoints[1] = static_cast<uint8_t>(i);2601}26022603inline bool is_alpha6_block() const { return get_low_alpha() <= get_high_alpha(); }26042605uint32_t get_endpoints_as_word() const { return m_endpoints[0] | (m_endpoints[1] << 8); }2606uint32_t get_selectors_as_word(uint32_t index) { assert(index < 3); return m_selectors[index * 2] | (m_selectors[index * 2 + 1] << 8); }26072608inline uint32_t get_selector(uint32_t x, uint32_t y) const2609{2610assert((x < 4U) && (y < 4U));26112612uint32_t selector_index = (y * 4) + x;2613uint32_t bit_index = selector_index * cDXT5SelectorBits;26142615uint32_t byte_index = bit_index >> 3;2616uint32_t bit_ofs = bit_index & 7;26172618uint32_t v = m_selectors[byte_index];2619if (byte_index < (cTotalSelectorBytes - 1))2620v |= (m_selectors[byte_index + 1] << 8);26212622return (v >> bit_ofs) & 7;2623}26242625inline void set_selector(uint32_t x, uint32_t y, uint32_t val)2626{2627assert((x < 4U) && (y < 4U) && (val < 8U));26282629uint32_t selector_index = (y * 4) + x;2630uint32_t bit_index = selector_index * cDXT5SelectorBits;26312632uint32_t byte_index = bit_index >> 3;2633uint32_t bit_ofs = bit_index & 7;26342635uint32_t v = m_selectors[byte_index];2636if (byte_index < (cTotalSelectorBytes - 1))2637v |= (m_selectors[byte_index + 1] << 8);26382639v &= (~(7 << bit_ofs));2640v |= (val << bit_ofs);26412642m_selectors[byte_index] = static_cast<uint8_t>(v);2643if (byte_index < (cTotalSelectorBytes - 1))2644m_selectors[byte_index + 1] = static_cast<uint8_t>(v >> 8);2645}26462647enum { cMaxSelectorValues = 8 };26482649static uint32_t get_block_values6(color32* pDst, uint32_t l, uint32_t h)2650{2651pDst[0].a = static_cast<uint8_t>(l);2652pDst[1].a = static_cast<uint8_t>(h);2653pDst[2].a = static_cast<uint8_t>((l * 4 + h) / 5);2654pDst[3].a = static_cast<uint8_t>((l * 3 + h * 2) / 5);2655pDst[4].a = static_cast<uint8_t>((l * 2 + h * 3) / 5);2656pDst[5].a = static_cast<uint8_t>((l + h * 4) / 5);2657pDst[6].a = 0;2658pDst[7].a = 255;2659return 6;2660}26612662static uint32_t get_block_values8(color32* pDst, uint32_t l, uint32_t h)2663{2664pDst[0].a = static_cast<uint8_t>(l);2665pDst[1].a = static_cast<uint8_t>(h);2666pDst[2].a = static_cast<uint8_t>((l * 6 + h) / 7);2667pDst[3].a = static_cast<uint8_t>((l * 5 + h * 2) / 7);2668pDst[4].a = static_cast<uint8_t>((l * 4 + h * 3) / 7);2669pDst[5].a = static_cast<uint8_t>((l * 3 + h * 4) / 7);2670pDst[6].a = static_cast<uint8_t>((l * 2 + h * 5) / 7);2671pDst[7].a = static_cast<uint8_t>((l + h * 6) / 7);2672return 8;2673}26742675static uint32_t get_block_values(color32* pDst, uint32_t l, uint32_t h)2676{2677if (l > h)2678return get_block_values8(pDst, l, h);2679else2680return get_block_values6(pDst, l, h);2681}2682};26832684static void convert_etc1s_to_dxt5a(dxt5a_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector)2685{2686const uint32_t low_selector = pSelector->m_lo_selector;2687const uint32_t high_selector = pSelector->m_hi_selector;26882689const color32& base_color = pEndpoints->m_color5;2690const uint32_t inten_table = pEndpoints->m_inten5;26912692if (low_selector == high_selector)2693{2694uint32_t r;2695decoder_etc_block::get_block_color5_r(base_color, inten_table, low_selector, r);26962697pDst_block->set_low_alpha(r);2698pDst_block->set_high_alpha(r);2699pDst_block->m_selectors[0] = 0;2700pDst_block->m_selectors[1] = 0;2701pDst_block->m_selectors[2] = 0;2702pDst_block->m_selectors[3] = 0;2703pDst_block->m_selectors[4] = 0;2704pDst_block->m_selectors[5] = 0;2705return;2706}2707else if (pSelector->m_num_unique_selectors == 2)2708{2709color32 block_colors[4];27102711decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table);27122713const uint32_t r0 = block_colors[low_selector].r;2714const uint32_t r1 = block_colors[high_selector].r;27152716pDst_block->set_low_alpha(r0);2717pDst_block->set_high_alpha(r1);27182719// TODO: Optimize this2720for (uint32_t y = 0; y < 4; y++)2721{2722for (uint32_t x = 0; x < 4; x++)2723{2724uint32_t s = pSelector->get_selector(x, y);2725pDst_block->set_selector(x, y, (s == high_selector) ? 1 : 0);2726}2727}27282729return;2730}27312732uint32_t selector_range_table = 0;2733for (selector_range_table = 0; selector_range_table < NUM_DXT5A_SELECTOR_RANGES; selector_range_table++)2734if ((low_selector == s_dxt5a_selector_ranges[selector_range_table].m_low) && (high_selector == s_dxt5a_selector_ranges[selector_range_table].m_high))2735break;2736if (selector_range_table >= NUM_DXT5A_SELECTOR_RANGES)2737selector_range_table = 0;27382739const etc1_g_to_dxt5a_conversion* pTable_entry = &g_etc1_g_to_dxt5a[base_color.r + inten_table * 32][selector_range_table];27402741pDst_block->set_low_alpha(pTable_entry->m_lo);2742pDst_block->set_high_alpha(pTable_entry->m_hi);27432744// TODO: Optimize this (like ETC1->BC1)2745for (uint32_t y = 0; y < 4; y++)2746{2747for (uint32_t x = 0; x < 4; x++)2748{2749uint32_t s = pSelector->get_selector(x, y);27502751uint32_t ds = (pTable_entry->m_trans >> (s * 3)) & 7;27522753pDst_block->set_selector(x, y, ds);2754}2755}2756}2757#endif //BASISD_SUPPORT_DXT5A27582759// PVRTC27602761#if BASISD_SUPPORT_PVRTC1 || BASISD_SUPPORT_UASTC2762static const uint16_t g_pvrtc_swizzle_table[256] =2763{27640x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,27650x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,27660x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,27670x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,27680x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,27690x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,27700x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,27710x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x55552772};27732774// Note we can't use simple calculations to convert PVRTC1 encoded endpoint components to/from 8-bits, due to hardware approximations.2775static const uint8_t g_pvrtc_5[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 };2776static const uint8_t g_pvrtc_4[16] = { 0,16,33,49,66,82,99,115,140,156,173,189,206,222,239,255 };2777static const uint8_t g_pvrtc_3[8] = { 0,33,74,107,148,181,222,255 };2778static const uint8_t g_pvrtc_alpha[9] = { 0,34,68,102,136,170,204,238,255 };27792780static const uint8_t g_pvrtc_5_floor[256] =2781{27820,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,27833,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,27847,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,278511,11,11,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,278615,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,278719,19,19,19,19,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,278823,23,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,278927,27,27,27,27,27,27,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,312790};27912792static const uint8_t g_pvrtc_5_ceil[256] =2793{27940,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,27954,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,27968,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,12,12,12,12,12,279712,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,279816,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,279920,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,280024,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,280128,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,312802};28032804static const uint8_t g_pvrtc_4_floor[256] =2805{28060,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,28071,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,28083,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,28095,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,28107,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,28119,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,281211,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,281313,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,152814};28152816static const uint8_t g_pvrtc_4_ceil[256] =2817{28180,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,28192,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,28204,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,28216,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,28228,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,282310,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,282412,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,282514,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,152826};28272828static const uint8_t g_pvrtc_3_floor[256] =2829{28300,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,0,0,0,28310,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,1,1,1,28321,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,28332,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,28343,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,28354,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,28365,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,28376,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,72838};28392840static const uint8_t g_pvrtc_3_ceil[256] =2841{28420,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,1,1,1,28431,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,28442,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,28453,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,28464,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,28475,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,28486,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,28497,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,72850};28512852static const uint8_t g_pvrtc_alpha_floor[256] =2853{28540,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,0,0,0,28550,0,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,1,1,28561,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,28572,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,28583,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,28594,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,28605,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,28616,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,82862};28632864static const uint8_t g_pvrtc_alpha_ceil[256] =2865{28660,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,1,1,1,28671,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,28682,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,28693,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,28704,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,28715,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,28726,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,28737,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,82874};28752876struct pvrtc4_block2877{2878uint32_t m_modulation;2879uint32_t m_endpoints;28802881pvrtc4_block() : m_modulation(0), m_endpoints(0) { }28822883inline bool operator== (const pvrtc4_block& rhs) const2884{2885return (m_modulation == rhs.m_modulation) && (m_endpoints == rhs.m_endpoints);2886}28872888inline void clear()2889{2890m_modulation = 0;2891m_endpoints = 0;2892}28932894inline bool get_block_uses_transparent_modulation() const2895{2896return (m_endpoints & 1) != 0;2897}28982899inline void set_block_uses_transparent_modulation(bool m)2900{2901m_endpoints = (m_endpoints & ~1U) | static_cast<uint32_t>(m);2902}29032904inline bool is_endpoint_opaque(uint32_t endpoint_index) const2905{2906static const uint32_t s_bitmasks[2] = { 0x8000U, 0x80000000U };2907return (m_endpoints & s_bitmasks[basisu::open_range_check(endpoint_index, 2U)]) != 0;2908}29092910inline void set_endpoint_opaque(uint32_t endpoint_index, bool opaque)2911{2912assert(endpoint_index < 2);2913static const uint32_t s_bitmasks[2] = { 0x8000U, 0x80000000U };2914if (opaque)2915m_endpoints |= s_bitmasks[endpoint_index];2916else2917m_endpoints &= ~s_bitmasks[endpoint_index];2918}29192920inline color32 get_endpoint_5554(uint32_t endpoint_index) const2921{2922assert(endpoint_index < 2);2923static const uint32_t s_endpoint_mask[2] = { 0xFFFE, 0xFFFF };2924uint32_t packed = (m_endpoints >> (basisu::open_range_check(endpoint_index, 2U) ? 16 : 0)) & s_endpoint_mask[endpoint_index];29252926uint32_t r, g, b, a;2927if (packed & 0x8000)2928{2929// opaque 554 or 5552930r = (packed >> 10) & 31;2931g = (packed >> 5) & 31;2932b = packed & 31;29332934if (!endpoint_index)2935b |= (b >> 4);29362937a = 0xF;2938}2939else2940{2941// translucent 4433 or 44432942r = (packed >> 7) & 0x1E;2943g = (packed >> 3) & 0x1E;2944b = (packed & 0xF) << 1;29452946r |= (r >> 4);2947g |= (g >> 4);29482949if (!endpoint_index)2950b |= (b >> 3);2951else2952b |= (b >> 4);29532954a = (packed >> 11) & 0xE;2955}29562957assert((r < 32) && (g < 32) && (b < 32) && (a < 16));29582959return color32(r, g, b, a);2960}29612962inline color32 get_endpoint_8888(uint32_t endpoint_index) const2963{2964assert(endpoint_index < 2);2965static const uint32_t s_endpoint_mask[2] = { 0xFFFE, 0xFFFF };2966uint32_t packed = (m_endpoints >> (basisu::open_range_check(endpoint_index, 2U) ? 16 : 0)) & s_endpoint_mask[endpoint_index];29672968uint32_t r, g, b, a;2969if (packed & 0x8000)2970{2971// opaque 554 or 5552972// 1RRRRRGGGGGBBBBM2973// 1RRRRRGGGGGBBBBB2974r = (packed >> 10) & 31;2975g = (packed >> 5) & 31;2976b = packed & 31;29772978r = g_pvrtc_5[r];2979g = g_pvrtc_5[g];29802981if (!endpoint_index)2982b = g_pvrtc_4[b >> 1];2983else2984b = g_pvrtc_5[b];29852986a = 255;2987}2988else2989{2990// translucent 4433 or 44432991// 0AAA RRRR GGGG BBBM2992// 0AAA RRRR GGGG BBBB2993r = (packed >> 8) & 0xF;2994g = (packed >> 4) & 0xF;2995b = packed & 0xF;2996a = (packed >> 12) & 7;29972998r = g_pvrtc_4[r];2999g = g_pvrtc_4[g];30003001if (!endpoint_index)3002b = g_pvrtc_3[b >> 1];3003else3004b = g_pvrtc_4[b];30053006a = g_pvrtc_alpha[a];3007}30083009return color32(r, g, b, a);3010}30113012inline uint32_t get_endpoint_l8(uint32_t endpoint_index) const3013{3014color32 c(get_endpoint_8888(endpoint_index));3015return c.r + c.g + c.b + c.a;3016}30173018inline uint32_t get_opaque_endpoint_l0() const3019{3020uint32_t packed = m_endpoints & 0xFFFE;30213022uint32_t r, g, b;3023assert(packed & 0x8000);30243025// opaque 554 or 5553026r = (packed >> 10) & 31;3027g = (packed >> 5) & 31;3028b = packed & 31;3029b |= (b >> 4);30303031return r + g + b;3032}30333034inline uint32_t get_opaque_endpoint_l1() const3035{3036uint32_t packed = m_endpoints >> 16;30373038uint32_t r, g, b;3039assert(packed & 0x8000);30403041// opaque 554 or 5553042r = (packed >> 10) & 31;3043g = (packed >> 5) & 31;3044b = packed & 31;30453046return r + g + b;3047}30483049static uint32_t get_component_precision_in_bits(uint32_t c, uint32_t endpoint_index, bool opaque_endpoint)3050{3051static const uint32_t s_comp_prec[4][4] =3052{3053// R0 G0 B0 A0 R1 G1 B1 A13054{ 4, 4, 3, 3 },{ 4, 4, 4, 3 }, // transparent endpoint30553056{ 5, 5, 4, 0 },{ 5, 5, 5, 0 } // opaque endpoint3057};3058return s_comp_prec[basisu::open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)][basisu::open_range_check(c, 4U)];3059}30603061static color32 get_color_precision_in_bits(uint32_t endpoint_index, bool opaque_endpoint)3062{3063static const color32 s_color_prec[4] =3064{3065color32(4, 4, 3, 3), color32(4, 4, 4, 3), // transparent endpoint3066color32(5, 5, 4, 0), color32(5, 5, 5, 0) // opaque endpoint3067};3068return s_color_prec[basisu::open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)];3069}30703071inline void set_opaque_endpoint_floor(uint32_t endpoint_index, const color32& c)3072{3073assert(endpoint_index < 2);3074const uint32_t m = m_endpoints & 1;30753076uint32_t r = g_pvrtc_5_floor[c[0]], g = g_pvrtc_5_floor[c[1]], b = c[2];30773078if (!endpoint_index)3079b = g_pvrtc_4_floor[b] << 1;3080else3081b = g_pvrtc_5_floor[b];30823083// rgba=555 here3084assert((r < 32) && (g < 32) && (b < 32));30853086// 1RRRRRGGGGGBBBBM3087// 1RRRRRGGGGGBBBBB30883089// opaque 554 or 5553090uint32_t packed = 0x8000 | (r << 10) | (g << 5) | b;3091if (!endpoint_index)3092packed = (packed & ~1) | m;30933094assert(packed <= 0xFFFF);30953096if (endpoint_index)3097m_endpoints = (m_endpoints & 0xFFFFU) | (packed << 16);3098else3099m_endpoints = (m_endpoints & 0xFFFF0000U) | packed;3100}31013102inline void set_opaque_endpoint_ceil(uint32_t endpoint_index, const color32& c)3103{3104assert(endpoint_index < 2);3105const uint32_t m = m_endpoints & 1;31063107uint32_t r = g_pvrtc_5_ceil[c[0]], g = g_pvrtc_5_ceil[c[1]], b = c[2];31083109if (!endpoint_index)3110b = g_pvrtc_4_ceil[b] << 1;3111else3112b = g_pvrtc_5_ceil[b];31133114// rgba=555 here3115assert((r < 32) && (g < 32) && (b < 32));31163117// 1RRRRRGGGGGBBBBM3118// 1RRRRRGGGGGBBBBB31193120// opaque 554 or 5553121uint32_t packed = 0x8000 | (r << 10) | (g << 5) | b;3122if (!endpoint_index)3123packed |= m;31243125assert(packed <= 0xFFFF);31263127if (endpoint_index)3128m_endpoints = (m_endpoints & 0xFFFFU) | (packed << 16);3129else3130m_endpoints = (m_endpoints & 0xFFFF0000U) | packed;3131}31323133// opaque endpoints: 554 or 5553134// transparent endpoints: 3443 or 34443135inline void set_endpoint_raw(uint32_t endpoint_index, const color32& c, bool opaque_endpoint)3136{3137assert(endpoint_index < 2);3138const uint32_t m = m_endpoints & 1;3139uint32_t r = c[0], g = c[1], b = c[2], a = c[3];31403141uint32_t packed;31423143if (opaque_endpoint)3144{3145if (!endpoint_index)3146{3147// 5543148// 1RRRRRGGGGGBBBBM3149assert((r < 32) && (g < 32) && (b < 16));3150packed = 0x8000 | (r << 10) | (g << 5) | (b << 1) | m;3151}3152else3153{3154// 5553155// 1RRRRRGGGGGBBBBB3156assert((r < 32) && (g < 32) && (b < 32));3157packed = 0x8000 | (r << 10) | (g << 5) | b;3158}3159}3160else3161{3162if (!endpoint_index)3163{3164// 34433165// 0AAA RRRR GGGG BBBM3166assert((r < 16) && (g < 16) && (b < 8) && (a < 8));3167packed = (a << 12) | (r << 8) | (g << 4) | (b << 1) | m;3168}3169else3170{3171// 34443172// 0AAA RRRR GGGG BBBB3173assert((r < 16) && (g < 16) && (b < 16) && (a < 8));3174packed = (a << 12) | (r << 8) | (g << 4) | b;3175}3176}31773178assert(packed <= 0xFFFF);31793180if (endpoint_index)3181m_endpoints = (m_endpoints & 0xFFFFU) | (packed << 16);3182else3183m_endpoints = (m_endpoints & 0xFFFF0000U) | packed;3184}31853186inline void set_endpoint_floor(uint32_t endpoint_index, const color32& c)3187{3188assert(endpoint_index < 2);31893190int a = g_pvrtc_alpha_floor[c.a];3191if (a == 8)3192{3193// 554 or 5553194uint32_t r = g_pvrtc_5_floor[c[0]], g = g_pvrtc_5_floor[c[1]], b = c[2];31953196if (!endpoint_index)3197b = g_pvrtc_4_floor[b];3198else3199b = g_pvrtc_5_floor[b];32003201set_endpoint_raw(endpoint_index, color32(r, g, b, a), true);3202}3203else3204{3205// 4433 or 44433206uint32_t r = g_pvrtc_4_floor[c[0]], g = g_pvrtc_4_floor[c[1]], b = c[2];32073208if (!endpoint_index)3209b = g_pvrtc_3_floor[b];3210else3211b = g_pvrtc_4_floor[b];32123213set_endpoint_raw(endpoint_index, color32(r, g, b, a), false);3214}3215}32163217inline void set_endpoint_ceil(uint32_t endpoint_index, const color32& c)3218{3219assert(endpoint_index < 2);32203221int a = g_pvrtc_alpha_ceil[c.a];3222if (a == 8)3223{3224// 554 or 5553225uint32_t r = g_pvrtc_5_ceil[c[0]], g = g_pvrtc_5_ceil[c[1]], b = c[2];32263227if (!endpoint_index)3228b = g_pvrtc_4_ceil[b];3229else3230b = g_pvrtc_5_ceil[b];32313232set_endpoint_raw(endpoint_index, color32(r, g, b, a), true);3233}3234else3235{3236// 4433 or 44433237uint32_t r = g_pvrtc_4_ceil[c[0]], g = g_pvrtc_4_ceil[c[1]], b = c[2];32383239if (!endpoint_index)3240b = g_pvrtc_3_ceil[b];3241else3242b = g_pvrtc_4_ceil[b];32433244set_endpoint_raw(endpoint_index, color32(r, g, b, a), false);3245}3246}32473248inline uint32_t get_modulation(uint32_t x, uint32_t y) const3249{3250assert((x < 4) && (y < 4));3251return (m_modulation >> ((y * 4 + x) * 2)) & 3;3252}32533254// Scaled by 83255inline const uint32_t* get_scaled_modulation_values(bool block_uses_transparent_modulation) const3256{3257static const uint32_t s_block_scales[2][4] = { { 0, 3, 5, 8 },{ 0, 4, 4, 8 } };3258return s_block_scales[block_uses_transparent_modulation];3259}32603261// Scaled by 83262inline uint32_t get_scaled_modulation(uint32_t x, uint32_t y) const3263{3264return get_scaled_modulation_values(get_block_uses_transparent_modulation())[get_modulation(x, y)];3265}32663267inline void set_modulation(uint32_t x, uint32_t y, uint32_t s)3268{3269assert((x < 4) && (y < 4) && (s < 4));3270uint32_t n = (y * 4 + x) * 2;3271m_modulation = (m_modulation & (~(3 << n))) | (s << n);3272assert(get_modulation(x, y) == s);3273}32743275// Assumes modulation was initialized to 03276inline void set_modulation_fast(uint32_t x, uint32_t y, uint32_t s)3277{3278assert((x < 4) && (y < 4) && (s < 4));3279uint32_t n = (y * 4 + x) * 2;3280m_modulation |= (s << n);3281assert(get_modulation(x, y) == s);3282}3283};32843285#if 03286static const uint8_t g_pvrtc_bilinear_weights[16][4] =3287{3288{ 4, 4, 4, 4 }, { 2, 6, 2, 6 }, { 8, 0, 8, 0 }, { 6, 2, 6, 2 },3289{ 2, 2, 6, 6 }, { 1, 3, 3, 9 }, { 4, 0, 12, 0 }, { 3, 1, 9, 3 },3290{ 8, 8, 0, 0 }, { 4, 12, 0, 0 }, { 16, 0, 0, 0 }, { 12, 4, 0, 0 },3291{ 6, 6, 2, 2 }, { 3, 9, 1, 3 }, { 12, 0, 4, 0 }, { 9, 3, 3, 1 },3292};3293#endif32943295struct pvrtc1_temp_block3296{3297decoder_etc_block m_etc1_block;3298uint32_t m_pvrtc_endpoints;3299};33003301static inline uint32_t get_opaque_endpoint_l0(uint32_t endpoints)3302{3303uint32_t packed = endpoints;33043305uint32_t r, g, b;3306assert(packed & 0x8000);33073308r = (packed >> 10) & 31;3309g = (packed >> 5) & 31;3310b = packed & 30;3311b |= (b >> 4);33123313return r + g + b;3314}33153316static inline uint32_t get_opaque_endpoint_l1(uint32_t endpoints)3317{3318uint32_t packed = endpoints >> 16;33193320uint32_t r, g, b;3321assert(packed & 0x8000);33223323r = (packed >> 10) & 31;3324g = (packed >> 5) & 31;3325b = packed & 31;33263327return r + g + b;3328}33293330static color32 get_endpoint_8888(uint32_t endpoints, uint32_t endpoint_index)3331{3332assert(endpoint_index < 2);3333static const uint32_t s_endpoint_mask[2] = { 0xFFFE, 0xFFFF };3334uint32_t packed = (endpoints >> (basisu::open_range_check(endpoint_index, 2U) ? 16 : 0)) & s_endpoint_mask[endpoint_index];33353336uint32_t r, g, b, a;3337if (packed & 0x8000)3338{3339// opaque 554 or 5553340// 1RRRRRGGGGGBBBBM3341// 1RRRRRGGGGGBBBBB3342r = (packed >> 10) & 31;3343g = (packed >> 5) & 31;3344b = packed & 31;33453346r = g_pvrtc_5[r];3347g = g_pvrtc_5[g];33483349if (!endpoint_index)3350b = g_pvrtc_4[b >> 1];3351else3352b = g_pvrtc_5[b];33533354a = 255;3355}3356else3357{3358// translucent 4433 or 44433359// 0AAA RRRR GGGG BBBM3360// 0AAA RRRR GGGG BBBB3361r = (packed >> 8) & 0xF;3362g = (packed >> 4) & 0xF;3363b = packed & 0xF;3364a = (packed >> 12) & 7;33653366r = g_pvrtc_4[r];3367g = g_pvrtc_4[g];33683369if (!endpoint_index)3370b = g_pvrtc_3[b >> 1];3371else3372b = g_pvrtc_4[b];33733374a = g_pvrtc_alpha[a];3375}33763377return color32(r, g, b, a);3378}33793380static uint32_t get_endpoint_l8(uint32_t endpoints, uint32_t endpoint_index)3381{3382color32 c(get_endpoint_8888(endpoints, endpoint_index));3383return c.r + c.g + c.b + c.a;3384}3385#endif33863387#if BASISD_SUPPORT_PVRTC13388// TODO: Support decoding a non-pow2 ETC1S texture into the next larger pow2 PVRTC texture.3389static void fixup_pvrtc1_4_modulation_rgb(const decoder_etc_block* pETC_Blocks, const uint32_t* pPVRTC_endpoints, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y)3390{3391const uint32_t x_mask = num_blocks_x - 1;3392const uint32_t y_mask = num_blocks_y - 1;3393const uint32_t x_bits = basisu::total_bits(x_mask);3394const uint32_t y_bits = basisu::total_bits(y_mask);3395const uint32_t min_bits = basisu::minimum(x_bits, y_bits);3396//const uint32_t max_bits = basisu::maximum(x_bits, y_bits);3397const uint32_t swizzle_mask = (1 << (min_bits * 2)) - 1;33983399uint32_t block_index = 0;34003401// really 3x33402int e0[4][4], e1[4][4];34033404for (int y = 0; y < static_cast<int>(num_blocks_y); y++)3405{3406const uint32_t* pE_rows[3];34073408for (int ey = 0; ey < 3; ey++)3409{3410int by = y + ey - 1;34113412const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x];34133414pE_rows[ey] = pE;34153416for (int ex = 0; ex < 3; ex++)3417{3418int bx = 0 + ex - 1;34193420const uint32_t e = pE[bx & x_mask];34213422e0[ex][ey] = (get_opaque_endpoint_l0(e) * 255) / 31;3423e1[ex][ey] = (get_opaque_endpoint_l1(e) * 255) / 31;3424}3425}34263427const uint32_t y_swizzle = (g_pvrtc_swizzle_table[y >> 8] << 16) | g_pvrtc_swizzle_table[y & 0xFF];34283429for (int x = 0; x < static_cast<int>(num_blocks_x); x++, block_index++)3430{3431const decoder_etc_block& src_block = pETC_Blocks[block_index];34323433const uint32_t x_swizzle = (g_pvrtc_swizzle_table[x >> 8] << 17) | (g_pvrtc_swizzle_table[x & 0xFF] << 1);34343435uint32_t swizzled = x_swizzle | y_swizzle;3436if (num_blocks_x != num_blocks_y)3437{3438swizzled &= swizzle_mask;34393440if (num_blocks_x > num_blocks_y)3441swizzled |= ((x >> min_bits) << (min_bits * 2));3442else3443swizzled |= ((y >> min_bits) << (min_bits * 2));3444}34453446pvrtc4_block* pDst_block = static_cast<pvrtc4_block*>(pDst_blocks) + swizzled;3447pDst_block->m_endpoints = pPVRTC_endpoints[block_index];34483449uint32_t base_r = g_etc_5_to_8[src_block.m_differential.m_red1];3450uint32_t base_g = g_etc_5_to_8[src_block.m_differential.m_green1];3451uint32_t base_b = g_etc_5_to_8[src_block.m_differential.m_blue1];34523453const int* pInten_table48 = g_etc1_inten_tables48[src_block.m_differential.m_cw1];3454int by = (base_r + base_g + base_b) * 16;3455int block_colors_y_x16[4];3456block_colors_y_x16[0] = by + pInten_table48[2];3457block_colors_y_x16[1] = by + pInten_table48[3];3458block_colors_y_x16[2] = by + pInten_table48[1];3459block_colors_y_x16[3] = by + pInten_table48[0];34603461{3462const uint32_t ex = 2;3463int bx = x + ex - 1;3464bx &= x_mask;34653466#define DO_ROW(ey) \3467{ \3468const uint32_t e = pE_rows[ey][bx]; \3469e0[ex][ey] = (get_opaque_endpoint_l0(e) * 255) / 31; \3470e1[ex][ey] = (get_opaque_endpoint_l1(e) * 255) / 31; \3471}34723473DO_ROW(0);3474DO_ROW(1);3475DO_ROW(2);3476#undef DO_ROW3477}34783479uint32_t mod = 0;34803481uint32_t lookup_x[4];34823483#define DO_LOOKUP(lx) { \3484const uint32_t byte_ofs = 7 - (((lx) * 4) >> 3); \3485const uint32_t lsb_bits = src_block.m_bytes[byte_ofs] >> (((lx) & 1) * 4); \3486const uint32_t msb_bits = src_block.m_bytes[byte_ofs - 2] >> (((lx) & 1) * 4); \3487lookup_x[lx] = (lsb_bits & 0xF) | ((msb_bits & 0xF) << 4); }34883489DO_LOOKUP(0);3490DO_LOOKUP(1);3491DO_LOOKUP(2);3492DO_LOOKUP(3);3493#undef DO_LOOKUP34943495#define DO_PIX(lx, ly, w0, w1, w2, w3) \3496{ \3497int ca_l = a0 * w0 + a1 * w1 + a2 * w2 + a3 * w3; \3498int cb_l = b0 * w0 + b1 * w1 + b2 * w2 + b3 * w3; \3499int cl = block_colors_y_x16[g_etc1_x_selector_unpack[ly][lookup_x[lx]]]; \3500int dl = cb_l - ca_l; \3501int vl = cl - ca_l; \3502int p = vl * 16; \3503if (ca_l > cb_l) { p = -p; dl = -dl; } \3504uint32_t m = 0; \3505if (p > 3 * dl) m = (uint32_t)(1 << ((ly) * 8 + (lx) * 2)); \3506if (p > 8 * dl) m = (uint32_t)(2 << ((ly) * 8 + (lx) * 2)); \3507if (p > 13 * dl) m = (uint32_t)(3 << ((ly) * 8 + (lx) * 2)); \3508mod |= m; \3509}35103511{3512const uint32_t ex = 0, ey = 0;3513const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];3514const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];3515DO_PIX(0, 0, 4, 4, 4, 4);3516DO_PIX(1, 0, 2, 6, 2, 6);3517DO_PIX(0, 1, 2, 2, 6, 6);3518DO_PIX(1, 1, 1, 3, 3, 9);3519}35203521{3522const uint32_t ex = 1, ey = 0;3523const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];3524const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];3525DO_PIX(2, 0, 8, 0, 8, 0);3526DO_PIX(3, 0, 6, 2, 6, 2);3527DO_PIX(2, 1, 4, 0, 12, 0);3528DO_PIX(3, 1, 3, 1, 9, 3);3529}35303531{3532const uint32_t ex = 0, ey = 1;3533const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];3534const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];3535DO_PIX(0, 2, 8, 8, 0, 0);3536DO_PIX(1, 2, 4, 12, 0, 0);3537DO_PIX(0, 3, 6, 6, 2, 2);3538DO_PIX(1, 3, 3, 9, 1, 3);3539}35403541{3542const uint32_t ex = 1, ey = 1;3543const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];3544const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];3545DO_PIX(2, 2, 16, 0, 0, 0);3546DO_PIX(3, 2, 12, 4, 0, 0);3547DO_PIX(2, 3, 12, 0, 4, 0);3548DO_PIX(3, 3, 9, 3, 3, 1);3549}3550#undef DO_PIX35513552pDst_block->m_modulation = mod;35533554e0[0][0] = e0[1][0]; e0[1][0] = e0[2][0];3555e0[0][1] = e0[1][1]; e0[1][1] = e0[2][1];3556e0[0][2] = e0[1][2]; e0[1][2] = e0[2][2];35573558e1[0][0] = e1[1][0]; e1[1][0] = e1[2][0];3559e1[0][1] = e1[1][1]; e1[1][1] = e1[2][1];3560e1[0][2] = e1[1][2]; e1[1][2] = e1[2][2];35613562} // x3563} // y3564}35653566static void fixup_pvrtc1_4_modulation_rgba(3567const decoder_etc_block* pETC_Blocks,3568const uint32_t* pPVRTC_endpoints,3569void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, void *pAlpha_blocks,3570const endpoint* pEndpoints, const selector* pSelectors)3571{3572const uint32_t x_mask = num_blocks_x - 1;3573const uint32_t y_mask = num_blocks_y - 1;3574const uint32_t x_bits = basisu::total_bits(x_mask);3575const uint32_t y_bits = basisu::total_bits(y_mask);3576const uint32_t min_bits = basisu::minimum(x_bits, y_bits);3577//const uint32_t max_bits = basisu::maximum(x_bits, y_bits);3578const uint32_t swizzle_mask = (1 << (min_bits * 2)) - 1;35793580uint32_t block_index = 0;35813582// really 3x33583int e0[4][4], e1[4][4];35843585for (int y = 0; y < static_cast<int>(num_blocks_y); y++)3586{3587const uint32_t* pE_rows[3];35883589for (int ey = 0; ey < 3; ey++)3590{3591int by = y + ey - 1;35923593const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x];35943595pE_rows[ey] = pE;35963597for (int ex = 0; ex < 3; ex++)3598{3599int bx = 0 + ex - 1;36003601const uint32_t e = pE[bx & x_mask];36023603e0[ex][ey] = get_endpoint_l8(e, 0);3604e1[ex][ey] = get_endpoint_l8(e, 1);3605}3606}36073608const uint32_t y_swizzle = (g_pvrtc_swizzle_table[y >> 8] << 16) | g_pvrtc_swizzle_table[y & 0xFF];36093610for (int x = 0; x < static_cast<int>(num_blocks_x); x++, block_index++)3611{3612const decoder_etc_block& src_block = pETC_Blocks[block_index];36133614const uint16_t* pSrc_alpha_block = reinterpret_cast<const uint16_t*>(static_cast<const uint32_t*>(pAlpha_blocks) + x + (y * num_blocks_x));3615const endpoint* pAlpha_endpoints = &pEndpoints[pSrc_alpha_block[0]];3616const selector* pAlpha_selectors = &pSelectors[pSrc_alpha_block[1]];36173618const uint32_t x_swizzle = (g_pvrtc_swizzle_table[x >> 8] << 17) | (g_pvrtc_swizzle_table[x & 0xFF] << 1);36193620uint32_t swizzled = x_swizzle | y_swizzle;3621if (num_blocks_x != num_blocks_y)3622{3623swizzled &= swizzle_mask;36243625if (num_blocks_x > num_blocks_y)3626swizzled |= ((x >> min_bits) << (min_bits * 2));3627else3628swizzled |= ((y >> min_bits) << (min_bits * 2));3629}36303631pvrtc4_block* pDst_block = static_cast<pvrtc4_block*>(pDst_blocks) + swizzled;3632pDst_block->m_endpoints = pPVRTC_endpoints[block_index];36333634uint32_t base_r = g_etc_5_to_8[src_block.m_differential.m_red1];3635uint32_t base_g = g_etc_5_to_8[src_block.m_differential.m_green1];3636uint32_t base_b = g_etc_5_to_8[src_block.m_differential.m_blue1];36373638const int* pInten_table48 = g_etc1_inten_tables48[src_block.m_differential.m_cw1];3639int by = (base_r + base_g + base_b) * 16;3640int block_colors_y_x16[4];3641block_colors_y_x16[0] = basisu::clamp<int>(by + pInten_table48[0], 0, 48 * 255);3642block_colors_y_x16[1] = basisu::clamp<int>(by + pInten_table48[1], 0, 48 * 255);3643block_colors_y_x16[2] = basisu::clamp<int>(by + pInten_table48[2], 0, 48 * 255);3644block_colors_y_x16[3] = basisu::clamp<int>(by + pInten_table48[3], 0, 48 * 255);36453646uint32_t alpha_base_g = g_etc_5_to_8[pAlpha_endpoints->m_color5.g] * 16;3647const int* pInten_table16 = g_etc1_inten_tables16[pAlpha_endpoints->m_inten5];3648int alpha_block_colors_x16[4];3649alpha_block_colors_x16[0] = basisu::clamp<int>(alpha_base_g + pInten_table16[0], 0, 16 * 255);3650alpha_block_colors_x16[1] = basisu::clamp<int>(alpha_base_g + pInten_table16[1], 0, 16 * 255);3651alpha_block_colors_x16[2] = basisu::clamp<int>(alpha_base_g + pInten_table16[2], 0, 16 * 255);3652alpha_block_colors_x16[3] = basisu::clamp<int>(alpha_base_g + pInten_table16[3], 0, 16 * 255);36533654// clamp((base_r + base_g + base_b) * 16 + color_inten[s] * 48) + clamp(alpha_base_g * 16 + alpha_inten[as] * 16)36553656{3657const uint32_t ex = 2;3658int bx = x + ex - 1;3659bx &= x_mask;36603661#define DO_ROW(ey) \3662{ \3663const uint32_t e = pE_rows[ey][bx]; \3664e0[ex][ey] = get_endpoint_l8(e, 0); \3665e1[ex][ey] = get_endpoint_l8(e, 1); \3666}36673668DO_ROW(0);3669DO_ROW(1);3670DO_ROW(2);3671#undef DO_ROW3672}36733674uint32_t mod = 0;36753676#define DO_PIX(lx, ly, w0, w1, w2, w3) \3677{ \3678int ca_l = a0 * w0 + a1 * w1 + a2 * w2 + a3 * w3; \3679int cb_l = b0 * w0 + b1 * w1 + b2 * w2 + b3 * w3; \3680int cl = block_colors_y_x16[(src_block.m_bytes[4 + ly] >> (lx * 2)) & 3] + alpha_block_colors_x16[(pAlpha_selectors->m_selectors[ly] >> (lx * 2)) & 3]; \3681int dl = cb_l - ca_l; \3682int vl = cl - ca_l; \3683int p = vl * 16; \3684if (ca_l > cb_l) { p = -p; dl = -dl; } \3685uint32_t m = 0; \3686if (p > 3 * dl) m = (uint32_t)(1 << ((ly) * 8 + (lx) * 2)); \3687if (p > 8 * dl) m = (uint32_t)(2 << ((ly) * 8 + (lx) * 2)); \3688if (p > 13 * dl) m = (uint32_t)(3 << ((ly) * 8 + (lx) * 2)); \3689mod |= m; \3690}36913692{3693const uint32_t ex = 0, ey = 0;3694const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];3695const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];3696DO_PIX(0, 0, 4, 4, 4, 4);3697DO_PIX(1, 0, 2, 6, 2, 6);3698DO_PIX(0, 1, 2, 2, 6, 6);3699DO_PIX(1, 1, 1, 3, 3, 9);3700}37013702{3703const uint32_t ex = 1, ey = 0;3704const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];3705const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];3706DO_PIX(2, 0, 8, 0, 8, 0);3707DO_PIX(3, 0, 6, 2, 6, 2);3708DO_PIX(2, 1, 4, 0, 12, 0);3709DO_PIX(3, 1, 3, 1, 9, 3);3710}37113712{3713const uint32_t ex = 0, ey = 1;3714const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];3715const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];3716DO_PIX(0, 2, 8, 8, 0, 0);3717DO_PIX(1, 2, 4, 12, 0, 0);3718DO_PIX(0, 3, 6, 6, 2, 2);3719DO_PIX(1, 3, 3, 9, 1, 3);3720}37213722{3723const uint32_t ex = 1, ey = 1;3724const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];3725const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];3726DO_PIX(2, 2, 16, 0, 0, 0);3727DO_PIX(3, 2, 12, 4, 0, 0);3728DO_PIX(2, 3, 12, 0, 4, 0);3729DO_PIX(3, 3, 9, 3, 3, 1);3730}3731#undef DO_PIX37323733pDst_block->m_modulation = mod;37343735e0[0][0] = e0[1][0]; e0[1][0] = e0[2][0];3736e0[0][1] = e0[1][1]; e0[1][1] = e0[2][1];3737e0[0][2] = e0[1][2]; e0[1][2] = e0[2][2];37383739e1[0][0] = e1[1][0]; e1[1][0] = e1[2][0];3740e1[0][1] = e1[1][1]; e1[1][1] = e1[2][1];3741e1[0][2] = e1[1][2]; e1[1][2] = e1[2][2];37423743} // x3744} // y3745}3746#endif // BASISD_SUPPORT_PVRTC137473748#if BASISD_SUPPORT_BC7_MODE53749static dxt_selector_range g_etc1_to_bc7_m5_selector_ranges[] =3750{3751{ 0, 3 },3752{ 1, 3 },3753{ 0, 2 },3754{ 1, 2 },3755{ 2, 3 },3756{ 0, 1 },3757};37583759const uint32_t NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES = sizeof(g_etc1_to_bc7_m5_selector_ranges) / sizeof(g_etc1_to_bc7_m5_selector_ranges[0]);37603761static uint32_t g_etc1_to_bc7_m5_selector_range_index[4][4];37623763const uint32_t NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS = 10;3764static const uint8_t g_etc1_to_bc7_m5_selector_mappings[NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS][4] =3765{3766{ 0, 0, 1, 1 },3767{ 0, 0, 1, 2 },3768{ 0, 0, 1, 3 },3769{ 0, 0, 2, 3 },3770{ 0, 1, 1, 1 },3771{ 0, 1, 2, 2 },3772{ 0, 1, 2, 3 },3773{ 0, 2, 3, 3 },3774{ 1, 2, 2, 2 },3775{ 1, 2, 3, 3 },3776};37773778struct etc1_to_bc7_m5_solution3779{3780uint8_t m_lo;3781uint8_t m_hi;3782uint16_t m_err;3783};37843785static const etc1_to_bc7_m5_solution g_etc1_to_bc7_m5_color[32 * 8 * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS * NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES] = {3786#include "basisu_transcoder_tables_bc7_m5_color.inc"3787};37883789static dxt_selector_range g_etc1_to_bc7_m5a_selector_ranges[] =3790{3791{ 0, 3 },3792{ 1, 3 },3793{ 0, 2 },3794{ 1, 2 },3795{ 2, 3 },3796{ 0, 1 }3797};37983799const uint32_t NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES = sizeof(g_etc1_to_bc7_m5a_selector_ranges) / sizeof(g_etc1_to_bc7_m5a_selector_ranges[0]);38003801static uint32_t g_etc1_to_bc7_m5a_selector_range_index[4][4];38023803struct etc1_g_to_bc7_m5a_conversion3804{3805uint8_t m_lo, m_hi;3806uint8_t m_trans;3807};38083809static etc1_g_to_bc7_m5a_conversion g_etc1_g_to_bc7_m5a[8 * 32 * NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES] =3810{3811#include "basisu_transcoder_tables_bc7_m5_alpha.inc"3812};38133814static inline uint32_t set_block_bits(uint8_t* pBytes, uint32_t val, uint32_t num_bits, uint32_t cur_ofs)3815{3816assert(num_bits < 32);3817assert(val < (1ULL << num_bits));38183819uint32_t mask = static_cast<uint32_t>((1ULL << num_bits) - 1);38203821while (num_bits)3822{3823const uint32_t n = basisu::minimum<uint32_t>(8 - (cur_ofs & 7), num_bits);38243825pBytes[cur_ofs >> 3] &= ~static_cast<uint8_t>(mask << (cur_ofs & 7));3826pBytes[cur_ofs >> 3] |= static_cast<uint8_t>(val << (cur_ofs & 7));38273828val >>= n;3829mask >>= n;38303831num_bits -= n;3832cur_ofs += n;3833}38343835return cur_ofs;3836}38373838struct bc7_mode_53839{3840union3841{3842struct3843{3844uint64_t m_mode : 6;3845uint64_t m_rot : 2;38463847uint64_t m_r0 : 7;3848uint64_t m_r1 : 7;3849uint64_t m_g0 : 7;3850uint64_t m_g1 : 7;3851uint64_t m_b0 : 7;3852uint64_t m_b1 : 7;3853uint64_t m_a0 : 8;3854uint64_t m_a1_0 : 6;38553856} m_lo;38573858uint64_t m_lo_bits;3859};38603861union3862{3863struct3864{3865uint64_t m_a1_1 : 2;38663867// bit 23868uint64_t m_c00 : 1;3869uint64_t m_c10 : 2;3870uint64_t m_c20 : 2;3871uint64_t m_c30 : 2;38723873uint64_t m_c01 : 2;3874uint64_t m_c11 : 2;3875uint64_t m_c21 : 2;3876uint64_t m_c31 : 2;38773878uint64_t m_c02 : 2;3879uint64_t m_c12 : 2;3880uint64_t m_c22 : 2;3881uint64_t m_c32 : 2;38823883uint64_t m_c03 : 2;3884uint64_t m_c13 : 2;3885uint64_t m_c23 : 2;3886uint64_t m_c33 : 2;38873888// bit 333889uint64_t m_a00 : 1;3890uint64_t m_a10 : 2;3891uint64_t m_a20 : 2;3892uint64_t m_a30 : 2;38933894uint64_t m_a01 : 2;3895uint64_t m_a11 : 2;3896uint64_t m_a21 : 2;3897uint64_t m_a31 : 2;38983899uint64_t m_a02 : 2;3900uint64_t m_a12 : 2;3901uint64_t m_a22 : 2;3902uint64_t m_a32 : 2;39033904uint64_t m_a03 : 2;3905uint64_t m_a13 : 2;3906uint64_t m_a23 : 2;3907uint64_t m_a33 : 2;39083909} m_hi;39103911uint64_t m_hi_bits;3912};3913};39143915#if BASISD_WRITE_NEW_BC7_MODE5_TABLES3916static void create_etc1_to_bc7_m5_color_conversion_table()3917{3918FILE* pFile = nullptr;3919fopen_s(&pFile, "basisu_transcoder_tables_bc7_m5_color.inc", "w");39203921uint32_t n = 0;39223923for (int inten = 0; inten < 8; inten++)3924{3925for (uint32_t g = 0; g < 32; g++)3926{3927color32 block_colors[4];3928decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);39293930for (uint32_t sr = 0; sr < NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES; sr++)3931{3932const uint32_t low_selector = g_etc1_to_bc7_m5_selector_ranges[sr].m_low;3933const uint32_t high_selector = g_etc1_to_bc7_m5_selector_ranges[sr].m_high;39343935for (uint32_t m = 0; m < NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS; m++)3936{3937uint32_t best_lo = 0;3938uint32_t best_hi = 0;3939uint64_t best_err = UINT64_MAX;39403941for (uint32_t hi = 0; hi <= 127; hi++)3942{3943for (uint32_t lo = 0; lo <= 127; lo++)3944{3945uint32_t colors[4];39463947colors[0] = (lo << 1) | (lo >> 6);3948colors[3] = (hi << 1) | (hi >> 6);39493950colors[1] = (colors[0] * (64 - 21) + colors[3] * 21 + 32) / 64;3951colors[2] = (colors[0] * (64 - 43) + colors[3] * 43 + 32) / 64;39523953uint64_t total_err = 0;39543955for (uint32_t s = low_selector; s <= high_selector; s++)3956{3957int err = block_colors[s].g - colors[g_etc1_to_bc7_m5_selector_mappings[m][s]];39583959int err_scale = 1;3960// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor3961// the low/high selectors which are clamping to either 0 or 255.3962if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))3963err_scale = 5;39643965total_err += (err * err) * err_scale;3966}39673968if (total_err < best_err)3969{3970best_err = total_err;3971best_lo = lo;3972best_hi = hi;3973}3974}3975}39763977best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);39783979fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);3980n++;3981if ((n & 31) == 31)3982fprintf(pFile, "\n");3983} // m3984} // sr3985} // g3986} // inten39873988fclose(pFile);3989}39903991static void create_etc1_to_bc7_m5_alpha_conversion_table()3992{3993FILE* pFile = nullptr;3994fopen_s(&pFile, "basisu_transcoder_tables_bc7_m5_alpha.inc", "w");39953996uint32_t n = 0;39973998for (int inten = 0; inten < 8; inten++)3999{4000for (uint32_t g = 0; g < 32; g++)4001{4002color32 block_colors[4];4003decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);40044005for (uint32_t sr = 0; sr < NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES; sr++)4006{4007const uint32_t low_selector = g_etc1_to_bc7_m5a_selector_ranges[sr].m_low;4008const uint32_t high_selector = g_etc1_to_bc7_m5a_selector_ranges[sr].m_high;40094010uint32_t best_lo = 0;4011uint32_t best_hi = 0;4012uint64_t best_err = UINT64_MAX;4013uint32_t best_output_selectors = 0;40144015for (uint32_t hi = 0; hi <= 255; hi++)4016{4017for (uint32_t lo = 0; lo <= 255; lo++)4018{4019uint32_t colors[4];40204021colors[0] = lo;4022colors[3] = hi;40234024colors[1] = (colors[0] * (64 - 21) + colors[3] * 21 + 32) / 64;4025colors[2] = (colors[0] * (64 - 43) + colors[3] * 43 + 32) / 64;40264027uint64_t total_err = 0;4028uint32_t output_selectors = 0;40294030for (uint32_t s = low_selector; s <= high_selector; s++)4031{4032int best_mapping_err = INT_MAX;4033int best_k = 0;4034for (int k = 0; k < 4; k++)4035{4036int mapping_err = block_colors[s].g - colors[k];4037mapping_err *= mapping_err;40384039// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor4040// the low/high selectors which are clamping to either 0 or 255.4041if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))4042mapping_err *= 5;40434044if (mapping_err < best_mapping_err)4045{4046best_mapping_err = mapping_err;4047best_k = k;4048}4049} // k40504051total_err += best_mapping_err;4052output_selectors |= (best_k << (s * 2));4053} // s40544055if (total_err < best_err)4056{4057best_err = total_err;4058best_lo = lo;4059best_hi = hi;4060best_output_selectors = output_selectors;4061}40624063} // lo4064} // hi40654066fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, best_output_selectors);4067n++;4068if ((n & 31) == 31)4069fprintf(pFile, "\n");40704071} // sr4072} // g4073} // inten40744075fclose(pFile);4076}4077#endif // BASISD_WRITE_NEW_BC7_MODE5_TABLES40784079struct bc7_m5_match_entry4080{4081uint8_t m_hi;4082uint8_t m_lo;4083};40844085static bc7_m5_match_entry g_bc7_m5_equals_1[256] =4086{4087{0,0},{1,0},{3,0},{4,0},{6,0},{7,0},{9,0},{10,0},{12,0},{13,0},{15,0},{16,0},{18,0},{20,0},{21,0},{23,0},4088{24,0},{26,0},{27,0},{29,0},{30,0},{32,0},{33,0},{35,0},{36,0},{38,0},{39,0},{41,0},{42,0},{44,0},{45,0},{47,0},4089{48,0},{50,0},{52,0},{53,0},{55,0},{56,0},{58,0},{59,0},{61,0},{62,0},{64,0},{65,0},{66,0},{68,0},{69,0},{71,0},4090{72,0},{74,0},{75,0},{77,0},{78,0},{80,0},{82,0},{83,0},{85,0},{86,0},{88,0},{89,0},{91,0},{92,0},{94,0},{95,0},4091{97,0},{98,0},{100,0},{101,0},{103,0},{104,0},{106,0},{107,0},{109,0},{110,0},{112,0},{114,0},{115,0},{117,0},{118,0},{120,0},4092{121,0},{123,0},{124,0},{126,0},{127,0},{127,1},{126,2},{126,3},{127,3},{127,4},{126,5},{126,6},{127,6},{127,7},{126,8},{126,9},4093{127,9},{127,10},{126,11},{126,12},{127,12},{127,13},{126,14},{125,15},{127,15},{126,16},{126,17},{127,17},{127,18},{126,19},{126,20},{127,20},4094{127,21},{126,22},{126,23},{127,23},{127,24},{126,25},{126,26},{127,26},{127,27},{126,28},{126,29},{127,29},{127,30},{126,31},{126,32},{127,32},4095{127,33},{126,34},{126,35},{127,35},{127,36},{126,37},{126,38},{127,38},{127,39},{126,40},{126,41},{127,41},{127,42},{126,43},{126,44},{127,44},4096{127,45},{126,46},{125,47},{127,47},{126,48},{126,49},{127,49},{127,50},{126,51},{126,52},{127,52},{127,53},{126,54},{126,55},{127,55},{127,56},4097{126,57},{126,58},{127,58},{127,59},{126,60},{126,61},{127,61},{127,62},{126,63},{125,64},{126,64},{126,65},{127,65},{127,66},{126,67},{126,68},4098{127,68},{127,69},{126,70},{126,71},{127,71},{127,72},{126,73},{126,74},{127,74},{127,75},{126,76},{125,77},{127,77},{126,78},{126,79},{127,79},4099{127,80},{126,81},{126,82},{127,82},{127,83},{126,84},{126,85},{127,85},{127,86},{126,87},{126,88},{127,88},{127,89},{126,90},{126,91},{127,91},4100{127,92},{126,93},{126,94},{127,94},{127,95},{126,96},{126,97},{127,97},{127,98},{126,99},{126,100},{127,100},{127,101},{126,102},{126,103},{127,103},4101{127,104},{126,105},{126,106},{127,106},{127,107},{126,108},{125,109},{127,109},{126,110},{126,111},{127,111},{127,112},{126,113},{126,114},{127,114},{127,115},4102{126,116},{126,117},{127,117},{127,118},{126,119},{126,120},{127,120},{127,121},{126,122},{126,123},{127,123},{127,124},{126,125},{126,126},{127,126},{127,127}4103};41044105static void transcoder_init_bc7_mode5()4106{4107#if 04108// This is a little too much work to do at init time, so precompute it.4109for (int i = 0; i < 256; i++)4110{4111int lowest_e = 256;4112for (int lo = 0; lo < 128; lo++)4113{4114for (int hi = 0; hi < 128; hi++)4115{4116const int lo_e = (lo << 1) | (lo >> 6);4117const int hi_e = (hi << 1) | (hi >> 6);41184119// Selector 14120int v = (lo_e * (64 - 21) + hi_e * 21 + 32) >> 6;4121int e = abs(v - i);41224123if (e < lowest_e)4124{4125g_bc7_m5_equals_1[i].m_hi = static_cast<uint8_t>(hi);4126g_bc7_m5_equals_1[i].m_lo = static_cast<uint8_t>(lo);41274128lowest_e = e;4129}41304131} // hi41324133} // lo41344135printf("{%u,%u},", g_bc7_m5_equals_1[i].m_hi, g_bc7_m5_equals_1[i].m_lo);4136if ((i & 15) == 15) printf("\n");4137}4138#endif41394140for (uint32_t i = 0; i < NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES; i++)4141{4142uint32_t l = g_etc1_to_bc7_m5_selector_ranges[i].m_low;4143uint32_t h = g_etc1_to_bc7_m5_selector_ranges[i].m_high;4144g_etc1_to_bc7_m5_selector_range_index[l][h] = i;4145}41464147for (uint32_t i = 0; i < NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES; i++)4148{4149uint32_t l = g_etc1_to_bc7_m5a_selector_ranges[i].m_low;4150uint32_t h = g_etc1_to_bc7_m5a_selector_ranges[i].m_high;4151g_etc1_to_bc7_m5a_selector_range_index[l][h] = i;4152}4153}41544155static void convert_etc1s_to_bc7_m5_color(void* pDst, const endpoint* pEndpoints, const selector* pSelector)4156{4157bc7_mode_5* pDst_block = static_cast<bc7_mode_5*>(pDst);41584159// First ensure the block is cleared to all 0's4160static_cast<uint64_t*>(pDst)[0] = 0;4161static_cast<uint64_t*>(pDst)[1] = 0;41624163// Set alpha to 2554164pDst_block->m_lo.m_mode = 1 << 5;4165pDst_block->m_lo.m_a0 = 255;4166pDst_block->m_lo.m_a1_0 = 63;4167pDst_block->m_hi.m_a1_1 = 3;41684169const uint32_t low_selector = pSelector->m_lo_selector;4170const uint32_t high_selector = pSelector->m_hi_selector;41714172const uint32_t base_color_r = pEndpoints->m_color5.r;4173const uint32_t base_color_g = pEndpoints->m_color5.g;4174const uint32_t base_color_b = pEndpoints->m_color5.b;4175const uint32_t inten_table = pEndpoints->m_inten5;41764177if (pSelector->m_num_unique_selectors == 1)4178{4179// Solid color block - use precomputed tables and set selectors to 1.4180uint32_t r, g, b;4181decoder_etc_block::get_block_color5(pEndpoints->m_color5, inten_table, low_selector, r, g, b);41824183pDst_block->m_lo.m_r0 = g_bc7_m5_equals_1[r].m_lo;4184pDst_block->m_lo.m_g0 = g_bc7_m5_equals_1[g].m_lo;4185pDst_block->m_lo.m_b0 = g_bc7_m5_equals_1[b].m_lo;41864187pDst_block->m_lo.m_r1 = g_bc7_m5_equals_1[r].m_hi;4188pDst_block->m_lo.m_g1 = g_bc7_m5_equals_1[g].m_hi;4189pDst_block->m_lo.m_b1 = g_bc7_m5_equals_1[b].m_hi;41904191set_block_bits((uint8_t*)pDst, 0x2aaaaaab, 31, 66);4192return;4193}4194else if (pSelector->m_num_unique_selectors == 2)4195{4196// Only one or two unique selectors, so just switch to block truncation coding (BTC) to avoid quality issues on extreme blocks.4197color32 block_colors[4];41984199decoder_etc_block::get_block_colors5(block_colors, color32(base_color_r, base_color_g, base_color_b, 255), inten_table);42004201const uint32_t r0 = block_colors[low_selector].r;4202const uint32_t g0 = block_colors[low_selector].g;4203const uint32_t b0 = block_colors[low_selector].b;42044205const uint32_t r1 = block_colors[high_selector].r;4206const uint32_t g1 = block_colors[high_selector].g;4207const uint32_t b1 = block_colors[high_selector].b;42084209pDst_block->m_lo.m_r0 = r0 >> 1;4210pDst_block->m_lo.m_g0 = g0 >> 1;4211pDst_block->m_lo.m_b0 = b0 >> 1;42124213pDst_block->m_lo.m_r1 = r1 >> 1;4214pDst_block->m_lo.m_g1 = g1 >> 1;4215pDst_block->m_lo.m_b1 = b1 >> 1;42164217uint32_t output_low_selector = 0, output_bit_offset = 0, output_bits = 0;42184219for (uint32_t y = 0; y < 4; y++)4220{4221for (uint32_t x = 0; x < 4; x++)4222{4223uint32_t s = pSelector->get_selector(x, y);4224uint32_t os = (s == low_selector) ? output_low_selector : (3 ^ output_low_selector);42254226uint32_t num_bits = 2;42274228if ((x | y) == 0)4229{4230if (os & 2)4231{4232pDst_block->m_lo.m_r0 = r1 >> 1;4233pDst_block->m_lo.m_g0 = g1 >> 1;4234pDst_block->m_lo.m_b0 = b1 >> 1;42354236pDst_block->m_lo.m_r1 = r0 >> 1;4237pDst_block->m_lo.m_g1 = g0 >> 1;4238pDst_block->m_lo.m_b1 = b0 >> 1;42394240output_low_selector = 3;4241os = 0;4242}42434244num_bits = 1;4245}42464247output_bits |= (os << output_bit_offset);4248output_bit_offset += num_bits;4249}4250}42514252set_block_bits((uint8_t*)pDst, output_bits, 31, 66);4253return;4254}42554256const uint32_t selector_range_table = g_etc1_to_bc7_m5_selector_range_index[low_selector][high_selector];42574258//[32][8][RANGES][MAPPING]4259const etc1_to_bc7_m5_solution* pTable_r = &g_etc1_to_bc7_m5_color[(inten_table * 32 + base_color_r) * (NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS];4260const etc1_to_bc7_m5_solution* pTable_g = &g_etc1_to_bc7_m5_color[(inten_table * 32 + base_color_g) * (NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS];4261const etc1_to_bc7_m5_solution* pTable_b = &g_etc1_to_bc7_m5_color[(inten_table * 32 + base_color_b) * (NUM_ETC1_TO_BC7_M5_SELECTOR_RANGES * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS];42624263uint32_t best_err = UINT_MAX;4264uint32_t best_mapping = 0;42654266assert(NUM_ETC1_TO_BC7_M5_SELECTOR_MAPPINGS == 10);4267#define DO_ITER(m) { uint32_t total_err = pTable_r[m].m_err + pTable_g[m].m_err + pTable_b[m].m_err; if (total_err < best_err) { best_err = total_err; best_mapping = m; } }4268DO_ITER(0); DO_ITER(1); DO_ITER(2); DO_ITER(3); DO_ITER(4);4269DO_ITER(5); DO_ITER(6); DO_ITER(7); DO_ITER(8); DO_ITER(9);4270#undef DO_ITER42714272const uint8_t* pSelectors_xlat = &g_etc1_to_bc7_m5_selector_mappings[best_mapping][0];42734274uint32_t s_inv = 0;4275if (pSelectors_xlat[pSelector->get_selector(0, 0)] & 2)4276{4277pDst_block->m_lo.m_r0 = pTable_r[best_mapping].m_hi;4278pDst_block->m_lo.m_g0 = pTable_g[best_mapping].m_hi;4279pDst_block->m_lo.m_b0 = pTable_b[best_mapping].m_hi;42804281pDst_block->m_lo.m_r1 = pTable_r[best_mapping].m_lo;4282pDst_block->m_lo.m_g1 = pTable_g[best_mapping].m_lo;4283pDst_block->m_lo.m_b1 = pTable_b[best_mapping].m_lo;42844285s_inv = 3;4286}4287else4288{4289pDst_block->m_lo.m_r0 = pTable_r[best_mapping].m_lo;4290pDst_block->m_lo.m_g0 = pTable_g[best_mapping].m_lo;4291pDst_block->m_lo.m_b0 = pTable_b[best_mapping].m_lo;42924293pDst_block->m_lo.m_r1 = pTable_r[best_mapping].m_hi;4294pDst_block->m_lo.m_g1 = pTable_g[best_mapping].m_hi;4295pDst_block->m_lo.m_b1 = pTable_b[best_mapping].m_hi;4296}42974298uint32_t output_bits = 0, output_bit_ofs = 0;42994300for (uint32_t y = 0; y < 4; y++)4301{4302for (uint32_t x = 0; x < 4; x++)4303{4304const uint32_t s = pSelector->get_selector(x, y);43054306const uint32_t os = pSelectors_xlat[s] ^ s_inv;43074308output_bits |= (os << output_bit_ofs);43094310output_bit_ofs += (((x | y) == 0) ? 1 : 2);4311}4312}43134314set_block_bits((uint8_t*)pDst, output_bits, 31, 66);4315}43164317static void convert_etc1s_to_bc7_m5_alpha(void* pDst, const endpoint* pEndpoints, const selector* pSelector)4318{4319bc7_mode_5* pDst_block = static_cast<bc7_mode_5*>(pDst);43204321const uint32_t low_selector = pSelector->m_lo_selector;4322const uint32_t high_selector = pSelector->m_hi_selector;43234324const uint32_t base_color_r = pEndpoints->m_color5.r;4325const uint32_t inten_table = pEndpoints->m_inten5;43264327if (pSelector->m_num_unique_selectors == 1)4328{4329uint32_t r;4330decoder_etc_block::get_block_color5_r(pEndpoints->m_color5, inten_table, low_selector, r);43314332pDst_block->m_lo.m_a0 = r;4333pDst_block->m_lo.m_a1_0 = r & 63;4334pDst_block->m_hi.m_a1_1 = r >> 6;43354336return;4337}4338else if (pSelector->m_num_unique_selectors == 2)4339{4340// Only one or two unique selectors, so just switch to block truncation coding (BTC) to avoid quality issues on extreme blocks.4341int block_colors[4];43424343decoder_etc_block::get_block_colors5_g(block_colors, pEndpoints->m_color5, inten_table);43444345pDst_block->m_lo.m_a0 = block_colors[low_selector];4346pDst_block->m_lo.m_a1_0 = block_colors[high_selector] & 63;4347pDst_block->m_hi.m_a1_1 = block_colors[high_selector] >> 6;43484349uint32_t output_low_selector = 0, output_bit_offset = 0, output_bits = 0;43504351for (uint32_t y = 0; y < 4; y++)4352{4353for (uint32_t x = 0; x < 4; x++)4354{4355const uint32_t s = pSelector->get_selector(x, y);4356uint32_t os = (s == low_selector) ? output_low_selector : (3 ^ output_low_selector);43574358uint32_t num_bits = 2;43594360if ((x | y) == 0)4361{4362if (os & 2)4363{4364pDst_block->m_lo.m_a0 = block_colors[high_selector];4365pDst_block->m_lo.m_a1_0 = block_colors[low_selector] & 63;4366pDst_block->m_hi.m_a1_1 = block_colors[low_selector] >> 6;43674368output_low_selector = 3;4369os = 0;4370}43714372num_bits = 1;4373}43744375output_bits |= (os << output_bit_offset);4376output_bit_offset += num_bits;4377}4378}43794380set_block_bits((uint8_t*)pDst, output_bits, 31, 97);4381return;4382}43834384const uint32_t selector_range_table = g_etc1_to_bc7_m5a_selector_range_index[low_selector][high_selector];43854386const etc1_g_to_bc7_m5a_conversion* pTable = &g_etc1_g_to_bc7_m5a[inten_table * (32 * NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES) + base_color_r * NUM_ETC1_TO_BC7_M5A_SELECTOR_RANGES + selector_range_table];43874388pDst_block->m_lo.m_a0 = pTable->m_lo;4389pDst_block->m_lo.m_a1_0 = pTable->m_hi & 63;4390pDst_block->m_hi.m_a1_1 = pTable->m_hi >> 6;43914392uint32_t output_bit_offset = 0, output_bits = 0, selector_trans = pTable->m_trans;43934394for (uint32_t y = 0; y < 4; y++)4395{4396for (uint32_t x = 0; x < 4; x++)4397{4398const uint32_t s = pSelector->get_selector(x, y);4399uint32_t os = (selector_trans >> (s * 2)) & 3;44004401uint32_t num_bits = 2;44024403if ((x | y) == 0)4404{4405if (os & 2)4406{4407pDst_block->m_lo.m_a0 = pTable->m_hi;4408pDst_block->m_lo.m_a1_0 = pTable->m_lo & 63;4409pDst_block->m_hi.m_a1_1 = pTable->m_lo >> 6;44104411selector_trans ^= 0xFF;4412os ^= 3;4413}44144415num_bits = 1;4416}44174418output_bits |= (os << output_bit_offset);4419output_bit_offset += num_bits;4420}4421}44224423set_block_bits((uint8_t*)pDst, output_bits, 31, 97);4424}4425#endif // BASISD_SUPPORT_BC7_MODE544264427#if BASISD_SUPPORT_ETC2_EAC_A8 || BASISD_SUPPORT_UASTC4428static const uint8_t g_etc2_eac_a8_sel4[6] = { 0x92, 0x49, 0x24, 0x92, 0x49, 0x24 };4429#endif44304431#if BASISD_SUPPORT_ETC2_EAC_A84432static void convert_etc1s_to_etc2_eac_a8(eac_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector)4433{4434const uint32_t low_selector = pSelector->m_lo_selector;4435const uint32_t high_selector = pSelector->m_hi_selector;44364437const color32& base_color = pEndpoints->m_color5;4438const uint32_t inten_table = pEndpoints->m_inten5;44394440if (low_selector == high_selector)4441{4442uint32_t r;4443decoder_etc_block::get_block_color5_r(base_color, inten_table, low_selector, r);44444445// Constant alpha block4446// Select table 13, use selector 4 (0), set multiplier to 1 and base color g4447pDst_block->m_base = r;4448pDst_block->m_table = 13;4449pDst_block->m_multiplier = 1;44504451// selectors are all 4's4452memcpy(pDst_block->m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));44534454return;4455}44564457uint32_t selector_range_table = 0;4458for (selector_range_table = 0; selector_range_table < NUM_ETC2_EAC_SELECTOR_RANGES; selector_range_table++)4459if ((low_selector == s_etc2_eac_selector_ranges[selector_range_table].m_low) && (high_selector == s_etc2_eac_selector_ranges[selector_range_table].m_high))4460break;4461if (selector_range_table >= NUM_ETC2_EAC_SELECTOR_RANGES)4462selector_range_table = 0;44634464const etc1_g_to_eac_conversion* pTable_entry = &s_etc1_g_to_etc2_a8[base_color.r + inten_table * 32][selector_range_table];44654466pDst_block->m_base = pTable_entry->m_base;4467pDst_block->m_table = pTable_entry->m_table_mul >> 4;4468pDst_block->m_multiplier = pTable_entry->m_table_mul & 15;44694470uint64_t selector_bits = 0;44714472for (uint32_t y = 0; y < 4; y++)4473{4474for (uint32_t x = 0; x < 4; x++)4475{4476uint32_t s = pSelector->get_selector(x, y);44774478uint32_t ds = (pTable_entry->m_trans >> (s * 3)) & 7;44794480const uint32_t dst_ofs = 45 - (y + x * 4) * 3;4481selector_bits |= (static_cast<uint64_t>(ds) << dst_ofs);4482}4483}44844485pDst_block->set_selector_bits(selector_bits);4486}4487#endif // BASISD_SUPPORT_ETC2_EAC_A844884489#if BASISD_SUPPORT_ETC2_EAC_RG114490static const etc1_g_to_eac_conversion s_etc1_g_to_etc2_r11[32 * 8][NUM_ETC2_EAC_SELECTOR_RANGES] =4491{4492{{0,1,3328},{0,1,3328},{0,16,457},{0,16,456}},4493{{0,226,3936},{0,226,3936},{0,17,424},{8,0,472}},4494{{6,178,4012},{6,178,4008},{0,146,501},{16,0,472}},4495{{14,178,4012},{14,178,4008},{8,146,501},{24,0,472}},4496{{23,178,4012},{23,178,4008},{17,146,501},{33,0,472}},4497{{31,178,4012},{31,178,4008},{25,146,501},{41,0,472}},4498{{39,178,4012},{39,178,4008},{33,146,501},{49,0,472}},4499{{47,178,4012},{47,178,4008},{41,146,501},{27,228,496}},4500{{56,178,4012},{56,178,4008},{50,146,501},{36,228,496}},4501{{64,178,4012},{64,178,4008},{58,146,501},{44,228,496}},4502{{72,178,4012},{72,178,4008},{66,146,501},{52,228,496}},4503{{80,178,4012},{80,178,4008},{74,146,501},{60,228,496}},4504{{89,178,4012},{89,178,4008},{83,146,501},{69,228,496}},4505{{97,178,4012},{97,178,4008},{91,146,501},{77,228,496}},4506{{105,178,4012},{105,178,4008},{99,146,501},{85,228,496}},4507{{113,178,4012},{113,178,4008},{107,146,501},{93,228,496}},4508{{122,178,4012},{122,178,4008},{116,146,501},{102,228,496}},4509{{130,178,4012},{130,178,4008},{124,146,501},{110,228,496}},4510{{138,178,4012},{138,178,4008},{132,146,501},{118,228,496}},4511{{146,178,4012},{146,178,4008},{140,146,501},{126,228,496}},4512{{155,178,4012},{155,178,4008},{149,146,501},{135,228,496}},4513{{163,178,4012},{163,178,4008},{157,146,501},{143,228,496}},4514{{171,178,4012},{171,178,4008},{165,146,501},{151,228,496}},4515{{179,178,4012},{179,178,4008},{173,146,501},{159,228,496}},4516{{188,178,4012},{188,178,4008},{182,146,501},{168,228,496}},4517{{196,178,4012},{196,178,4008},{190,146,501},{176,228,496}},4518{{204,178,4012},{204,178,4008},{198,146,501},{184,228,496}},4519{{212,178,4012},{212,178,4008},{206,146,501},{192,228,496}},4520{{221,178,4012},{221,178,4008},{215,146,501},{201,228,496}},4521{{229,178,4012},{229,178,4008},{223,146,501},{209,228,496}},4522{{235,66,4012},{221,100,4008},{231,146,501},{217,228,496}},4523{{211,102,4085},{254,32,4040},{211,102,501},{254,32,456}},4524{{0,2,3328},{0,2,3328},{0,1,320},{0,1,320}},4525{{7,162,3905},{7,162,3904},{0,17,480},{0,17,480}},4526{{15,162,3906},{15,162,3904},{1,117,352},{1,117,352}},4527{{23,162,3906},{23,162,3904},{5,34,500},{4,53,424}},4528{{32,162,3906},{32,162,3904},{14,34,500},{3,69,424}},4529{{40,162,3906},{40,162,3904},{22,34,500},{1,133,496}},4530{{48,162,3906},{48,162,3904},{30,34,500},{4,85,496}},4531{{56,162,3906},{56,162,3904},{38,34,500},{12,85,496}},4532{{65,162,3906},{65,162,3904},{47,34,500},{1,106,424}},4533{{73,162,3906},{73,162,3904},{55,34,500},{9,106,424}},4534{{81,162,3906},{81,162,3904},{63,34,500},{7,234,496}},4535{{89,162,3906},{89,162,3904},{71,34,500},{15,234,496}},4536{{98,162,3906},{98,162,3904},{80,34,500},{24,234,496}},4537{{106,162,3906},{106,162,3904},{88,34,500},{32,234,496}},4538{{114,162,3906},{114,162,3904},{96,34,500},{40,234,496}},4539{{122,162,3906},{122,162,3904},{104,34,500},{48,234,496}},4540{{131,162,3906},{131,162,3904},{113,34,500},{57,234,496}},4541{{139,162,3906},{139,162,3904},{121,34,500},{65,234,496}},4542{{147,162,3906},{147,162,3904},{129,34,500},{73,234,496}},4543{{155,162,3906},{155,162,3904},{137,34,500},{81,234,496}},4544{{164,162,3906},{164,162,3904},{146,34,500},{90,234,496}},4545{{172,162,3906},{172,162,3904},{154,34,500},{98,234,496}},4546{{180,162,3906},{180,162,3904},{162,34,500},{106,234,496}},4547{{188,162,3906},{188,162,3904},{170,34,500},{114,234,496}},4548{{197,162,3906},{197,162,3904},{179,34,500},{123,234,496}},4549{{205,162,3906},{205,162,3904},{187,34,500},{131,234,496}},4550{{213,162,3906},{213,162,3904},{195,34,500},{139,234,496}},4551{{221,162,3906},{221,162,3904},{203,34,500},{147,234,496}},4552{{230,162,3906},{230,162,3904},{212,34,500},{156,234,496}},4553{{238,162,3906},{174,106,4008},{220,34,500},{164,234,496}},4554{{240,178,4001},{182,106,4008},{228,34,500},{172,234,496}},4555{{166,108,4085},{115,31,4080},{166,108,501},{115,31,496}},4556{{1,68,3328},{1,68,3328},{0,1,384},{0,1,384}},4557{{1,51,3968},{1,51,3968},{0,2,384},{0,2,384}},4558{{21,18,3851},{21,18,3848},{1,50,488},{1,50,488}},4559{{26,195,3851},{29,18,3848},{0,67,488},{0,67,488}},4560{{35,195,3851},{38,18,3848},{12,115,488},{0,3,496}},4561{{43,195,3851},{46,18,3848},{20,115,488},{2,6,424}},4562{{51,195,3851},{54,18,3848},{36,66,482},{4,22,424}},4563{{59,195,3851},{62,18,3848},{44,66,482},{3,73,424}},4564{{68,195,3851},{71,18,3848},{53,66,482},{3,22,496}},4565{{76,195,3851},{79,18,3848},{61,66,482},{2,137,496}},4566{{84,195,3851},{87,18,3848},{69,66,482},{1,89,496}},4567{{92,195,3851},{95,18,3848},{77,66,482},{9,89,496}},4568{{101,195,3851},{104,18,3848},{86,66,482},{18,89,496}},4569{{109,195,3851},{112,18,3848},{94,66,482},{26,89,496}},4570{{117,195,3851},{120,18,3848},{102,66,482},{34,89,496}},4571{{125,195,3851},{128,18,3848},{110,66,482},{42,89,496}},4572{{134,195,3851},{137,18,3848},{119,66,482},{51,89,496}},4573{{141,195,3907},{145,18,3848},{127,66,482},{59,89,496}},4574{{149,195,3907},{153,18,3848},{135,66,482},{67,89,496}},4575{{157,195,3907},{161,18,3848},{143,66,482},{75,89,496}},4576{{166,195,3907},{170,18,3848},{152,66,482},{84,89,496}},4577{{174,195,3907},{178,18,3848},{160,66,482},{92,89,496}},4578{{182,195,3907},{186,18,3848},{168,66,482},{100,89,496}},4579{{190,195,3907},{194,18,3848},{176,66,482},{108,89,496}},4580{{199,195,3907},{203,18,3848},{185,66,482},{117,89,496}},4581{{207,195,3907},{211,18,3848},{193,66,482},{125,89,496}},4582{{215,195,3907},{219,18,3848},{201,66,482},{133,89,496}},4583{{223,195,3907},{227,18,3848},{209,66,482},{141,89,496}},4584{{232,195,3907},{168,89,4008},{218,66,482},{150,89,496}},4585{{236,18,3907},{176,89,4008},{226,66,482},{158,89,496}},4586{{158,90,4085},{103,31,4080},{158,90,501},{103,31,496}},4587{{166,90,4085},{111,31,4080},{166,90,501},{111,31,496}},4588{{0,70,3328},{0,70,3328},{0,17,448},{0,17,448}},4589{{0,117,3904},{0,117,3904},{0,35,384},{0,35,384}},4590{{13,165,3905},{13,165,3904},{2,211,480},{2,211,480}},4591{{21,165,3906},{21,165,3904},{1,51,488},{1,51,488}},4592{{30,165,3906},{30,165,3904},{7,61,352},{7,61,352}},4593{{38,165,3906},{38,165,3904},{2,125,352},{2,125,352}},4594{{46,165,3906},{46,165,3904},{1,37,500},{10,125,352}},4595{{54,165,3906},{54,165,3904},{9,37,500},{5,61,424}},4596{{63,165,3906},{63,165,3904},{18,37,500},{1,189,424}},4597{{71,165,3906},{71,165,3904},{26,37,500},{9,189,424}},4598{{79,165,3906},{79,165,3904},{34,37,500},{4,77,424}},4599{{87,165,3906},{87,165,3904},{42,37,500},{12,77,424}},4600{{96,165,3906},{96,165,3904},{51,37,500},{8,93,424}},4601{{104,165,3906},{104,165,3904},{59,37,500},{3,141,496}},4602{{112,165,3906},{112,165,3904},{68,37,500},{11,141,496}},4603{{120,165,3906},{120,165,3904},{76,37,500},{6,93,496}},4604{{129,165,3906},{129,165,3904},{85,37,500},{15,93,496}},4605{{70,254,4012},{137,165,3904},{93,37,500},{23,93,496}},4606{{145,165,3906},{145,165,3904},{101,37,500},{31,93,496}},4607{{86,254,4012},{153,165,3904},{109,37,500},{39,93,496}},4608{{163,165,3906},{162,165,3904},{118,37,500},{48,93,496}},4609{{171,165,3906},{170,165,3904},{126,37,500},{56,93,496}},4610{{179,165,3906},{178,165,3904},{134,37,500},{64,93,496}},4611{{187,165,3906},{187,165,3904},{142,37,500},{72,93,496}},4612{{196,165,3906},{196,165,3904},{151,37,500},{81,93,496}},4613{{204,165,3906},{204,165,3904},{159,37,500},{89,93,496}},4614{{212,165,3906},{136,77,4008},{167,37,500},{97,93,496}},4615{{220,165,3906},{131,93,4008},{175,37,500},{105,93,496}},4616{{214,181,4001},{140,93,4008},{184,37,500},{114,93,496}},4617{{222,181,4001},{148,93,4008},{192,37,500},{122,93,496}},4618{{115,95,4085},{99,31,4080},{115,95,501},{99,31,496}},4619{{123,95,4085},{107,31,4080},{123,95,501},{107,31,496}},4620{{0,102,3840},{0,102,3840},{0,18,384},{0,18,384}},4621{{5,167,3904},{5,167,3904},{0,13,256},{0,13,256}},4622{{4,54,3968},{4,54,3968},{1,67,448},{1,67,448}},4623{{30,198,3850},{30,198,3848},{0,3,480},{0,3,480}},4624{{39,198,3850},{39,198,3848},{3,52,488},{3,52,488}},4625{{47,198,3851},{47,198,3848},{3,4,488},{3,4,488}},4626{{55,198,3851},{55,198,3848},{1,70,488},{1,70,488}},4627{{53,167,3906},{63,198,3848},{3,22,488},{3,22,488}},4628{{62,167,3906},{72,198,3848},{24,118,488},{0,6,496}},4629{{70,167,3906},{80,198,3848},{32,118,488},{2,89,488}},4630{{78,167,3906},{88,198,3848},{40,118,488},{1,73,496}},4631{{86,167,3906},{96,198,3848},{48,118,488},{0,28,424}},4632{{95,167,3906},{105,198,3848},{57,118,488},{9,28,424}},4633{{103,167,3906},{113,198,3848},{65,118,488},{5,108,496}},4634{{111,167,3906},{121,198,3848},{73,118,488},{13,108,496}},4635{{119,167,3906},{129,198,3848},{81,118,488},{21,108,496}},4636{{128,167,3906},{138,198,3848},{90,118,488},{6,28,496}},4637{{136,167,3906},{146,198,3848},{98,118,488},{14,28,496}},4638{{145,167,3906},{154,198,3848},{106,118,488},{22,28,496}},4639{{153,167,3906},{162,198,3848},{114,118,488},{30,28,496}},4640{{162,167,3906},{171,198,3848},{123,118,488},{39,28,496}},4641{{170,167,3906},{179,198,3848},{131,118,488},{47,28,496}},4642{{178,167,3906},{187,198,3848},{139,118,488},{55,28,496}},4643{{186,167,3906},{195,198,3848},{147,118,488},{63,28,496}},4644{{194,167,3906},{120,12,4008},{156,118,488},{72,28,496}},4645{{206,198,3907},{116,28,4008},{164,118,488},{80,28,496}},4646{{214,198,3907},{124,28,4008},{172,118,488},{88,28,496}},4647{{222,198,3395},{132,28,4008},{180,118,488},{96,28,496}},4648{{207,134,4001},{141,28,4008},{189,118,488},{105,28,496}},4649{{95,30,4085},{86,31,4080},{95,30,501},{86,31,496}},4650{{103,30,4085},{94,31,4080},{103,30,501},{94,31,496}},4651{{111,30,4085},{102,31,4080},{111,30,501},{102,31,496}},4652{{0,104,3840},{0,104,3840},{0,18,448},{0,18,448}},4653{{4,39,3904},{4,39,3904},{0,4,384},{0,4,384}},4654{{0,56,3968},{0,56,3968},{0,84,448},{0,84,448}},4655{{6,110,3328},{6,110,3328},{0,20,448},{0,20,448}},4656{{41,200,3850},{41,200,3848},{1,4,480},{1,4,480}},4657{{49,200,3850},{49,200,3848},{1,8,416},{1,8,416}},4658{{57,200,3851},{57,200,3848},{1,38,488},{1,38,488}},4659{{65,200,3851},{65,200,3848},{1,120,488},{1,120,488}},4660{{74,200,3851},{74,200,3848},{2,72,488},{2,72,488}},4661{{68,6,3907},{82,200,3848},{2,24,488},{2,24,488}},4662{{77,6,3907},{90,200,3848},{26,120,488},{10,24,488}},4663{{97,63,3330},{98,200,3848},{34,120,488},{2,8,496}},4664{{106,63,3330},{107,200,3848},{43,120,488},{3,92,488}},4665{{114,63,3330},{115,200,3848},{51,120,488},{11,92,488}},4666{{122,63,3330},{123,200,3848},{59,120,488},{7,76,496}},4667{{130,63,3330},{131,200,3848},{67,120,488},{15,76,496}},4668{{139,63,3330},{140,200,3848},{76,120,488},{24,76,496}},4669{{147,63,3330},{148,200,3848},{84,120,488},{32,76,496}},4670{{155,63,3330},{156,200,3848},{92,120,488},{40,76,496}},4671{{164,63,3330},{164,200,3848},{100,120,488},{48,76,496}},4672{{173,63,3330},{173,200,3848},{109,120,488},{57,76,496}},4673{{184,6,3851},{181,200,3848},{117,120,488},{65,76,496}},4674{{192,6,3851},{133,28,3936},{125,120,488},{73,76,496}},4675{{189,200,3907},{141,28,3936},{133,120,488},{81,76,496}},4676{{198,200,3907},{138,108,4000},{142,120,488},{90,76,496}},4677{{206,200,3907},{146,108,4000},{150,120,488},{98,76,496}},4678{{214,200,3395},{154,108,4000},{158,120,488},{106,76,496}},4679{{190,136,4001},{162,108,4000},{166,120,488},{114,76,496}},4680{{123,30,4076},{87,15,4080},{123,30,492},{87,15,496}},4681{{117,110,4084},{80,31,4080},{117,110,500},{80,31,496}},4682{{125,110,4084},{88,31,4080},{125,110,500},{88,31,496}},4683{{133,110,4084},{96,31,4080},{133,110,500},{96,31,496}},4684{{9,56,3904},{9,56,3904},{0,67,448},{0,67,448}},4685{{1,8,3904},{1,8,3904},{1,84,448},{1,84,448}},4686{{1,124,3904},{1,124,3904},{0,39,384},{0,39,384}},4687{{9,124,3904},{9,124,3904},{1,4,448},{1,4,448}},4688{{6,76,3904},{6,76,3904},{0,70,448},{0,70,448}},4689{{62,6,3859},{62,6,3856},{2,38,480},{2,38,480}},4690{{70,6,3859},{70,6,3856},{5,43,416},{5,43,416}},4691{{78,6,3859},{78,6,3856},{2,11,416},{2,11,416}},4692{{87,6,3859},{87,6,3856},{0,171,488},{0,171,488}},4693{{67,8,3906},{95,6,3856},{8,171,488},{8,171,488}},4694{{75,8,3907},{103,6,3856},{5,123,488},{5,123,488}},4695{{83,8,3907},{111,6,3856},{2,75,488},{2,75,488}},4696{{92,8,3907},{120,6,3856},{0,27,488},{0,27,488}},4697{{100,8,3907},{128,6,3856},{8,27,488},{8,27,488}},4698{{120,106,3843},{136,6,3856},{99,6,387},{16,27,488}},4699{{128,106,3843},{144,6,3856},{107,6,387},{2,11,496}},4700{{137,106,3843},{153,6,3856},{117,6,387},{11,11,496}},4701{{145,106,3843},{161,6,3856},{125,6,387},{19,11,496}},4702{{163,8,3851},{137,43,3904},{133,6,387},{27,11,496}},4703{{171,8,3851},{145,43,3904},{141,6,387},{35,11,496}},4704{{180,8,3851},{110,11,4000},{150,6,387},{44,11,496}},4705{{188,8,3851},{118,11,4000},{158,6,387},{52,11,496}},4706{{172,72,3907},{126,11,4000},{166,6,387},{60,11,496}},4707{{174,6,3971},{134,11,4000},{174,6,387},{68,11,496}},4708{{183,6,3971},{143,11,4000},{183,6,387},{77,11,496}},4709{{191,6,3971},{151,11,4000},{191,6,387},{85,11,496}},4710{{199,6,3971},{159,11,4000},{199,6,387},{93,11,496}},4711{{92,12,4084},{69,15,4080},{92,12,500},{69,15,496}},4712{{101,12,4084},{78,15,4080},{101,12,500},{78,15,496}},4713{{110,12,4084},{86,15,4080},{110,12,500},{86,15,496}},4714{{118,12,4084},{79,31,4080},{118,12,500},{79,31,496}},4715{{126,12,4084},{87,31,4080},{126,12,500},{87,31,496}},4716{{71,8,3602},{71,8,3600},{2,21,384},{2,21,384}},4717{{79,8,3611},{79,8,3608},{0,69,448},{0,69,448}},4718{{87,8,3611},{87,8,3608},{0,23,384},{0,23,384}},4719{{95,8,3611},{95,8,3608},{1,5,448},{1,5,448}},4720{{104,8,3611},{104,8,3608},{0,88,448},{0,88,448}},4721{{112,8,3611},{112,8,3608},{0,72,448},{0,72,448}},4722{{120,8,3611},{121,8,3608},{36,21,458},{36,21,456}},4723{{133,47,3091},{129,8,3608},{44,21,458},{44,21,456}},4724{{142,47,3091},{138,8,3608},{53,21,459},{53,21,456}},4725{{98,12,3850},{98,12,3848},{61,21,459},{61,21,456}},4726{{106,12,3850},{106,12,3848},{10,92,480},{69,21,456}},4727{{114,12,3851},{114,12,3848},{18,92,480},{77,21,456}},4728{{123,12,3851},{123,12,3848},{3,44,488},{86,21,456}},4729{{95,12,3906},{95,12,3904},{11,44,488},{94,21,456}},4730{{103,12,3906},{103,12,3904},{19,44,488},{102,21,456}},4731{{111,12,3907},{111,12,3904},{27,44,489},{110,21,456}},4732{{120,12,3907},{120,12,3904},{36,44,489},{119,21,456}},4733{{128,12,3907},{128,12,3904},{44,44,489},{127,21,456}},4734{{136,12,3907},{136,12,3904},{52,44,489},{135,21,456}},4735{{144,12,3907},{144,12,3904},{60,44,490},{144,21,456}},4736{{153,12,3907},{153,12,3904},{69,44,490},{153,21,456}},4737{{161,12,3395},{149,188,3968},{77,44,490},{161,21,456}},4738{{169,12,3395},{199,21,3928},{85,44,490},{169,21,456}},4739{{113,95,4001},{202,69,3992},{125,8,483},{177,21,456}},4740{{122,95,4001},{201,21,3984},{134,8,483},{186,21,456}},4741{{143,8,4067},{209,21,3984},{142,8,483},{194,21,456}},4742{{151,8,4067},{47,15,4080},{151,8,483},{47,15,496}},4743{{159,8,4067},{55,15,4080},{159,8,483},{55,15,496}},4744{{168,8,4067},{64,15,4080},{168,8,483},{64,15,496}},4745{{160,40,4075},{72,15,4080},{160,40,491},{72,15,496}},4746{{168,40,4075},{80,15,4080},{168,40,491},{80,15,496}},4747{{144,8,4082},{88,15,4080},{144,8,498},{88,15,496}},4748};47494750static void convert_etc1s_to_etc2_eac_r11(eac_block* pDst_block, const endpoint* pEndpoints, const selector* pSelector)4751{4752const uint32_t low_selector = pSelector->m_lo_selector;4753const uint32_t high_selector = pSelector->m_hi_selector;47544755const color32& base_color = pEndpoints->m_color5;4756const uint32_t inten_table = pEndpoints->m_inten5;47574758if (low_selector == high_selector)4759{4760uint32_t r;4761decoder_etc_block::get_block_color5_r(base_color, inten_table, low_selector, r);47624763// Constant alpha block4764// Select table 13, use selector 4 (0), set multiplier to 1 and base color r4765pDst_block->m_base = r;4766pDst_block->m_table = 13;4767pDst_block->m_multiplier = 1;47684769// selectors are all 4's4770static const uint8_t s_etc2_eac_r11_sel4[6] = { 0x92, 0x49, 0x24, 0x92, 0x49, 0x24 };4771memcpy(pDst_block->m_selectors, s_etc2_eac_r11_sel4, sizeof(s_etc2_eac_r11_sel4));47724773return;4774}47754776uint32_t selector_range_table = 0;4777for (selector_range_table = 0; selector_range_table < NUM_ETC2_EAC_SELECTOR_RANGES; selector_range_table++)4778if ((low_selector == s_etc2_eac_selector_ranges[selector_range_table].m_low) && (high_selector == s_etc2_eac_selector_ranges[selector_range_table].m_high))4779break;4780if (selector_range_table >= NUM_ETC2_EAC_SELECTOR_RANGES)4781selector_range_table = 0;47824783const etc1_g_to_eac_conversion* pTable_entry = &s_etc1_g_to_etc2_r11[base_color.r + inten_table * 32][selector_range_table];47844785pDst_block->m_base = pTable_entry->m_base;4786pDst_block->m_table = pTable_entry->m_table_mul >> 4;4787pDst_block->m_multiplier = pTable_entry->m_table_mul & 15;47884789uint64_t selector_bits = 0;47904791for (uint32_t y = 0; y < 4; y++)4792{4793for (uint32_t x = 0; x < 4; x++)4794{4795uint32_t s = pSelector->get_selector(x, y);47964797uint32_t ds = (pTable_entry->m_trans >> (s * 3)) & 7;47984799const uint32_t dst_ofs = 45 - (y + x * 4) * 3;4800selector_bits |= (static_cast<uint64_t>(ds) << dst_ofs);4801}4802}48034804pDst_block->set_selector_bits(selector_bits);4805}4806#endif // BASISD_SUPPORT_ETC2_EAC_RG1148074808// ASTC4809struct etc1_to_astc_solution4810{4811uint8_t m_lo;4812uint8_t m_hi;4813uint16_t m_err;4814};48154816#if BASISD_SUPPORT_ASTC4817static dxt_selector_range g_etc1_to_astc_selector_ranges[] =4818{4819{ 0, 3 },48204821{ 1, 3 },4822{ 0, 2 },48234824{ 1, 2 },48254826{ 2, 3 },4827{ 0, 1 },4828};48294830const uint32_t NUM_ETC1_TO_ASTC_SELECTOR_RANGES = sizeof(g_etc1_to_astc_selector_ranges) / sizeof(g_etc1_to_astc_selector_ranges[0]);48314832static uint32_t g_etc1_to_astc_selector_range_index[4][4];48334834const uint32_t NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS = 10;4835static const uint8_t g_etc1_to_astc_selector_mappings[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS][4] =4836{4837{ 0, 0, 1, 1 },4838{ 0, 0, 1, 2 },4839{ 0, 0, 1, 3 },4840{ 0, 0, 2, 3 },4841{ 0, 1, 1, 1 },4842{ 0, 1, 2, 2 },4843{ 0, 1, 2, 3 },4844{ 0, 2, 3, 3 },4845{ 1, 2, 2, 2 },4846{ 1, 2, 3, 3 },4847};48484849static const etc1_to_astc_solution g_etc1_to_astc[32 * 8 * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS * NUM_ETC1_TO_ASTC_SELECTOR_RANGES] = {4850#include "basisu_transcoder_tables_astc.inc"4851};48524853// The best selector mapping to use given a base base+inten table and used selector range for converting grayscale data.4854static uint8_t g_etc1_to_astc_best_grayscale_mapping[32][8][NUM_ETC1_TO_ASTC_SELECTOR_RANGES];48554856#if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY4857static const etc1_to_astc_solution g_etc1_to_astc_0_255[32 * 8 * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS * NUM_ETC1_TO_ASTC_SELECTOR_RANGES] = {4858#include "basisu_transcoder_tables_astc_0_255.inc"4859};4860static uint8_t g_etc1_to_astc_best_grayscale_mapping_0_255[32][8][NUM_ETC1_TO_ASTC_SELECTOR_RANGES];4861#endif48624863static uint32_t g_ise_to_unquant[48];48644865#if BASISD_WRITE_NEW_ASTC_TABLES4866static void create_etc1_to_astc_conversion_table_0_47()4867{4868FILE* pFile = nullptr;4869fopen_s(&pFile, "basisu_transcoder_tables_astc.inc", "w");48704871uint32_t n = 0;48724873for (int inten = 0; inten < 8; inten++)4874{4875for (uint32_t g = 0; g < 32; g++)4876{4877color32 block_colors[4];4878decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);48794880for (uint32_t sr = 0; sr < NUM_ETC1_TO_ASTC_SELECTOR_RANGES; sr++)4881{4882const uint32_t low_selector = g_etc1_to_astc_selector_ranges[sr].m_low;4883const uint32_t high_selector = g_etc1_to_astc_selector_ranges[sr].m_high;48844885uint32_t mapping_best_low[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];4886uint32_t mapping_best_high[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];4887uint64_t mapping_best_err[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];4888uint64_t highest_best_err = 0;48894890for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++)4891{4892uint32_t best_lo = 0;4893uint32_t best_hi = 0;4894uint64_t best_err = UINT64_MAX;48954896for (uint32_t hi = 0; hi <= 47; hi++)4897{4898for (uint32_t lo = 0; lo <= 47; lo++)4899{4900uint32_t colors[4];49014902for (uint32_t s = 0; s < 4; s++)4903{4904uint32_t s_scaled = s | (s << 2) | (s << 4);4905if (s_scaled > 32)4906s_scaled++;49074908uint32_t c0 = g_ise_to_unquant[lo] | (g_ise_to_unquant[lo] << 8);4909uint32_t c1 = g_ise_to_unquant[hi] | (g_ise_to_unquant[hi] << 8);4910colors[s] = ((c0 * (64 - s_scaled) + c1 * s_scaled + 32) / 64) >> 8;4911}49124913uint64_t total_err = 0;49144915for (uint32_t s = low_selector; s <= high_selector; s++)4916{4917int err = block_colors[s].g - colors[g_etc1_to_astc_selector_mappings[m][s]];49184919int err_scale = 1;4920// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor4921// the low/high selectors which are clamping to either 0 or 255.4922if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))4923err_scale = 8;49244925total_err += (err * err) * err_scale;4926}49274928if (total_err < best_err)4929{4930best_err = total_err;4931best_lo = lo;4932best_hi = hi;4933}4934}4935}49364937mapping_best_low[m] = best_lo;4938mapping_best_high[m] = best_hi;4939mapping_best_err[m] = best_err;4940highest_best_err = basisu::maximum(highest_best_err, best_err);49414942} // m49434944for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++)4945{4946uint64_t err = mapping_best_err[m];49474948err = basisu::minimum<uint64_t>(err, 0xFFFF);49494950fprintf(pFile, "{%u,%u,%u},", mapping_best_low[m], mapping_best_high[m], (uint32_t)err);49514952n++;4953if ((n & 31) == 31)4954fprintf(pFile, "\n");4955} // m49564957} // sr4958} // g4959} // inten49604961fclose(pFile);4962}49634964static void create_etc1_to_astc_conversion_table_0_255()4965{4966FILE* pFile = nullptr;4967fopen_s(&pFile, "basisu_transcoder_tables_astc_0_255.inc", "w");49684969uint32_t n = 0;49704971for (int inten = 0; inten < 8; inten++)4972{4973for (uint32_t g = 0; g < 32; g++)4974{4975color32 block_colors[4];4976decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);49774978for (uint32_t sr = 0; sr < NUM_ETC1_TO_ASTC_SELECTOR_RANGES; sr++)4979{4980const uint32_t low_selector = g_etc1_to_astc_selector_ranges[sr].m_low;4981const uint32_t high_selector = g_etc1_to_astc_selector_ranges[sr].m_high;49824983uint32_t mapping_best_low[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];4984uint32_t mapping_best_high[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];4985uint64_t mapping_best_err[NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];4986uint64_t highest_best_err = 0;49874988for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++)4989{4990uint32_t best_lo = 0;4991uint32_t best_hi = 0;4992uint64_t best_err = UINT64_MAX;49934994for (uint32_t hi = 0; hi <= 255; hi++)4995{4996for (uint32_t lo = 0; lo <= 255; lo++)4997{4998uint32_t colors[4];49995000for (uint32_t s = 0; s < 4; s++)5001{5002uint32_t s_scaled = s | (s << 2) | (s << 4);5003if (s_scaled > 32)5004s_scaled++;50055006uint32_t c0 = lo | (lo << 8);5007uint32_t c1 = hi | (hi << 8);5008colors[s] = ((c0 * (64 - s_scaled) + c1 * s_scaled + 32) / 64) >> 8;5009}50105011uint64_t total_err = 0;50125013for (uint32_t s = low_selector; s <= high_selector; s++)5014{5015int err = block_colors[s].g - colors[g_etc1_to_astc_selector_mappings[m][s]];50165017// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor5018// the low/high selectors which are clamping to either 0 or 255.5019int err_scale = 1;5020if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))5021err_scale = 8;50225023total_err += (err * err) * err_scale;5024}50255026if (total_err < best_err)5027{5028best_err = total_err;5029best_lo = lo;5030best_hi = hi;5031}5032}5033}50345035mapping_best_low[m] = best_lo;5036mapping_best_high[m] = best_hi;5037mapping_best_err[m] = best_err;5038highest_best_err = basisu::maximum(highest_best_err, best_err);5039} // m50405041for (uint32_t m = 0; m < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; m++)5042{5043uint64_t err = mapping_best_err[m];50445045err = basisu::minimum<uint64_t>(err, 0xFFFF);50465047fprintf(pFile, "{%u,%u,%u},", mapping_best_low[m], mapping_best_high[m], (uint32_t)err);50485049n++;5050if ((n & 31) == 31)5051fprintf(pFile, "\n");5052} // m50535054} // sr5055} // g5056} // inten50575058fclose(pFile);5059}5060#endif50615062#endif50635064#if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ASTC5065// Table encodes 5 trits to 8 output bits. 3^5 entries.5066// Inverse of the trit bit manipulation process in https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-integer-sequence-encoding5067static const uint8_t g_astc_trit_encode[243] = { 0, 1, 2, 4, 5, 6, 8, 9, 10, 16, 17, 18, 20, 21, 22, 24, 25, 26, 3, 7, 11, 19, 23, 27, 12, 13, 14, 32, 33, 34, 36, 37, 38, 40, 41, 42, 48, 49, 50, 52, 53, 54, 56, 57, 58, 35, 39,506843, 51, 55, 59, 44, 45, 46, 64, 65, 66, 68, 69, 70, 72, 73, 74, 80, 81, 82, 84, 85, 86, 88, 89, 90, 67, 71, 75, 83, 87, 91, 76, 77, 78, 128, 129, 130, 132, 133, 134, 136, 137, 138, 144, 145, 146, 148, 149, 150, 152, 153, 154,5069131, 135, 139, 147, 151, 155, 140, 141, 142, 160, 161, 162, 164, 165, 166, 168, 169, 170, 176, 177, 178, 180, 181, 182, 184, 185, 186, 163, 167, 171, 179, 183, 187, 172, 173, 174, 192, 193, 194, 196, 197, 198, 200, 201, 202,5070208, 209, 210, 212, 213, 214, 216, 217, 218, 195, 199, 203, 211, 215, 219, 204, 205, 206, 96, 97, 98, 100, 101, 102, 104, 105, 106, 112, 113, 114, 116, 117, 118, 120, 121, 122, 99, 103, 107, 115, 119, 123, 108, 109, 110, 224,5071225, 226, 228, 229, 230, 232, 233, 234, 240, 241, 242, 244, 245, 246, 248, 249, 250, 227, 231, 235, 243, 247, 251, 236, 237, 238, 28, 29, 30, 60, 61, 62, 92, 93, 94, 156, 157, 158, 188, 189, 190, 220, 221, 222, 31, 63, 95, 159,5072191, 223, 124, 125, 126 };50735074// Extracts bits [low,high]5075static inline uint32_t astc_extract_bits(uint32_t bits, int low, int high)5076{5077return (bits >> low) & ((1 << (high - low + 1)) - 1);5078}50795080// Writes bits to output in an endian safe way5081static inline void astc_set_bits(uint32_t* pOutput, int& bit_pos, uint32_t value, uint32_t total_bits)5082{5083uint8_t* pBytes = reinterpret_cast<uint8_t*>(pOutput);50845085while (total_bits)5086{5087const uint32_t bits_to_write = basisu::minimum<int>(total_bits, 8 - (bit_pos & 7));50885089pBytes[bit_pos >> 3] |= static_cast<uint8_t>(value << (bit_pos & 7));50905091bit_pos += bits_to_write;5092total_bits -= bits_to_write;5093value >>= bits_to_write;5094}5095}50965097// Encodes 5 values to output, usable for any range that uses trits and bits5098static void astc_encode_trits(uint32_t* pOutput, const uint8_t* pValues, int& bit_pos, int n)5099{5100// First extract the trits and the bits from the 5 input values5101int trits = 0, bits[5];5102const uint32_t bit_mask = (1 << n) - 1;5103for (int i = 0; i < 5; i++)5104{5105static const int s_muls[5] = { 1, 3, 9, 27, 81 };51065107const int t = pValues[i] >> n;51085109trits += t * s_muls[i];5110bits[i] = pValues[i] & bit_mask;5111}51125113// Encode the trits, by inverting the bit manipulations done by the decoder, converting 5 trits into 8-bits.5114// See https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-integer-sequence-encoding51155116assert(trits < 243);5117const int T = g_astc_trit_encode[trits];51185119// Now interleave the 8 encoded trit bits with the bits to form the encoded output. See table 94.5120astc_set_bits(pOutput, bit_pos, bits[0] | (astc_extract_bits(T, 0, 1) << n) | (bits[1] << (2 + n)), n * 2 + 2);51215122astc_set_bits(pOutput, bit_pos, astc_extract_bits(T, 2, 3) | (bits[2] << 2) | (astc_extract_bits(T, 4, 4) << (2 + n)) | (bits[3] << (3 + n)) | (astc_extract_bits(T, 5, 6) << (3 + n * 2)) |5123(bits[4] << (5 + n * 2)) | (astc_extract_bits(T, 7, 7) << (5 + n * 3)), n * 3 + 6);5124}5125#endif // #if BASISD_SUPPORT_UASTC || BASISD_SUPPORT_ASTC51265127#if BASISD_SUPPORT_ASTC5128struct astc_block_params5129{5130// 2 groups of 5, but only a max of 8 are used (RRGGBBAA00)5131uint8_t m_endpoints[10];5132uint8_t m_weights[32];5133};51345135// Packs a single format ASTC block using Color Endpoint Mode 12 (LDR RGBA direct), endpoint BISE range 13, 2-bit weights (range 2).5136// We're always going to output blocks containing alpha, even if the input doesn't have alpha, for simplicity.5137// Each block always has 4x4 weights, uses range 13 BISE encoding on the endpoints (0-47), and each weight ranges from 0-3. This encoding should be roughly equal in quality vs. BC1 for color.5138// 8 total endpoints, stored as RGBA LH LH LH LH order, each ranging from 0-47.5139// Note the input [0,47] endpoint values are not linear - they are encoded as outlined in the ASTC spec:5140// https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-endpoint-unquantization5141// 32 total weights, stored as 16 CA CA, each ranging from 0-3.5142static void astc_pack_block_cem_12_weight_range2(uint32_t *pOutput, const astc_block_params* pBlock)5143{5144uint8_t* pBytes = reinterpret_cast<uint8_t*>(pOutput);51455146// Write constant block mode, color component selector, number of partitions, color endpoint mode5147// https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#_block_mode5148pBytes[0] = 0x42; pBytes[1] = 0x84; pBytes[2] = 0x01; pBytes[3] = 0x00;5149pBytes[4] = 0x00; pBytes[5] = 0x00; pBytes[6] = 0x00; pBytes[7] = 0xc0;51505151pOutput[2] = 0;5152pOutput[3] = 0;51535154// Pack 8 endpoints (each ranging between [0,47]) using BISE starting at bit 175155int bit_pos = 17;5156astc_encode_trits(pOutput, pBlock->m_endpoints, bit_pos, 4);5157astc_encode_trits(pOutput, pBlock->m_endpoints + 5, bit_pos, 4);51585159// Pack 32 2-bit weights, which are stored from the top down into the block in opposite bit order.51605161for (uint32_t i = 0; i < 32; i++)5162{5163static const uint8_t s_reverse_bits[4] = { 0, 2, 1, 3 };5164const uint32_t ofs = 126 - (i * 2);5165pBytes[ofs >> 3] |= (s_reverse_bits[pBlock->m_weights[i]] << (ofs & 7));5166}5167}51685169// CEM mode 12 (LDR RGBA Direct), 8-bit endpoints, 1-bit weights5170// This ASTC mode is basically block truncation coding (BTC) using 1-bit weights and 8-bit/component endpoints - very convenient.5171static void astc_pack_block_cem_12_weight_range0(uint32_t* pOutput, const astc_block_params* pBlock)5172{5173uint8_t* pBytes = reinterpret_cast<uint8_t*>(pOutput);51745175// Write constant block mode, color component selector, number of partitions, color endpoint mode5176// https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#_block_mode5177pBytes[0] = 0x41; pBytes[1] = 0x84; pBytes[2] = 0x01; pBytes[3] = 0x00;5178pOutput[1] = 0;5179pBytes[8] = 0x00; pBytes[9] = 0x00; pBytes[10] = 0x00; pBytes[11] = 0xc0;5180pOutput[3] = 0;51815182// Pack 8 endpoints (each ranging between [0,255]) as 8-bits starting at bit 175183int bit_pos = 17;5184for (uint32_t i = 0; i < 8; i++)5185astc_set_bits(pOutput, bit_pos, pBlock->m_endpoints[i], 8);51865187// Pack 32 1-bit weights, which are stored from the top down into the block in opposite bit order.5188for (uint32_t i = 0; i < 32; i++)5189{5190const uint32_t ofs = 127 - i;5191pBytes[ofs >> 3] |= (pBlock->m_weights[i] << (ofs & 7));5192}5193}51945195#if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY5196// Optional 8-bit endpoint packing functions.51975198// CEM mode 4 (LDR Luminance+Alpha Direct), 8-bit endpoints, 2 bit weights5199static void astc_pack_block_cem_4_weight_range2(uint32_t* pOutput, const astc_block_params* pBlock)5200{5201uint8_t* pBytes = reinterpret_cast<uint8_t*>(pOutput);52025203// Write constant block mode, color component selector, number of partitions, color endpoint mode5204// https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#_block_mode5205pBytes[0] = 0x42; pBytes[1] = 0x84; pBytes[2] = 0x00; pBytes[3] = 0x00;5206pBytes[4] = 0x00; pBytes[5] = 0x00; pBytes[6] = 0x00; pBytes[7] = 0xc0;52075208pOutput[2] = 0;5209pOutput[3] = 0;52105211// Pack 4 endpoints (each ranging between [0,255]) as 8-bits starting at bit 175212int bit_pos = 17;5213for (uint32_t i = 0; i < 4; i++)5214astc_set_bits(pOutput, bit_pos, pBlock->m_endpoints[i], 8);52155216// Pack 32 2-bit weights, which are stored from the top down into the block in opposite bit order.5217for (uint32_t i = 0; i < 32; i++)5218{5219static const uint8_t s_reverse_bits[4] = { 0, 2, 1, 3 };5220const uint32_t ofs = 126 - (i * 2);5221pBytes[ofs >> 3] |= (s_reverse_bits[pBlock->m_weights[i]] << (ofs & 7));5222}5223}52245225// CEM mode 8 (LDR RGB Direct), 8-bit endpoints, 2 bit weights5226static void astc_pack_block_cem_8_weight_range2(uint32_t* pOutput, const astc_block_params* pBlock)5227{5228uint8_t* pBytes = reinterpret_cast<uint8_t*>(pOutput);52295230// Write constant block mode, color component selector, number of partitions, color endpoint mode5231// https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#_block_mode5232pBytes[0] = 0x42; pBytes[1] = 0x00; pBytes[2] = 0x01; pBytes[3] = 0x00;52335234pOutput[1] = 0;5235pOutput[2] = 0;5236pOutput[3] = 0;52375238// Pack 6 endpoints (each ranging between [0,255]) as 8-bits starting at bit 175239int bit_pos = 17;5240for (uint32_t i = 0; i < 6; i++)5241astc_set_bits(pOutput, bit_pos, pBlock->m_endpoints[i], 8);52425243// Pack 16 2-bit weights, which are stored from the top down into the block in opposite bit order.5244for (uint32_t i = 0; i < 16; i++)5245{5246static const uint8_t s_reverse_bits[4] = { 0, 2, 1, 3 };5247const uint32_t ofs = 126 - (i * 2);5248pBytes[ofs >> 3] |= (s_reverse_bits[pBlock->m_weights[i]] << (ofs & 7));5249}5250}5251#endif52525253// Optimal quantized [0,47] entry to use given [0,255] input5254static uint8_t g_astc_single_color_encoding_0[256];52555256// Optimal quantized [0,47] low/high values given [0,255] input assuming a selector of 15257static struct5258{5259uint8_t m_lo, m_hi;5260} g_astc_single_color_encoding_1[256];52615262static void transcoder_init_astc()5263{5264for (uint32_t base_color = 0; base_color < 32; base_color++)5265{5266for (uint32_t inten_table = 0; inten_table < 8; inten_table++)5267{5268for (uint32_t range_index = 0; range_index < NUM_ETC1_TO_ASTC_SELECTOR_RANGES; range_index++)5269{5270const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc[(inten_table * 32 + base_color) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + range_index * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];52715272uint32_t best_mapping = 0;5273uint32_t best_err = UINT32_MAX;5274for (uint32_t mapping_index = 0; mapping_index < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; mapping_index++)5275{5276if (pTable_g[mapping_index].m_err < best_err)5277{5278best_err = pTable_g[mapping_index].m_err;5279best_mapping = mapping_index;5280}5281}52825283g_etc1_to_astc_best_grayscale_mapping[base_color][inten_table][range_index] = static_cast<uint8_t>(best_mapping);5284}5285}5286}52875288#if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY5289for (uint32_t base_color = 0; base_color < 32; base_color++)5290{5291for (uint32_t inten_table = 0; inten_table < 8; inten_table++)5292{5293for (uint32_t range_index = 0; range_index < NUM_ETC1_TO_ASTC_SELECTOR_RANGES; range_index++)5294{5295const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc_0_255[(inten_table * 32 + base_color) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + range_index * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];52965297uint32_t best_mapping = 0;5298uint32_t best_err = UINT32_MAX;5299for (uint32_t mapping_index = 0; mapping_index < NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS; mapping_index++)5300{5301if (pTable_g[mapping_index].m_err < best_err)5302{5303best_err = pTable_g[mapping_index].m_err;5304best_mapping = mapping_index;5305}5306}53075308g_etc1_to_astc_best_grayscale_mapping_0_255[base_color][inten_table][range_index] = static_cast<uint8_t>(best_mapping);5309}5310}5311}5312#endif53135314for (uint32_t i = 0; i < NUM_ETC1_TO_ASTC_SELECTOR_RANGES; i++)5315{5316uint32_t l = g_etc1_to_astc_selector_ranges[i].m_low;5317uint32_t h = g_etc1_to_astc_selector_ranges[i].m_high;5318g_etc1_to_astc_selector_range_index[l][h] = i;5319}53205321// Endpoint dequantization, see:5322// https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-endpoint-unquantization5323for (uint32_t trit = 0; trit < 3; trit++)5324{5325for (uint32_t bit = 0; bit < 16; bit++)5326{5327const uint32_t A = (bit & 1) ? 511 : 0;5328const uint32_t B = (bit >> 1) | ((bit >> 1) << 6);5329const uint32_t C = 22;5330const uint32_t D = trit;53315332uint32_t unq = D * C + B;5333unq = unq ^ A;5334unq = (A & 0x80) | (unq >> 2);53355336g_ise_to_unquant[bit | (trit << 4)] = unq;5337}5338}53395340// Compute table used for optimal single color encoding.5341for (int i = 0; i < 256; i++)5342{5343int lowest_e = INT_MAX;53445345for (int lo = 0; lo < 48; lo++)5346{5347for (int hi = 0; hi < 48; hi++)5348{5349const int lo_v = g_ise_to_unquant[lo];5350const int hi_v = g_ise_to_unquant[hi];53515352int l = lo_v | (lo_v << 8);5353int h = hi_v | (hi_v << 8);53545355int v = ((l * (64 - 21) + (h * 21) + 32) / 64) >> 8;53565357int e = abs(v - i);53585359if (e < lowest_e)5360{5361g_astc_single_color_encoding_1[i].m_hi = static_cast<uint8_t>(hi);5362g_astc_single_color_encoding_1[i].m_lo = static_cast<uint8_t>(lo);53635364lowest_e = e;5365}53665367} // hi5368} // lo5369}53705371for (int i = 0; i < 256; i++)5372{5373int lowest_e = INT_MAX;53745375for (int lo = 0; lo < 48; lo++)5376{5377const int lo_v = g_ise_to_unquant[lo];53785379int e = abs(lo_v - i);53805381if (e < lowest_e)5382{5383g_astc_single_color_encoding_0[i] = static_cast<uint8_t>(lo);53845385lowest_e = e;5386}5387} // lo5388}5389}53905391// Converts opaque or color+alpha ETC1S block to ASTC 4x4.5392// This function tries to use the best ASTC mode given the block's actual contents.5393static void convert_etc1s_to_astc_4x4(void* pDst_block, const endpoint* pEndpoints, const selector* pSelector,5394bool transcode_alpha, const endpoint *pEndpoint_codebook, const selector *pSelector_codebook)5395{5396astc_block_params blk;53975398blk.m_endpoints[8] = 0;5399blk.m_endpoints[9] = 0;54005401int constant_alpha_val = 255;5402int num_unique_alpha_selectors = 1;54035404if (transcode_alpha)5405{5406const selector& alpha_selectors = pSelector_codebook[((uint16_t*)pDst_block)[1]];54075408num_unique_alpha_selectors = alpha_selectors.m_num_unique_selectors;54095410if (num_unique_alpha_selectors == 1)5411{5412const endpoint& alpha_endpoint = pEndpoint_codebook[((uint16_t*)pDst_block)[0]];54135414const color32& alpha_base_color = alpha_endpoint.m_color5;5415const uint32_t alpha_inten_table = alpha_endpoint.m_inten5;54165417int alpha_block_colors[4];5418decoder_etc_block::get_block_colors5_g(alpha_block_colors, alpha_base_color, alpha_inten_table);54195420constant_alpha_val = alpha_block_colors[alpha_selectors.m_lo_selector];5421}5422}54235424const color32& base_color = pEndpoints->m_color5;5425const uint32_t inten_table = pEndpoints->m_inten5;54265427const uint32_t low_selector = pSelector->m_lo_selector;5428const uint32_t high_selector = pSelector->m_hi_selector;54295430// Handle solid color or BTC blocks, which can always be encoded from ETC1S to ASTC losslessly.5431if ((pSelector->m_num_unique_selectors == 1) && (num_unique_alpha_selectors == 1))5432{5433// Both color and alpha are constant, write a solid color block and exit.5434// See https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-void-extent-blocks5435uint32_t r, g, b;5436decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b);54375438uint32_t* pOutput = static_cast<uint32_t*>(pDst_block);5439uint8_t* pBytes = reinterpret_cast<uint8_t*>(pDst_block);54405441pBytes[0] = 0xfc; pBytes[1] = 0xfd; pBytes[2] = 0xff; pBytes[3] = 0xff;54425443pOutput[1] = 0xffffffff;5444pOutput[2] = 0;5445pOutput[3] = 0;54465447int bit_pos = 64;5448astc_set_bits(pOutput, bit_pos, r | (r << 8), 16);5449astc_set_bits(pOutput, bit_pos, g | (g << 8), 16);5450astc_set_bits(pOutput, bit_pos, b | (b << 8), 16);5451astc_set_bits(pOutput, bit_pos, constant_alpha_val | (constant_alpha_val << 8), 16);54525453return;5454}5455else if ((pSelector->m_num_unique_selectors <= 2) && (num_unique_alpha_selectors <= 2))5456{5457// Both color and alpha use <= 2 unique selectors each.5458// Use block truncation coding, which is lossless with ASTC (8-bit endpoints, 1-bit weights).5459color32 block_colors[4];5460decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table);54615462blk.m_endpoints[0] = block_colors[low_selector].r;5463blk.m_endpoints[2] = block_colors[low_selector].g;5464blk.m_endpoints[4] = block_colors[low_selector].b;54655466blk.m_endpoints[1] = block_colors[high_selector].r;5467blk.m_endpoints[3] = block_colors[high_selector].g;5468blk.m_endpoints[5] = block_colors[high_selector].b;54695470int s0 = blk.m_endpoints[0] + blk.m_endpoints[2] + blk.m_endpoints[4];5471int s1 = blk.m_endpoints[1] + blk.m_endpoints[3] + blk.m_endpoints[5];5472bool invert = false;5473if (s1 < s0)5474{5475std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);5476std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);5477std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);5478invert = true;5479}54805481if (transcode_alpha)5482{5483const endpoint& alpha_endpoint = pEndpoint_codebook[((uint16_t*)pDst_block)[0]];5484const selector& alpha_selectors = pSelector_codebook[((uint16_t*)pDst_block)[1]];54855486const color32& alpha_base_color = alpha_endpoint.m_color5;5487const uint32_t alpha_inten_table = alpha_endpoint.m_inten5;54885489const uint32_t alpha_low_selector = alpha_selectors.m_lo_selector;5490const uint32_t alpha_high_selector = alpha_selectors.m_hi_selector;54915492int alpha_block_colors[4];5493decoder_etc_block::get_block_colors5_g(alpha_block_colors, alpha_base_color, alpha_inten_table);54945495blk.m_endpoints[6] = static_cast<uint8_t>(alpha_block_colors[alpha_low_selector]);5496blk.m_endpoints[7] = static_cast<uint8_t>(alpha_block_colors[alpha_high_selector]);54975498for (uint32_t y = 0; y < 4; y++)5499{5500for (uint32_t x = 0; x < 4; x++)5501{5502uint32_t s = alpha_selectors.get_selector(x, y);5503s = (s == alpha_high_selector) ? 1 : 0;55045505blk.m_weights[(x + y * 4) * 2 + 1] = static_cast<uint8_t>(s);5506} // x5507} // y5508}5509else5510{5511blk.m_endpoints[6] = 255;5512blk.m_endpoints[7] = 255;55135514for (uint32_t i = 0; i < 16; i++)5515blk.m_weights[i * 2 + 1] = 0;5516}55175518for (uint32_t y = 0; y < 4; y++)5519{5520for (uint32_t x = 0; x < 4; x++)5521{5522uint32_t s = pSelector->get_selector(x, y);55235524s = (s == high_selector) ? 1 : 0;55255526if (invert)5527s = 1 - s;55285529blk.m_weights[(x + y * 4) * 2] = static_cast<uint8_t>(s);5530} // x5531} // y55325533astc_pack_block_cem_12_weight_range0(reinterpret_cast<uint32_t*>(pDst_block), &blk);55345535return;5536}55375538// Either alpha and/or color use > 2 unique selectors each, so we must do something more complex.55395540#if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY5541// The optional higher quality modes use 8-bits endpoints vs. [0,47] endpoints.55425543// If the block's base color is grayscale, all pixels are grayscale, so encode the block as Luminance+Alpha.5544if ((base_color.r == base_color.g) && (base_color.r == base_color.b))5545{5546if (transcode_alpha)5547{5548const endpoint& alpha_endpoint = pEndpoint_codebook[((uint16_t*)pDst_block)[0]];5549const selector& alpha_selectors = pSelector_codebook[((uint16_t*)pDst_block)[1]];55505551const color32& alpha_base_color = alpha_endpoint.m_color5;5552const uint32_t alpha_inten_table = alpha_endpoint.m_inten5;55535554const uint32_t alpha_low_selector = alpha_selectors.m_lo_selector;5555const uint32_t alpha_high_selector = alpha_selectors.m_hi_selector;55565557if (num_unique_alpha_selectors <= 2)5558{5559// Simple alpha block with only 1 or 2 unique values, so use BTC. This is lossless.5560int alpha_block_colors[4];5561decoder_etc_block::get_block_colors5_g(alpha_block_colors, alpha_base_color, alpha_inten_table);55625563blk.m_endpoints[2] = static_cast<uint8_t>(alpha_block_colors[alpha_low_selector]);5564blk.m_endpoints[3] = static_cast<uint8_t>(alpha_block_colors[alpha_high_selector]);55655566for (uint32_t i = 0; i < 16; i++)5567{5568uint32_t s = alpha_selectors.get_selector(i & 3, i >> 2);5569blk.m_weights[i * 2 + 1] = (s == alpha_high_selector) ? 3 : 0;5570}5571}5572else5573{5574// Convert ETC1S alpha5575const uint32_t alpha_selector_range_table = g_etc1_to_astc_selector_range_index[alpha_low_selector][alpha_high_selector];55765577//[32][8][RANGES][MAPPING]5578const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc_0_255[(alpha_inten_table * 32 + alpha_base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + alpha_selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];55795580const uint32_t best_mapping = g_etc1_to_astc_best_grayscale_mapping_0_255[alpha_base_color.g][alpha_inten_table][alpha_selector_range_table];55815582blk.m_endpoints[2] = pTable_g[best_mapping].m_lo;5583blk.m_endpoints[3] = pTable_g[best_mapping].m_hi;55845585const uint8_t* pSelectors_xlat = &g_etc1_to_astc_selector_mappings[best_mapping][0];55865587for (uint32_t y = 0; y < 4; y++)5588{5589for (uint32_t x = 0; x < 4; x++)5590{5591uint32_t s = alpha_selectors.get_selector(x, y);5592uint32_t as = pSelectors_xlat[s];55935594blk.m_weights[(x + y * 4) * 2 + 1] = static_cast<uint8_t>(as);5595} // x5596} // y5597}5598}5599else5600{5601// No alpha slice - set output alpha to all 255's5602blk.m_endpoints[2] = 255;5603blk.m_endpoints[3] = 255;56045605for (uint32_t i = 0; i < 16; i++)5606blk.m_weights[i * 2 + 1] = 0;5607}56085609if (pSelector->m_num_unique_selectors <= 2)5610{5611// Simple color block with only 1 or 2 unique values, so use BTC. This is lossless.5612int block_colors[4];5613decoder_etc_block::get_block_colors5_g(block_colors, base_color, inten_table);56145615blk.m_endpoints[0] = static_cast<uint8_t>(block_colors[low_selector]);5616blk.m_endpoints[1] = static_cast<uint8_t>(block_colors[high_selector]);56175618for (uint32_t i = 0; i < 16; i++)5619{5620uint32_t s = pSelector->get_selector(i & 3, i >> 2);5621blk.m_weights[i * 2] = (s == high_selector) ? 3 : 0;5622}5623}5624else5625{5626// Convert ETC1S alpha5627const uint32_t selector_range_table = g_etc1_to_astc_selector_range_index[low_selector][high_selector];56285629//[32][8][RANGES][MAPPING]5630const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc_0_255[(inten_table * 32 + base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];56315632const uint32_t best_mapping = g_etc1_to_astc_best_grayscale_mapping_0_255[base_color.g][inten_table][selector_range_table];56335634blk.m_endpoints[0] = pTable_g[best_mapping].m_lo;5635blk.m_endpoints[1] = pTable_g[best_mapping].m_hi;56365637const uint8_t* pSelectors_xlat = &g_etc1_to_astc_selector_mappings[best_mapping][0];56385639for (uint32_t y = 0; y < 4; y++)5640{5641for (uint32_t x = 0; x < 4; x++)5642{5643uint32_t s = pSelector->get_selector(x, y);5644uint32_t as = pSelectors_xlat[s];56455646blk.m_weights[(x + y * 4) * 2] = static_cast<uint8_t>(as);5647} // x5648} // y5649}56505651astc_pack_block_cem_4_weight_range2(reinterpret_cast<uint32_t*>(pDst_block), &blk);5652return;5653}56545655// The block isn't grayscale and it uses > 2 unique selectors for opaque and/or alpha.5656// Check for fully opaque blocks, if so use 8-bit endpoints for slightly higher opaque quality (higher than BC1, but lower than BC7 mode 6 opaque).5657if ((num_unique_alpha_selectors == 1) && (constant_alpha_val == 255))5658{5659// Convert ETC1S color5660const uint32_t selector_range_table = g_etc1_to_astc_selector_range_index[low_selector][high_selector];56615662//[32][8][RANGES][MAPPING]5663const etc1_to_astc_solution* pTable_r = &g_etc1_to_astc_0_255[(inten_table * 32 + base_color.r) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];5664const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc_0_255[(inten_table * 32 + base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];5665const etc1_to_astc_solution* pTable_b = &g_etc1_to_astc_0_255[(inten_table * 32 + base_color.b) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];56665667uint32_t best_err = UINT_MAX;5668uint32_t best_mapping = 0;56695670assert(NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS == 10);5671#define DO_ITER(m) { uint32_t total_err = pTable_r[m].m_err + pTable_g[m].m_err + pTable_b[m].m_err; if (total_err < best_err) { best_err = total_err; best_mapping = m; } }5672DO_ITER(0); DO_ITER(1); DO_ITER(2); DO_ITER(3); DO_ITER(4);5673DO_ITER(5); DO_ITER(6); DO_ITER(7); DO_ITER(8); DO_ITER(9);5674#undef DO_ITER56755676blk.m_endpoints[0] = pTable_r[best_mapping].m_lo;5677blk.m_endpoints[1] = pTable_r[best_mapping].m_hi;56785679blk.m_endpoints[2] = pTable_g[best_mapping].m_lo;5680blk.m_endpoints[3] = pTable_g[best_mapping].m_hi;56815682blk.m_endpoints[4] = pTable_b[best_mapping].m_lo;5683blk.m_endpoints[5] = pTable_b[best_mapping].m_hi;56845685int s0 = blk.m_endpoints[0] + blk.m_endpoints[2] + blk.m_endpoints[4];5686int s1 = blk.m_endpoints[1] + blk.m_endpoints[3] + blk.m_endpoints[5];5687bool invert = false;56885689if (s1 < s0)5690{5691std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);5692std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);5693std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);5694invert = true;5695}56965697const uint8_t* pSelectors_xlat = &g_etc1_to_astc_selector_mappings[best_mapping][0];56985699for (uint32_t y = 0; y < 4; y++)5700{5701for (uint32_t x = 0; x < 4; x++)5702{5703uint32_t s = pSelector->get_selector(x, y);5704uint32_t as = pSelectors_xlat[s];5705if (invert)5706as = 3 - as;57075708blk.m_weights[x + y * 4] = static_cast<uint8_t>(as);5709} // x5710} // y57115712// Now pack to ASTC5713astc_pack_block_cem_8_weight_range2(reinterpret_cast<uint32_t*>(pDst_block), &blk);5714return;5715}5716#endif //#if BASISD_SUPPORT_ASTC_HIGHER_OPAQUE_QUALITY57175718// Nothing else worked, so fall back to CEM Mode 12 (LDR RGBA Direct), [0,47] endpoints, weight range 2 (2-bit weights), dual planes.5719// This mode can handle everything, but at slightly less quality than BC1.5720if (transcode_alpha)5721{5722const endpoint& alpha_endpoint = pEndpoint_codebook[((uint16_t*)pDst_block)[0]];5723const selector& alpha_selectors = pSelector_codebook[((uint16_t*)pDst_block)[1]];57245725const color32& alpha_base_color = alpha_endpoint.m_color5;5726const uint32_t alpha_inten_table = alpha_endpoint.m_inten5;57275728const uint32_t alpha_low_selector = alpha_selectors.m_lo_selector;5729const uint32_t alpha_high_selector = alpha_selectors.m_hi_selector;57305731if (alpha_low_selector == alpha_high_selector)5732{5733// Solid alpha block - use precomputed tables.5734int alpha_block_colors[4];5735decoder_etc_block::get_block_colors5_g(alpha_block_colors, alpha_base_color, alpha_inten_table);57365737const uint32_t g = alpha_block_colors[alpha_low_selector];57385739blk.m_endpoints[6] = g_astc_single_color_encoding_1[g].m_lo;5740blk.m_endpoints[7] = g_astc_single_color_encoding_1[g].m_hi;57415742for (uint32_t i = 0; i < 16; i++)5743blk.m_weights[i * 2 + 1] = 1;5744}5745else if ((alpha_inten_table >= 7) && (alpha_selectors.m_num_unique_selectors == 2) && (alpha_low_selector == 0) && (alpha_high_selector == 3))5746{5747// Handle outlier case where only the two outer colors are used with inten table 7.5748color32 alpha_block_colors[4];57495750decoder_etc_block::get_block_colors5(alpha_block_colors, alpha_base_color, alpha_inten_table);57515752const uint32_t g0 = alpha_block_colors[0].g;5753const uint32_t g1 = alpha_block_colors[3].g;57545755blk.m_endpoints[6] = g_astc_single_color_encoding_0[g0];5756blk.m_endpoints[7] = g_astc_single_color_encoding_0[g1];57575758for (uint32_t y = 0; y < 4; y++)5759{5760for (uint32_t x = 0; x < 4; x++)5761{5762uint32_t s = alpha_selectors.get_selector(x, y);5763uint32_t as = (s == alpha_high_selector) ? 3 : 0;57645765blk.m_weights[(x + y * 4) * 2 + 1] = static_cast<uint8_t>(as);5766} // x5767} // y5768}5769else5770{5771// Convert ETC1S alpha5772const uint32_t alpha_selector_range_table = g_etc1_to_astc_selector_range_index[alpha_low_selector][alpha_high_selector];57735774//[32][8][RANGES][MAPPING]5775const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc[(alpha_inten_table * 32 + alpha_base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + alpha_selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];57765777const uint32_t best_mapping = g_etc1_to_astc_best_grayscale_mapping[alpha_base_color.g][alpha_inten_table][alpha_selector_range_table];57785779blk.m_endpoints[6] = pTable_g[best_mapping].m_lo;5780blk.m_endpoints[7] = pTable_g[best_mapping].m_hi;57815782const uint8_t* pSelectors_xlat = &g_etc1_to_astc_selector_mappings[best_mapping][0];57835784for (uint32_t y = 0; y < 4; y++)5785{5786for (uint32_t x = 0; x < 4; x++)5787{5788uint32_t s = alpha_selectors.get_selector(x, y);5789uint32_t as = pSelectors_xlat[s];57905791blk.m_weights[(x + y * 4) * 2 + 1] = static_cast<uint8_t>(as);5792} // x5793} // y5794}5795}5796else5797{5798// No alpha slice - set output alpha to all 255's5799// 1 is 255 when dequantized5800blk.m_endpoints[6] = 1;5801blk.m_endpoints[7] = 1;58025803for (uint32_t i = 0; i < 16; i++)5804blk.m_weights[i * 2 + 1] = 0;5805}58065807if (low_selector == high_selector)5808{5809// Solid color block - use precomputed tables of optimal endpoints assuming selector weights are all 1.5810color32 block_colors[4];58115812decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table);58135814const uint32_t r = block_colors[low_selector].r;5815const uint32_t g = block_colors[low_selector].g;5816const uint32_t b = block_colors[low_selector].b;58175818blk.m_endpoints[0] = g_astc_single_color_encoding_1[r].m_lo;5819blk.m_endpoints[1] = g_astc_single_color_encoding_1[r].m_hi;58205821blk.m_endpoints[2] = g_astc_single_color_encoding_1[g].m_lo;5822blk.m_endpoints[3] = g_astc_single_color_encoding_1[g].m_hi;58235824blk.m_endpoints[4] = g_astc_single_color_encoding_1[b].m_lo;5825blk.m_endpoints[5] = g_astc_single_color_encoding_1[b].m_hi;58265827int s0 = g_ise_to_unquant[blk.m_endpoints[0]] + g_ise_to_unquant[blk.m_endpoints[2]] + g_ise_to_unquant[blk.m_endpoints[4]];5828int s1 = g_ise_to_unquant[blk.m_endpoints[1]] + g_ise_to_unquant[blk.m_endpoints[3]] + g_ise_to_unquant[blk.m_endpoints[5]];5829bool invert = false;58305831if (s1 < s0)5832{5833std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);5834std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);5835std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);5836invert = true;5837}58385839for (uint32_t i = 0; i < 16; i++)5840blk.m_weights[i * 2] = invert ? 2 : 1;5841}5842else if ((inten_table >= 7) && (pSelector->m_num_unique_selectors == 2) && (pSelector->m_lo_selector == 0) && (pSelector->m_hi_selector == 3))5843{5844// Handle outlier case where only the two outer colors are used with inten table 7.5845color32 block_colors[4];58465847decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table);58485849const uint32_t r0 = block_colors[0].r;5850const uint32_t g0 = block_colors[0].g;5851const uint32_t b0 = block_colors[0].b;58525853const uint32_t r1 = block_colors[3].r;5854const uint32_t g1 = block_colors[3].g;5855const uint32_t b1 = block_colors[3].b;58565857blk.m_endpoints[0] = g_astc_single_color_encoding_0[r0];5858blk.m_endpoints[1] = g_astc_single_color_encoding_0[r1];58595860blk.m_endpoints[2] = g_astc_single_color_encoding_0[g0];5861blk.m_endpoints[3] = g_astc_single_color_encoding_0[g1];58625863blk.m_endpoints[4] = g_astc_single_color_encoding_0[b0];5864blk.m_endpoints[5] = g_astc_single_color_encoding_0[b1];58655866int s0 = g_ise_to_unquant[blk.m_endpoints[0]] + g_ise_to_unquant[blk.m_endpoints[2]] + g_ise_to_unquant[blk.m_endpoints[4]];5867int s1 = g_ise_to_unquant[blk.m_endpoints[1]] + g_ise_to_unquant[blk.m_endpoints[3]] + g_ise_to_unquant[blk.m_endpoints[5]];5868bool invert = false;58695870if (s1 < s0)5871{5872std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);5873std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);5874std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);5875invert = true;5876}58775878for (uint32_t y = 0; y < 4; y++)5879{5880for (uint32_t x = 0; x < 4; x++)5881{5882uint32_t s = pSelector->get_selector(x, y);5883uint32_t as = (s == low_selector) ? 0 : 3;58845885if (invert)5886as = 3 - as;58875888blk.m_weights[(x + y * 4) * 2] = static_cast<uint8_t>(as);5889} // x5890} // y5891}5892else5893{5894// Convert ETC1S color5895const uint32_t selector_range_table = g_etc1_to_astc_selector_range_index[low_selector][high_selector];58965897//[32][8][RANGES][MAPPING]5898const etc1_to_astc_solution* pTable_r = &g_etc1_to_astc[(inten_table * 32 + base_color.r) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];5899const etc1_to_astc_solution* pTable_g = &g_etc1_to_astc[(inten_table * 32 + base_color.g) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];5900const etc1_to_astc_solution* pTable_b = &g_etc1_to_astc[(inten_table * 32 + base_color.b) * (NUM_ETC1_TO_ASTC_SELECTOR_RANGES * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS];59015902uint32_t best_err = UINT_MAX;5903uint32_t best_mapping = 0;59045905assert(NUM_ETC1_TO_ASTC_SELECTOR_MAPPINGS == 10);5906#define DO_ITER(m) { uint32_t total_err = pTable_r[m].m_err + pTable_g[m].m_err + pTable_b[m].m_err; if (total_err < best_err) { best_err = total_err; best_mapping = m; } }5907DO_ITER(0); DO_ITER(1); DO_ITER(2); DO_ITER(3); DO_ITER(4);5908DO_ITER(5); DO_ITER(6); DO_ITER(7); DO_ITER(8); DO_ITER(9);5909#undef DO_ITER59105911blk.m_endpoints[0] = pTable_r[best_mapping].m_lo;5912blk.m_endpoints[1] = pTable_r[best_mapping].m_hi;59135914blk.m_endpoints[2] = pTable_g[best_mapping].m_lo;5915blk.m_endpoints[3] = pTable_g[best_mapping].m_hi;59165917blk.m_endpoints[4] = pTable_b[best_mapping].m_lo;5918blk.m_endpoints[5] = pTable_b[best_mapping].m_hi;59195920int s0 = g_ise_to_unquant[blk.m_endpoints[0]] + g_ise_to_unquant[blk.m_endpoints[2]] + g_ise_to_unquant[blk.m_endpoints[4]];5921int s1 = g_ise_to_unquant[blk.m_endpoints[1]] + g_ise_to_unquant[blk.m_endpoints[3]] + g_ise_to_unquant[blk.m_endpoints[5]];5922bool invert = false;59235924if (s1 < s0)5925{5926std::swap(blk.m_endpoints[0], blk.m_endpoints[1]);5927std::swap(blk.m_endpoints[2], blk.m_endpoints[3]);5928std::swap(blk.m_endpoints[4], blk.m_endpoints[5]);5929invert = true;5930}59315932const uint8_t* pSelectors_xlat = &g_etc1_to_astc_selector_mappings[best_mapping][0];59335934for (uint32_t y = 0; y < 4; y++)5935{5936for (uint32_t x = 0; x < 4; x++)5937{5938uint32_t s = pSelector->get_selector(x, y);5939uint32_t as = pSelectors_xlat[s];5940if (invert)5941as = 3 - as;59425943blk.m_weights[(x + y * 4) * 2] = static_cast<uint8_t>(as);5944} // x5945} // y5946}59475948// Now pack to ASTC5949astc_pack_block_cem_12_weight_range2(reinterpret_cast<uint32_t *>(pDst_block), &blk);5950}5951#endif59525953#if BASISD_SUPPORT_ATC5954// ATC and PVRTC2 both use these tables.5955struct etc1s_to_atc_solution5956{5957uint8_t m_lo;5958uint8_t m_hi;5959uint16_t m_err;5960};59615962static dxt_selector_range g_etc1s_to_atc_selector_ranges[] =5963{5964{ 0, 3 },5965{ 1, 3 },5966{ 0, 2 },5967{ 1, 2 },5968{ 2, 3 },5969{ 0, 1 },5970};59715972const uint32_t NUM_ETC1S_TO_ATC_SELECTOR_RANGES = sizeof(g_etc1s_to_atc_selector_ranges) / sizeof(g_etc1s_to_atc_selector_ranges[0]);59735974static uint32_t g_etc1s_to_atc_selector_range_index[4][4];59755976const uint32_t NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS = 10;5977static const uint8_t g_etc1s_to_atc_selector_mappings[NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS][4] =5978{5979{ 0, 0, 1, 1 },5980{ 0, 0, 1, 2 },5981{ 0, 0, 1, 3 },5982{ 0, 0, 2, 3 },5983{ 0, 1, 1, 1 },5984{ 0, 1, 2, 2 },5985{ 0, 1, 2, 3 }, //6 - identity5986{ 0, 2, 3, 3 },5987{ 1, 2, 2, 2 },5988{ 1, 2, 3, 3 },5989};5990const uint32_t ATC_IDENTITY_SELECTOR_MAPPING_INDEX = 6;59915992#if BASISD_SUPPORT_PVRTC25993static const etc1s_to_atc_solution g_etc1s_to_pvrtc2_45[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] = {5994#include "basisu_transcoder_tables_pvrtc2_45.inc"5995};59965997#if 05998static const etc1s_to_atc_solution g_etc1s_to_pvrtc2_alpha_33[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] = {5999#include "basisu_transcoder_tables_pvrtc2_alpha_33.inc"6000};6001#endif60026003#endif60046005static const etc1s_to_atc_solution g_etc1s_to_atc_55[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] = {6006#include "basisu_transcoder_tables_atc_55.inc"6007};60086009static const etc1s_to_atc_solution g_etc1s_to_atc_56[32 * 8 * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS * NUM_ETC1S_TO_ATC_SELECTOR_RANGES] = {6010#include "basisu_transcoder_tables_atc_56.inc"6011};60126013struct atc_match_entry6014{6015uint8_t m_lo;6016uint8_t m_hi;6017};6018static atc_match_entry g_pvrtc2_match45_equals_1[256], g_atc_match55_equals_1[256], g_atc_match56_equals_1[256]; // selector 16019static atc_match_entry g_pvrtc2_match4[256], g_atc_match5[256], g_atc_match6[256];60206021static void prepare_atc_single_color_table(atc_match_entry* pTable, int size0, int size1, int sel)6022{6023for (int i = 0; i < 256; i++)6024{6025int lowest_e = 256;6026for (int lo = 0; lo < size0; lo++)6027{6028int lo_e = lo;6029if (size0 == 16)6030{6031lo_e = (lo_e << 1) | (lo_e >> 3);6032lo_e = (lo_e << 3) | (lo_e >> 2);6033}6034else if (size0 == 32)6035lo_e = (lo_e << 3) | (lo_e >> 2);6036else6037lo_e = (lo_e << 2) | (lo_e >> 4);60386039for (int hi = 0; hi < size1; hi++)6040{6041int hi_e = hi;6042if (size1 == 16)6043{6044// This is only for PVRTC2 - expand to 5 then 86045hi_e = (hi_e << 1) | (hi_e >> 3);6046hi_e = (hi_e << 3) | (hi_e >> 2);6047}6048else if (size1 == 32)6049hi_e = (hi_e << 3) | (hi_e >> 2);6050else6051hi_e = (hi_e << 2) | (hi_e >> 4);60526053int e;60546055if (sel == 1)6056{6057// Selector 16058e = abs(((lo_e * 5 + hi_e * 3) / 8) - i);6059}6060else6061{6062assert(sel == 3);60636064// Selector 36065e = abs(hi_e - i);6066}60676068if (e < lowest_e)6069{6070pTable[i].m_lo = static_cast<uint8_t>(lo);6071pTable[i].m_hi = static_cast<uint8_t>(hi);60726073lowest_e = e;6074}60756076} // hi6077} // lo6078} // i6079}60806081static void transcoder_init_atc()6082{6083prepare_atc_single_color_table(g_pvrtc2_match45_equals_1, 16, 32, 1);6084prepare_atc_single_color_table(g_atc_match55_equals_1, 32, 32, 1);6085prepare_atc_single_color_table(g_atc_match56_equals_1, 32, 64, 1);60866087prepare_atc_single_color_table(g_pvrtc2_match4, 1, 16, 3);6088prepare_atc_single_color_table(g_atc_match5, 1, 32, 3);6089prepare_atc_single_color_table(g_atc_match6, 1, 64, 3);60906091for (uint32_t i = 0; i < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; i++)6092{6093uint32_t l = g_etc1s_to_atc_selector_ranges[i].m_low;6094uint32_t h = g_etc1s_to_atc_selector_ranges[i].m_high;6095g_etc1s_to_atc_selector_range_index[l][h] = i;6096}6097}60986099struct atc_block6100{6101uint8_t m_lo[2];6102uint8_t m_hi[2];6103uint8_t m_sels[4];61046105void set_low_color(uint32_t r, uint32_t g, uint32_t b)6106{6107assert((r < 32) && (g < 32) && (b < 32));6108uint32_t x = (r << 10) | (g << 5) | b;6109m_lo[0] = x & 0xFF;6110m_lo[1] = (x >> 8) & 0xFF;6111}61126113void set_high_color(uint32_t r, uint32_t g, uint32_t b)6114{6115assert((r < 32) && (g < 64) && (b < 32));6116uint32_t x = (r << 11) | (g << 5) | b;6117m_hi[0] = x & 0xFF;6118m_hi[1] = (x >> 8) & 0xFF;6119}6120};61216122static void convert_etc1s_to_atc(void* pDst, const endpoint* pEndpoints, const selector* pSelector)6123{6124atc_block* pBlock = static_cast<atc_block*>(pDst);61256126const uint32_t low_selector = pSelector->m_lo_selector;6127const uint32_t high_selector = pSelector->m_hi_selector;61286129const color32& base_color = pEndpoints->m_color5;6130const uint32_t inten_table = pEndpoints->m_inten5;61316132if (low_selector == high_selector)6133{6134uint32_t r, g, b;6135decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b);61366137pBlock->set_low_color(g_atc_match55_equals_1[r].m_lo, g_atc_match56_equals_1[g].m_lo, g_atc_match55_equals_1[b].m_lo);6138pBlock->set_high_color(g_atc_match55_equals_1[r].m_hi, g_atc_match56_equals_1[g].m_hi, g_atc_match55_equals_1[b].m_hi);61396140pBlock->m_sels[0] = 0x55;6141pBlock->m_sels[1] = 0x55;6142pBlock->m_sels[2] = 0x55;6143pBlock->m_sels[3] = 0x55;61446145return;6146}6147else if ((inten_table >= 7) && (pSelector->m_num_unique_selectors == 2) && (pSelector->m_lo_selector == 0) && (pSelector->m_hi_selector == 3))6148{6149color32 block_colors[4];6150decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table);61516152const uint32_t r0 = block_colors[0].r;6153const uint32_t g0 = block_colors[0].g;6154const uint32_t b0 = block_colors[0].b;61556156const uint32_t r1 = block_colors[3].r;6157const uint32_t g1 = block_colors[3].g;6158const uint32_t b1 = block_colors[3].b;61596160pBlock->set_low_color(g_atc_match5[r0].m_hi, g_atc_match5[g0].m_hi, g_atc_match5[b0].m_hi);6161pBlock->set_high_color(g_atc_match5[r1].m_hi, g_atc_match6[g1].m_hi, g_atc_match5[b1].m_hi);61626163pBlock->m_sels[0] = pSelector->m_selectors[0];6164pBlock->m_sels[1] = pSelector->m_selectors[1];6165pBlock->m_sels[2] = pSelector->m_selectors[2];6166pBlock->m_sels[3] = pSelector->m_selectors[3];61676168return;6169}61706171const uint32_t selector_range_table = g_etc1s_to_atc_selector_range_index[low_selector][high_selector];61726173//[32][8][RANGES][MAPPING]6174const etc1s_to_atc_solution* pTable_r = &g_etc1s_to_atc_55[(inten_table * 32 + base_color.r) * (NUM_ETC1S_TO_ATC_SELECTOR_RANGES * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS];6175const etc1s_to_atc_solution* pTable_g = &g_etc1s_to_atc_56[(inten_table * 32 + base_color.g) * (NUM_ETC1S_TO_ATC_SELECTOR_RANGES * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS];6176const etc1s_to_atc_solution* pTable_b = &g_etc1s_to_atc_55[(inten_table * 32 + base_color.b) * (NUM_ETC1S_TO_ATC_SELECTOR_RANGES * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS];61776178uint32_t best_err = UINT_MAX;6179uint32_t best_mapping = 0;61806181assert(NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS == 10);6182#define DO_ITER(m) { uint32_t total_err = pTable_r[m].m_err + pTable_g[m].m_err + pTable_b[m].m_err; if (total_err < best_err) { best_err = total_err; best_mapping = m; } }6183DO_ITER(0); DO_ITER(1); DO_ITER(2); DO_ITER(3); DO_ITER(4);6184DO_ITER(5); DO_ITER(6); DO_ITER(7); DO_ITER(8); DO_ITER(9);6185#undef DO_ITER61866187pBlock->set_low_color(pTable_r[best_mapping].m_lo, pTable_g[best_mapping].m_lo, pTable_b[best_mapping].m_lo);6188pBlock->set_high_color(pTable_r[best_mapping].m_hi, pTable_g[best_mapping].m_hi, pTable_b[best_mapping].m_hi);61896190if (ATC_IDENTITY_SELECTOR_MAPPING_INDEX == best_mapping)6191{6192pBlock->m_sels[0] = pSelector->m_selectors[0];6193pBlock->m_sels[1] = pSelector->m_selectors[1];6194pBlock->m_sels[2] = pSelector->m_selectors[2];6195pBlock->m_sels[3] = pSelector->m_selectors[3];6196}6197else6198{6199const uint8_t* pSelectors_xlat = &g_etc1s_to_atc_selector_mappings[best_mapping][0];62006201const uint32_t sel_bits0 = pSelector->m_selectors[0];6202const uint32_t sel_bits1 = pSelector->m_selectors[1];6203const uint32_t sel_bits2 = pSelector->m_selectors[2];6204const uint32_t sel_bits3 = pSelector->m_selectors[3];62056206uint32_t atc_sels0 = 0, atc_sels1 = 0, atc_sels2 = 0, atc_sels3 = 0;62076208#define DO_X(x) { \6209const uint32_t x_shift = (x) * 2; \6210atc_sels0 |= (pSelectors_xlat[(sel_bits0 >> x_shift) & 3] << x_shift); \6211atc_sels1 |= (pSelectors_xlat[(sel_bits1 >> x_shift) & 3] << x_shift); \6212atc_sels2 |= (pSelectors_xlat[(sel_bits2 >> x_shift) & 3] << x_shift); \6213atc_sels3 |= (pSelectors_xlat[(sel_bits3 >> x_shift) & 3] << x_shift); }62146215DO_X(0);6216DO_X(1);6217DO_X(2);6218DO_X(3);6219#undef DO_X62206221pBlock->m_sels[0] = (uint8_t)atc_sels0;6222pBlock->m_sels[1] = (uint8_t)atc_sels1;6223pBlock->m_sels[2] = (uint8_t)atc_sels2;6224pBlock->m_sels[3] = (uint8_t)atc_sels3;6225}6226}62276228#if BASISD_WRITE_NEW_ATC_TABLES6229static void create_etc1s_to_atc_conversion_tables()6230{6231// ATC 556232FILE* pFile = nullptr;6233fopen_s(&pFile, "basisu_transcoder_tables_atc_55.inc", "w");62346235uint32_t n = 0;62366237for (int inten = 0; inten < 8; inten++)6238{6239for (uint32_t g = 0; g < 32; g++)6240{6241color32 block_colors[4];6242decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);62436244for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)6245{6246const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;6247const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;62486249for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)6250{6251uint32_t best_lo = 0;6252uint32_t best_hi = 0;6253uint64_t best_err = UINT64_MAX;62546255for (uint32_t hi = 0; hi <= 31; hi++)6256{6257for (uint32_t lo = 0; lo <= 31; lo++)6258{6259uint32_t colors[4];62606261colors[0] = (lo << 3) | (lo >> 2);6262colors[3] = (hi << 3) | (hi >> 2);62636264colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;6265colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;62666267uint64_t total_err = 0;62686269for (uint32_t s = low_selector; s <= high_selector; s++)6270{6271int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];62726273int err_scale = 1;6274// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor6275// the low/high selectors which are clamping to either 0 or 255.6276if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))6277err_scale = 5;62786279total_err += (err * err) * err_scale;6280}62816282if (total_err < best_err)6283{6284best_err = total_err;6285best_lo = lo;6286best_hi = hi;6287}6288}6289}62906291//assert(best_err <= 0xFFFF);6292best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);62936294fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);6295n++;6296if ((n & 31) == 31)6297fprintf(pFile, "\n");6298} // m6299} // sr6300} // g6301} // inten63026303fclose(pFile);6304pFile = nullptr;63056306// ATC 566307fopen_s(&pFile, "basisu_transcoder_tables_atc_56.inc", "w");63086309n = 0;63106311for (int inten = 0; inten < 8; inten++)6312{6313for (uint32_t g = 0; g < 32; g++)6314{6315color32 block_colors[4];6316decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);63176318for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)6319{6320const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;6321const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;63226323for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)6324{6325uint32_t best_lo = 0;6326uint32_t best_hi = 0;6327uint64_t best_err = UINT64_MAX;63286329for (uint32_t hi = 0; hi <= 63; hi++)6330{6331for (uint32_t lo = 0; lo <= 31; lo++)6332{6333uint32_t colors[4];63346335colors[0] = (lo << 3) | (lo >> 2);6336colors[3] = (hi << 2) | (hi >> 4);63376338colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;6339colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;63406341uint64_t total_err = 0;63426343for (uint32_t s = low_selector; s <= high_selector; s++)6344{6345int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];63466347int err_scale = 1;6348// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor6349// the low/high selectors which are clamping to either 0 or 255.6350if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))6351err_scale = 5;63526353total_err += (err * err) * err_scale;6354}63556356if (total_err < best_err)6357{6358best_err = total_err;6359best_lo = lo;6360best_hi = hi;6361}6362}6363}63646365//assert(best_err <= 0xFFFF);6366best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);63676368fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);6369n++;6370if ((n & 31) == 31)6371fprintf(pFile, "\n");6372} // m6373} // sr6374} // g6375} // inten63766377fclose(pFile);63786379// PVRTC2 456380fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_45.inc", "w");63816382n = 0;63836384for (int inten = 0; inten < 8; inten++)6385{6386for (uint32_t g = 0; g < 32; g++)6387{6388color32 block_colors[4];6389decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);63906391for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)6392{6393const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;6394const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;63956396for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)6397{6398uint32_t best_lo = 0;6399uint32_t best_hi = 0;6400uint64_t best_err = UINT64_MAX;64016402for (uint32_t hi = 0; hi <= 31; hi++)6403{6404for (uint32_t lo = 0; lo <= 15; lo++)6405{6406uint32_t colors[4];64076408colors[0] = (lo << 1) | (lo >> 3);6409colors[0] = (colors[0] << 3) | (colors[0] >> 2);64106411colors[3] = (hi << 3) | (hi >> 2);64126413colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;6414colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;64156416uint64_t total_err = 0;64176418for (uint32_t s = low_selector; s <= high_selector; s++)6419{6420int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];64216422int err_scale = 1;6423// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor6424// the low/high selectors which are clamping to either 0 or 255.6425if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))6426err_scale = 5;64276428total_err += (err * err) * err_scale;6429}64306431if (total_err < best_err)6432{6433best_err = total_err;6434best_lo = lo;6435best_hi = hi;6436}6437}6438}64396440//assert(best_err <= 0xFFFF);6441best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);64426443fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);6444n++;6445if ((n & 31) == 31)6446fprintf(pFile, "\n");6447} // m6448} // sr6449} // g6450} // inten64516452fclose(pFile);64536454#if 06455// PVRTC2 346456fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_34.inc", "w");64576458n = 0;64596460for (int inten = 0; inten < 8; inten++)6461{6462for (uint32_t g = 0; g < 32; g++)6463{6464color32 block_colors[4];6465decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);64666467for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)6468{6469const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;6470const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;64716472for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)6473{6474uint32_t best_lo = 0;6475uint32_t best_hi = 0;6476uint64_t best_err = UINT64_MAX;64776478for (uint32_t hi = 0; hi <= 15; hi++)6479{6480for (uint32_t lo = 0; lo <= 7; lo++)6481{6482uint32_t colors[4];64836484colors[0] = (lo << 2) | (lo >> 1);6485colors[0] = (colors[0] << 3) | (colors[0] >> 2);64866487colors[3] = (hi << 1) | (hi >> 3);6488colors[3] = (colors[3] << 3) | (colors[3] >> 2);64896490colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;6491colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;64926493uint64_t total_err = 0;64946495for (uint32_t s = low_selector; s <= high_selector; s++)6496{6497int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];64986499int err_scale = 1;6500// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor6501// the low/high selectors which are clamping to either 0 or 255.6502if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))6503err_scale = 5;65046505total_err += (err * err) * err_scale;6506}65076508if (total_err < best_err)6509{6510best_err = total_err;6511best_lo = lo;6512best_hi = hi;6513}6514}6515}65166517//assert(best_err <= 0xFFFF);6518best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);65196520fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);6521n++;6522if ((n & 31) == 31)6523fprintf(pFile, "\n");6524} // m6525} // sr6526} // g6527} // inten65286529fclose(pFile);6530#endif6531#if 06532// PVRTC2 446533fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_44.inc", "w");65346535n = 0;65366537for (int inten = 0; inten < 8; inten++)6538{6539for (uint32_t g = 0; g < 32; g++)6540{6541color32 block_colors[4];6542decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);65436544for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)6545{6546const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;6547const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;65486549for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)6550{6551uint32_t best_lo = 0;6552uint32_t best_hi = 0;6553uint64_t best_err = UINT64_MAX;65546555for (uint32_t hi = 0; hi <= 15; hi++)6556{6557for (uint32_t lo = 0; lo <= 15; lo++)6558{6559uint32_t colors[4];65606561colors[0] = (lo << 1) | (lo >> 3);6562colors[0] = (colors[0] << 3) | (colors[0] >> 2);65636564colors[3] = (hi << 1) | (hi >> 3);6565colors[3] = (colors[3] << 3) | (colors[3] >> 2);65666567colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;6568colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;65696570uint64_t total_err = 0;65716572for (uint32_t s = low_selector; s <= high_selector; s++)6573{6574int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];65756576int err_scale = 1;6577// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor6578// the low/high selectors which are clamping to either 0 or 255.6579if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))6580err_scale = 5;65816582total_err += (err * err) * err_scale;6583}65846585if (total_err < best_err)6586{6587best_err = total_err;6588best_lo = lo;6589best_hi = hi;6590}6591}6592}65936594//assert(best_err <= 0xFFFF);6595best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);65966597fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);6598n++;6599if ((n & 31) == 31)6600fprintf(pFile, "\n");6601} // m6602} // sr6603} // g6604} // inten66056606fclose(pFile);6607#endif66086609// PVRTC2 alpha 336610fopen_s(&pFile, "basisu_transcoder_tables_pvrtc2_alpha_33.inc", "w");66116612n = 0;66136614for (int inten = 0; inten < 8; inten++)6615{6616for (uint32_t g = 0; g < 32; g++)6617{6618color32 block_colors[4];6619decoder_etc_block::get_diff_subblock_colors(block_colors, decoder_etc_block::pack_color5(color32(g, g, g, 255), false), inten);66206621for (uint32_t sr = 0; sr < NUM_ETC1S_TO_ATC_SELECTOR_RANGES; sr++)6622{6623const uint32_t low_selector = g_etc1s_to_atc_selector_ranges[sr].m_low;6624const uint32_t high_selector = g_etc1s_to_atc_selector_ranges[sr].m_high;66256626for (uint32_t m = 0; m < NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS; m++)6627{6628uint32_t best_lo = 0;6629uint32_t best_hi = 0;6630uint64_t best_err = UINT64_MAX;66316632for (uint32_t hi = 0; hi <= 7; hi++)6633{6634for (uint32_t lo = 0; lo <= 7; lo++)6635{6636uint32_t colors[4];66376638colors[0] = (lo << 1);6639colors[0] = (colors[0] << 4) | colors[0];66406641colors[3] = (hi << 1) | 1;6642colors[3] = (colors[3] << 4) | colors[3];66436644colors[1] = (colors[0] * 5 + colors[3] * 3) / 8;6645colors[2] = (colors[3] * 5 + colors[0] * 3) / 8;66466647uint64_t total_err = 0;66486649for (uint32_t s = low_selector; s <= high_selector; s++)6650{6651int err = block_colors[s].g - colors[g_etc1s_to_atc_selector_mappings[m][s]];66526653int err_scale = 1;6654// Special case when the intensity table is 7, low_selector is 0, and high_selector is 3. In this extreme case, it's likely the encoder is trying to strongly favor6655// the low/high selectors which are clamping to either 0 or 255.6656if (((inten == 7) && (low_selector == 0) && (high_selector == 3)) && ((s == 0) || (s == 3)))6657err_scale = 5;66586659total_err += (err * err) * err_scale;6660}66616662if (total_err < best_err)6663{6664best_err = total_err;6665best_lo = lo;6666best_hi = hi;6667}6668}6669}66706671//assert(best_err <= 0xFFFF);6672best_err = basisu::minimum<uint32_t>(best_err, 0xFFFF);66736674fprintf(pFile, "{%u,%u,%u},", best_lo, best_hi, (uint32_t)best_err);6675n++;6676if ((n & 31) == 31)6677fprintf(pFile, "\n");6678} // m6679} // sr6680} // g6681} // inten66826683fclose(pFile);6684}6685#endif // BASISD_WRITE_NEW_ATC_TABLES66866687#endif // BASISD_SUPPORT_ATC66886689#if BASISD_SUPPORT_PVRTC26690struct pvrtc2_block6691{6692uint8_t m_modulation[4];66936694union6695{6696union6697{6698// Opaque mode: RGB colora=554 and colorb=5556699struct6700{6701uint32_t m_mod_flag : 1;6702uint32_t m_blue_a : 4;6703uint32_t m_green_a : 5;6704uint32_t m_red_a : 5;6705uint32_t m_hard_flag : 1;6706uint32_t m_blue_b : 5;6707uint32_t m_green_b : 5;6708uint32_t m_red_b : 5;6709uint32_t m_opaque_flag : 1;67106711} m_opaque_color_data;67126713// Transparent mode: RGBA colora=4433 and colorb=44436714struct6715{6716uint32_t m_mod_flag : 1;6717uint32_t m_blue_a : 3;6718uint32_t m_green_a : 4;6719uint32_t m_red_a : 4;6720uint32_t m_alpha_a : 3;6721uint32_t m_hard_flag : 1;6722uint32_t m_blue_b : 4;6723uint32_t m_green_b : 4;6724uint32_t m_red_b : 4;6725uint32_t m_alpha_b : 3;6726uint32_t m_opaque_flag : 1;67276728} m_trans_color_data;6729};67306731uint32_t m_color_data_bits;6732};67336734// 5546735void set_low_color(uint32_t r, uint32_t g, uint32_t b)6736{6737assert((r < 32) && (g < 32) && (b < 16));6738m_opaque_color_data.m_red_a = r;6739m_opaque_color_data.m_green_a = g;6740m_opaque_color_data.m_blue_a = b;6741}67426743// 5556744void set_high_color(uint32_t r, uint32_t g, uint32_t b)6745{6746assert((r < 32) && (g < 32) && (b < 32));6747m_opaque_color_data.m_red_b = r;6748m_opaque_color_data.m_green_b = g;6749m_opaque_color_data.m_blue_b = b;6750}67516752// 44336753void set_trans_low_color(uint32_t r, uint32_t g, uint32_t b, uint32_t a)6754{6755assert((r < 16) && (g < 16) && (b < 8) && (a < 8));6756m_trans_color_data.m_red_a = r;6757m_trans_color_data.m_green_a = g;6758m_trans_color_data.m_blue_a = b;6759m_trans_color_data.m_alpha_a = a;6760}67616762// 44436763void set_trans_high_color(uint32_t r, uint32_t g, uint32_t b, uint32_t a)6764{6765assert((r < 16) && (g < 16) && (b < 16) && (a < 8));6766m_trans_color_data.m_red_b = r;6767m_trans_color_data.m_green_b = g;6768m_trans_color_data.m_blue_b = b;6769m_trans_color_data.m_alpha_b = a;6770}6771};67726773static struct6774{6775uint8_t m_l, m_h;6776} g_pvrtc2_trans_match34[256];67776778static struct6779{6780uint8_t m_l, m_h;6781} g_pvrtc2_trans_match44[256];67826783static struct6784{6785uint8_t m_l, m_h;6786} g_pvrtc2_alpha_match33[256];67876788static struct6789{6790uint8_t m_l, m_h;6791} g_pvrtc2_alpha_match33_0[256];67926793static struct6794{6795uint8_t m_l, m_h;6796} g_pvrtc2_alpha_match33_3[256];67976798// PVRTC2 can be forced to look like a slightly weaker variant of ATC/BC1, so that's what we do here for simplicity.6799static void convert_etc1s_to_pvrtc2_rgb(void* pDst, const endpoint* pEndpoints, const selector* pSelector)6800{6801pvrtc2_block* pBlock = static_cast<pvrtc2_block*>(pDst);68026803pBlock->m_opaque_color_data.m_hard_flag = 1;6804pBlock->m_opaque_color_data.m_mod_flag = 0;6805pBlock->m_opaque_color_data.m_opaque_flag = 1;68066807const uint32_t low_selector = pSelector->m_lo_selector;6808const uint32_t high_selector = pSelector->m_hi_selector;68096810const color32& base_color = pEndpoints->m_color5;6811const uint32_t inten_table = pEndpoints->m_inten5;68126813if (low_selector == high_selector)6814{6815uint32_t r, g, b;6816decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b);68176818pBlock->set_low_color(g_atc_match55_equals_1[r].m_lo, g_atc_match55_equals_1[g].m_lo, g_pvrtc2_match45_equals_1[b].m_lo);6819pBlock->set_high_color(g_atc_match55_equals_1[r].m_hi, g_atc_match55_equals_1[g].m_hi, g_pvrtc2_match45_equals_1[b].m_hi);68206821pBlock->m_modulation[0] = 0x55;6822pBlock->m_modulation[1] = 0x55;6823pBlock->m_modulation[2] = 0x55;6824pBlock->m_modulation[3] = 0x55;68256826return;6827}6828else if ((inten_table >= 7) && (pSelector->m_num_unique_selectors == 2) && (pSelector->m_lo_selector == 0) && (pSelector->m_hi_selector == 3))6829{6830color32 block_colors[4];6831decoder_etc_block::get_block_colors5(block_colors, base_color, inten_table);68326833const uint32_t r0 = block_colors[0].r;6834const uint32_t g0 = block_colors[0].g;6835const uint32_t b0 = block_colors[0].b;68366837const uint32_t r1 = block_colors[3].r;6838const uint32_t g1 = block_colors[3].g;6839const uint32_t b1 = block_colors[3].b;68406841pBlock->set_low_color(g_atc_match5[r0].m_hi, g_atc_match5[g0].m_hi, g_pvrtc2_match4[b0].m_hi);6842pBlock->set_high_color(g_atc_match5[r1].m_hi, g_atc_match5[g1].m_hi, g_atc_match5[b1].m_hi);68436844pBlock->m_modulation[0] = pSelector->m_selectors[0];6845pBlock->m_modulation[1] = pSelector->m_selectors[1];6846pBlock->m_modulation[2] = pSelector->m_selectors[2];6847pBlock->m_modulation[3] = pSelector->m_selectors[3];68486849return;6850}68516852const uint32_t selector_range_table = g_etc1s_to_atc_selector_range_index[low_selector][high_selector];68536854//[32][8][RANGES][MAPPING]6855const etc1s_to_atc_solution* pTable_r = &g_etc1s_to_atc_55[(inten_table * 32 + base_color.r) * (NUM_ETC1S_TO_ATC_SELECTOR_RANGES * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS];6856const etc1s_to_atc_solution* pTable_g = &g_etc1s_to_atc_55[(inten_table * 32 + base_color.g) * (NUM_ETC1S_TO_ATC_SELECTOR_RANGES * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS];6857const etc1s_to_atc_solution* pTable_b = &g_etc1s_to_pvrtc2_45[(inten_table * 32 + base_color.b) * (NUM_ETC1S_TO_ATC_SELECTOR_RANGES * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS) + selector_range_table * NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS];68586859uint32_t best_err = UINT_MAX;6860uint32_t best_mapping = 0;68616862assert(NUM_ETC1S_TO_ATC_SELECTOR_MAPPINGS == 10);6863#define DO_ITER(m) { uint32_t total_err = pTable_r[m].m_err + pTable_g[m].m_err + pTable_b[m].m_err; if (total_err < best_err) { best_err = total_err; best_mapping = m; } }6864DO_ITER(0); DO_ITER(1); DO_ITER(2); DO_ITER(3); DO_ITER(4);6865DO_ITER(5); DO_ITER(6); DO_ITER(7); DO_ITER(8); DO_ITER(9);6866#undef DO_ITER68676868pBlock->set_low_color(pTable_r[best_mapping].m_lo, pTable_g[best_mapping].m_lo, pTable_b[best_mapping].m_lo);6869pBlock->set_high_color(pTable_r[best_mapping].m_hi, pTable_g[best_mapping].m_hi, pTable_b[best_mapping].m_hi);68706871if (ATC_IDENTITY_SELECTOR_MAPPING_INDEX == best_mapping)6872{6873pBlock->m_modulation[0] = pSelector->m_selectors[0];6874pBlock->m_modulation[1] = pSelector->m_selectors[1];6875pBlock->m_modulation[2] = pSelector->m_selectors[2];6876pBlock->m_modulation[3] = pSelector->m_selectors[3];6877}6878else6879{6880// TODO: We could make this faster using several precomputed 256 entry tables, like ETC1S->BC1 does.6881const uint8_t* pSelectors_xlat = &g_etc1s_to_atc_selector_mappings[best_mapping][0];68826883const uint32_t sel_bits0 = pSelector->m_selectors[0];6884const uint32_t sel_bits1 = pSelector->m_selectors[1];6885const uint32_t sel_bits2 = pSelector->m_selectors[2];6886const uint32_t sel_bits3 = pSelector->m_selectors[3];68876888uint32_t sels0 = 0, sels1 = 0, sels2 = 0, sels3 = 0;68896890#define DO_X(x) { \6891const uint32_t x_shift = (x) * 2; \6892sels0 |= (pSelectors_xlat[(sel_bits0 >> x_shift) & 3] << x_shift); \6893sels1 |= (pSelectors_xlat[(sel_bits1 >> x_shift) & 3] << x_shift); \6894sels2 |= (pSelectors_xlat[(sel_bits2 >> x_shift) & 3] << x_shift); \6895sels3 |= (pSelectors_xlat[(sel_bits3 >> x_shift) & 3] << x_shift); }68966897DO_X(0);6898DO_X(1);6899DO_X(2);6900DO_X(3);6901#undef DO_X69026903pBlock->m_modulation[0] = (uint8_t)sels0;6904pBlock->m_modulation[1] = (uint8_t)sels1;6905pBlock->m_modulation[2] = (uint8_t)sels2;6906pBlock->m_modulation[3] = (uint8_t)sels3;6907}6908}69096910typedef struct { float c[4]; } vec4F;69116912static inline vec4F* vec4F_set_scalar(vec4F* pV, float x) { pV->c[0] = x; pV->c[1] = x; pV->c[2] = x; pV->c[3] = x; return pV; }6913static inline vec4F* vec4F_set(vec4F* pV, float x, float y, float z, float w) { pV->c[0] = x; pV->c[1] = y; pV->c[2] = z; pV->c[3] = w; return pV; }6914static inline vec4F* vec4F_saturate_in_place(vec4F* pV) { pV->c[0] = saturate(pV->c[0]); pV->c[1] = saturate(pV->c[1]); pV->c[2] = saturate(pV->c[2]); pV->c[3] = saturate(pV->c[3]); return pV; }6915static inline vec4F vec4F_saturate(const vec4F* pV) { vec4F res; res.c[0] = saturate(pV->c[0]); res.c[1] = saturate(pV->c[1]); res.c[2] = saturate(pV->c[2]); res.c[3] = saturate(pV->c[3]); return res; }6916static inline vec4F vec4F_from_color(const color32* pC) { vec4F res; vec4F_set(&res, pC->c[0], pC->c[1], pC->c[2], pC->c[3]); return res; }6917static inline vec4F vec4F_add(const vec4F* pLHS, const vec4F* pRHS) { vec4F res; vec4F_set(&res, pLHS->c[0] + pRHS->c[0], pLHS->c[1] + pRHS->c[1], pLHS->c[2] + pRHS->c[2], pLHS->c[3] + pRHS->c[3]); return res; }6918static inline vec4F vec4F_sub(const vec4F* pLHS, const vec4F* pRHS) { vec4F res; vec4F_set(&res, pLHS->c[0] - pRHS->c[0], pLHS->c[1] - pRHS->c[1], pLHS->c[2] - pRHS->c[2], pLHS->c[3] - pRHS->c[3]); return res; }6919static inline float vec4F_dot(const vec4F* pLHS, const vec4F* pRHS) { return pLHS->c[0] * pRHS->c[0] + pLHS->c[1] * pRHS->c[1] + pLHS->c[2] * pRHS->c[2] + pLHS->c[3] * pRHS->c[3]; }6920static inline vec4F vec4F_mul(const vec4F* pLHS, float s) { vec4F res; vec4F_set(&res, pLHS->c[0] * s, pLHS->c[1] * s, pLHS->c[2] * s, pLHS->c[3] * s); return res; }6921static inline vec4F* vec4F_normalize_in_place(vec4F* pV) { float s = pV->c[0] * pV->c[0] + pV->c[1] * pV->c[1] + pV->c[2] * pV->c[2] + pV->c[3] * pV->c[3]; if (s != 0.0f) { s = 1.0f / sqrtf(s); pV->c[0] *= s; pV->c[1] *= s; pV->c[2] *= s; pV->c[3] *= s; } return pV; }69226923static color32 convert_rgba_5554_to_8888(const color32& col)6924{6925return color32((col[0] << 3) | (col[0] >> 2), (col[1] << 3) | (col[1] >> 2), (col[2] << 3) | (col[2] >> 2), (col[3] << 4) | col[3]);6926}69276928static inline int sq(int x) { return x * x; }69296930// PVRTC2 is a slightly borked format for alpha: In Non-Interpolated mode, the way AlphaB8 is exanded from 4 to 8 bits means it can never be 0.6931// This is actually very bad, because on 100% transparent blocks which have non-trivial color pixels, part of the color channel will leak into alpha!6932// And there's nothing straightforward we can do because using the other modes is too expensive/complex. I can see why Apple didn't adopt it.6933static void convert_etc1s_to_pvrtc2_rgba(void* pDst, const endpoint* pEndpoints, const selector* pSelector, const endpoint* pEndpoint_codebook, const selector* pSelector_codebook)6934{6935pvrtc2_block* pBlock = static_cast<pvrtc2_block*>(pDst);69366937const endpoint& alpha_endpoint = pEndpoint_codebook[((uint16_t*)pBlock)[0]];6938const selector& alpha_selectors = pSelector_codebook[((uint16_t*)pBlock)[1]];69396940pBlock->m_opaque_color_data.m_hard_flag = 1;6941pBlock->m_opaque_color_data.m_mod_flag = 0;6942pBlock->m_opaque_color_data.m_opaque_flag = 0;69436944const int num_unique_alpha_selectors = alpha_selectors.m_num_unique_selectors;69456946const color32& alpha_base_color = alpha_endpoint.m_color5;6947const uint32_t alpha_inten_table = alpha_endpoint.m_inten5;69486949int constant_alpha_val = -1;69506951int alpha_block_colors[4];6952decoder_etc_block::get_block_colors5_g(alpha_block_colors, alpha_base_color, alpha_inten_table);69536954if (num_unique_alpha_selectors == 1)6955{6956constant_alpha_val = alpha_block_colors[alpha_selectors.m_lo_selector];6957}6958else6959{6960constant_alpha_val = alpha_block_colors[alpha_selectors.m_lo_selector];69616962for (uint32_t i = alpha_selectors.m_lo_selector + 1; i <= alpha_selectors.m_hi_selector; i++)6963{6964if (constant_alpha_val != alpha_block_colors[i])6965{6966constant_alpha_val = -1;6967break;6968}6969}6970}69716972if (constant_alpha_val >= 250)6973{6974// It's opaque enough, so don't bother trying to encode it as an alpha block.6975convert_etc1s_to_pvrtc2_rgb(pDst, pEndpoints, pSelector);6976return;6977}69786979const color32& base_color = pEndpoints->m_color5;6980const uint32_t inten_table = pEndpoints->m_inten5;69816982const uint32_t low_selector = pSelector->m_lo_selector;6983const uint32_t high_selector = pSelector->m_hi_selector;69846985const int num_unique_color_selectors = pSelector->m_num_unique_selectors;69866987// We need to reencode the block at the pixel level, unfortunately, from two ETC1S planes.6988// Do 4D incremental PCA, project all pixels to this hyperline, then quantize to packed endpoints and compute the modulation values.6989const int br = (base_color.r << 3) | (base_color.r >> 2);6990const int bg = (base_color.g << 3) | (base_color.g >> 2);6991const int bb = (base_color.b << 3) | (base_color.b >> 2);69926993color32 block_cols[4];6994for (uint32_t i = 0; i < 4; i++)6995{6996const int ci = g_etc1_inten_tables[inten_table][i];6997block_cols[i].set_clamped(br + ci, bg + ci, bb + ci, alpha_block_colors[i]);6998}69997000bool solid_color_block = true;7001if (num_unique_color_selectors > 1)7002{7003for (uint32_t i = low_selector + 1; i <= high_selector; i++)7004{7005if ((block_cols[low_selector].r != block_cols[i].r) || (block_cols[low_selector].g != block_cols[i].g) || (block_cols[low_selector].b != block_cols[i].b))7006{7007solid_color_block = false;7008break;7009}7010}7011}70127013if ((solid_color_block) && (constant_alpha_val >= 0))7014{7015// Constant color/alpha block.7016// This is more complex than it may seem because of the way color and alpha are packed in PVRTC2. We need to evaluate mod0, mod1 and mod3 encodings to find the best one.7017uint32_t r, g, b;7018decoder_etc_block::get_block_color5(base_color, inten_table, low_selector, r, g, b);70197020// Mod 07021uint32_t lr0 = (r * 15 + 128) / 255, lg0 = (g * 15 + 128) / 255, lb0 = (b * 7 + 128) / 255;7022uint32_t la0 = g_pvrtc2_alpha_match33_0[constant_alpha_val].m_l;70237024uint32_t cr0 = (lr0 << 1) | (lr0 >> 3);7025uint32_t cg0 = (lg0 << 1) | (lg0 >> 3);7026uint32_t cb0 = (lb0 << 2) | (lb0 >> 1);7027uint32_t ca0 = (la0 << 1);70287029cr0 = (cr0 << 3) | (cr0 >> 2);7030cg0 = (cg0 << 3) | (cg0 >> 2);7031cb0 = (cb0 << 3) | (cb0 >> 2);7032ca0 = (ca0 << 4) | ca0;70337034uint32_t err0 = sq(cr0 - r) + sq(cg0 - g) + sq(cb0 - b) + sq(ca0 - constant_alpha_val) * 2;70357036// If the alpha is < 3 or so we're kinda screwed. It's better to have some RGB error than it is to turn a 100% transparent area slightly opaque.7037if ((err0 == 0) || (constant_alpha_val < 3))7038{7039pBlock->set_trans_low_color(lr0, lg0, lb0, la0);7040pBlock->set_trans_high_color(0, 0, 0, 0);70417042pBlock->m_modulation[0] = 0;7043pBlock->m_modulation[1] = 0;7044pBlock->m_modulation[2] = 0;7045pBlock->m_modulation[3] = 0;7046return;7047}70487049// Mod 37050uint32_t lr3 = (r * 15 + 128) / 255, lg3 = (g * 15 + 128) / 255, lb3 = (b * 15 + 128) / 255;7051uint32_t la3 = g_pvrtc2_alpha_match33_3[constant_alpha_val].m_l;70527053uint32_t cr3 = (lr3 << 1) | (lr3 >> 3);7054uint32_t cg3 = (lg3 << 1) | (lg3 >> 3);7055uint32_t cb3 = (lb3 << 1) | (lb3 >> 3);7056uint32_t ca3 = (la3 << 1) | 1;70577058cr3 = (cr3 << 3) | (cr3 >> 2);7059cg3 = (cg3 << 3) | (cg3 >> 2);7060cb3 = (cb3 << 3) | (cb3 >> 2);7061ca3 = (ca3 << 4) | ca3;70627063uint32_t err3 = sq(cr3 - r) + sq(cg3 - g) + sq(cb3 - b) + sq(ca3 - constant_alpha_val) * 2;70647065// Mod 17066uint32_t lr1 = g_pvrtc2_trans_match44[r].m_l, lg1 = g_pvrtc2_trans_match44[g].m_l, lb1 = g_pvrtc2_trans_match34[b].m_l;7067uint32_t hr1 = g_pvrtc2_trans_match44[r].m_h, hg1 = g_pvrtc2_trans_match44[g].m_h, hb1 = g_pvrtc2_trans_match34[b].m_h;7068uint32_t la1 = g_pvrtc2_alpha_match33[constant_alpha_val].m_l, ha1 = g_pvrtc2_alpha_match33[constant_alpha_val].m_h;70697070uint32_t clr1 = (lr1 << 1) | (lr1 >> 3);7071uint32_t clg1 = (lg1 << 1) | (lg1 >> 3);7072uint32_t clb1 = (lb1 << 2) | (lb1 >> 1);7073uint32_t cla1 = (la1 << 1);70747075clr1 = (clr1 << 3) | (clr1 >> 2);7076clg1 = (clg1 << 3) | (clg1 >> 2);7077clb1 = (clb1 << 3) | (clb1 >> 2);7078cla1 = (cla1 << 4) | cla1;70797080uint32_t chr1 = (hr1 << 1) | (hr1 >> 3);7081uint32_t chg1 = (hg1 << 1) | (hg1 >> 3);7082uint32_t chb1 = (hb1 << 1) | (hb1 >> 3);7083uint32_t cha1 = (ha1 << 1) | 1;70847085chr1 = (chr1 << 3) | (chr1 >> 2);7086chg1 = (chg1 << 3) | (chg1 >> 2);7087chb1 = (chb1 << 3) | (chb1 >> 2);7088cha1 = (cha1 << 4) | cha1;70897090uint32_t r1 = (clr1 * 5 + chr1 * 3) / 8;7091uint32_t g1 = (clg1 * 5 + chg1 * 3) / 8;7092uint32_t b1 = (clb1 * 5 + chb1 * 3) / 8;7093uint32_t a1 = (cla1 * 5 + cha1 * 3) / 8;70947095uint32_t err1 = sq(r1 - r) + sq(g1 - g) + sq(b1 - b) + sq(a1 - constant_alpha_val) * 2;70967097if ((err1 < err0) && (err1 < err3))7098{7099pBlock->set_trans_low_color(lr1, lg1, lb1, la1);7100pBlock->set_trans_high_color(hr1, hg1, hb1, ha1);71017102pBlock->m_modulation[0] = 0x55;7103pBlock->m_modulation[1] = 0x55;7104pBlock->m_modulation[2] = 0x55;7105pBlock->m_modulation[3] = 0x55;7106}7107else if (err0 < err3)7108{7109pBlock->set_trans_low_color(lr0, lg0, lb0, la0);7110pBlock->set_trans_high_color(0, 0, 0, 0);71117112pBlock->m_modulation[0] = 0;7113pBlock->m_modulation[1] = 0;7114pBlock->m_modulation[2] = 0;7115pBlock->m_modulation[3] = 0;7116}7117else7118{7119pBlock->set_trans_low_color(0, 0, 0, 0);7120pBlock->set_trans_high_color(lr3, lg3, lb3, la3);71217122pBlock->m_modulation[0] = 0xFF;7123pBlock->m_modulation[1] = 0xFF;7124pBlock->m_modulation[2] = 0xFF;7125pBlock->m_modulation[3] = 0xFF;7126}71277128return;7129}71307131// It's a complex block with non-solid color and/or alpha pixels.7132vec4F minColor, maxColor;71337134if (solid_color_block)7135{7136// It's a solid color block.7137uint32_t low_a = block_cols[alpha_selectors.m_lo_selector].a;7138uint32_t high_a = block_cols[alpha_selectors.m_hi_selector].a;71397140const float S = 1.0f / 255.0f;7141vec4F_set(&minColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, low_a * S);7142vec4F_set(&maxColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, high_a * S);7143}7144else if (constant_alpha_val >= 0)7145{7146// It's a solid alpha block.7147const float S = 1.0f / 255.0f;7148vec4F_set(&minColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, constant_alpha_val * S);7149vec4F_set(&maxColor, block_cols[high_selector].r * S, block_cols[high_selector].g * S, block_cols[high_selector].b * S, constant_alpha_val * S);7150}7151// See if any of the block colors got clamped - if so the principle axis got distorted (it's no longer just the ETC1S luma axis).7152// To keep quality up we need to use full 4D PCA in this case.7153else if ((block_cols[low_selector].c[0] == 0) || (block_cols[high_selector].c[0] == 255) ||7154(block_cols[low_selector].c[1] == 0) || (block_cols[high_selector].c[1] == 255) ||7155(block_cols[low_selector].c[2] == 0) || (block_cols[high_selector].c[2] == 255) ||7156(block_cols[alpha_selectors.m_lo_selector].c[3] == 0) || (block_cols[alpha_selectors.m_hi_selector].c[3] == 255))7157{7158// Find principle component of RGBA colors treated as 4D vectors.7159color32 pixels[16];71607161uint32_t sum_r = 0, sum_g = 0, sum_b = 0, sum_a = 0;7162for (uint32_t i = 0; i < 16; i++)7163{7164color32 rgb(block_cols[pSelector->get_selector(i & 3, i >> 2)]);7165uint32_t a = block_cols[alpha_selectors.get_selector(i & 3, i >> 2)].a;71667167pixels[i].set(rgb.r, rgb.g, rgb.b, a);71687169sum_r += rgb.r;7170sum_g += rgb.g;7171sum_b += rgb.b;7172sum_a += a;7173}71747175vec4F meanColor;7176vec4F_set(&meanColor, (float)sum_r, (float)sum_g, (float)sum_b, (float)sum_a);7177vec4F meanColorScaled = vec4F_mul(&meanColor, 1.0f / 16.0f);71787179meanColor = vec4F_mul(&meanColor, 1.0f / (float)(16.0f * 255.0f));7180vec4F_saturate_in_place(&meanColor);71817182vec4F axis;7183vec4F_set_scalar(&axis, 0.0f);7184// Why this incremental method? Because it's stable and predictable. Covar+power method can require a lot of iterations to converge in 4D.7185for (uint32_t i = 0; i < 16; i++)7186{7187vec4F color = vec4F_from_color(&pixels[i]);7188color = vec4F_sub(&color, &meanColorScaled);7189vec4F a = vec4F_mul(&color, color.c[0]);7190vec4F b = vec4F_mul(&color, color.c[1]);7191vec4F c = vec4F_mul(&color, color.c[2]);7192vec4F d = vec4F_mul(&color, color.c[3]);7193vec4F n = i ? axis : color;7194vec4F_normalize_in_place(&n);7195axis.c[0] += vec4F_dot(&a, &n);7196axis.c[1] += vec4F_dot(&b, &n);7197axis.c[2] += vec4F_dot(&c, &n);7198axis.c[3] += vec4F_dot(&d, &n);7199}72007201vec4F_normalize_in_place(&axis);72027203if (vec4F_dot(&axis, &axis) < .5f)7204vec4F_set_scalar(&axis, .5f);72057206float l = 1e+9f, h = -1e+9f;72077208for (uint32_t i = 0; i < 16; i++)7209{7210vec4F color = vec4F_from_color(&pixels[i]);72117212vec4F q = vec4F_sub(&color, &meanColorScaled);7213float d = vec4F_dot(&q, &axis);72147215l = basisu::minimum(l, d);7216h = basisu::maximum(h, d);7217}72187219l *= (1.0f / 255.0f);7220h *= (1.0f / 255.0f);72217222vec4F b0 = vec4F_mul(&axis, l);7223vec4F b1 = vec4F_mul(&axis, h);7224vec4F c0 = vec4F_add(&meanColor, &b0);7225vec4F c1 = vec4F_add(&meanColor, &b1);7226minColor = vec4F_saturate(&c0);7227maxColor = vec4F_saturate(&c1);7228if (minColor.c[3] > maxColor.c[3])7229{7230// VS 2019 release Code Generator issue7231//std::swap(minColor, maxColor);72327233float a = minColor.c[0], b = minColor.c[1], c = minColor.c[2], d = minColor.c[3];7234minColor.c[0] = maxColor.c[0]; minColor.c[1] = maxColor.c[1]; minColor.c[2] = maxColor.c[2]; minColor.c[3] = maxColor.c[3];7235minColor.c[0] = maxColor.c[0]; minColor.c[1] = maxColor.c[1]; minColor.c[2] = maxColor.c[2]; minColor.c[3] = maxColor.c[3];7236maxColor.c[0] = a; maxColor.c[1] = b; maxColor.c[2] = c; maxColor.c[3] = d;7237}7238}7239else7240{7241// We know the RGB axis is luma, because it's an ETC1S block and none of the block colors got clamped. So we only need to use 2D PCA.7242// We project each LA vector onto two 2D lines with axes (1,1) and (1,-1) and find the largest projection to determine if axis A is flipped relative to L.7243uint32_t block_cols_l[4], block_cols_a[4];7244for (uint32_t i = 0; i < 4; i++)7245{7246block_cols_l[i] = block_cols[i].r + block_cols[i].g + block_cols[i].b;7247block_cols_a[i] = block_cols[i].a * 3;7248}72497250int p0_min = INT_MAX, p0_max = INT_MIN;7251int p1_min = INT_MAX, p1_max = INT_MIN;7252for (uint32_t y = 0; y < 4; y++)7253{7254const uint32_t cs = pSelector->m_selectors[y];7255const uint32_t as = alpha_selectors.m_selectors[y];72567257{7258const int l = block_cols_l[cs & 3];7259const int a = block_cols_a[as & 3];7260const int p0 = l + a; p0_min = basisu::minimum(p0_min, p0); p0_max = basisu::maximum(p0_max, p0);7261const int p1 = l - a; p1_min = basisu::minimum(p1_min, p1); p1_max = basisu::maximum(p1_max, p1);7262}7263{7264const int l = block_cols_l[(cs >> 2) & 3];7265const int a = block_cols_a[(as >> 2) & 3];7266const int p0 = l + a; p0_min = basisu::minimum(p0_min, p0); p0_max = basisu::maximum(p0_max, p0);7267const int p1 = l - a; p1_min = basisu::minimum(p1_min, p1); p1_max = basisu::maximum(p1_max, p1);7268}7269{7270const int l = block_cols_l[(cs >> 4) & 3];7271const int a = block_cols_a[(as >> 4) & 3];7272const int p0 = l + a; p0_min = basisu::minimum(p0_min, p0); p0_max = basisu::maximum(p0_max, p0);7273const int p1 = l - a; p1_min = basisu::minimum(p1_min, p1); p1_max = basisu::maximum(p1_max, p1);7274}7275{7276const int l = block_cols_l[cs >> 6];7277const int a = block_cols_a[as >> 6];7278const int p0 = l + a; p0_min = basisu::minimum(p0_min, p0); p0_max = basisu::maximum(p0_max, p0);7279const int p1 = l - a; p1_min = basisu::minimum(p1_min, p1); p1_max = basisu::maximum(p1_max, p1);7280}7281}72827283int dist0 = p0_max - p0_min;7284int dist1 = p1_max - p1_min;72857286const float S = 1.0f / 255.0f;72877288vec4F_set(&minColor, block_cols[low_selector].r * S, block_cols[low_selector].g * S, block_cols[low_selector].b * S, block_cols[alpha_selectors.m_lo_selector].a * S);7289vec4F_set(&maxColor, block_cols[high_selector].r * S, block_cols[high_selector].g * S, block_cols[high_selector].b * S, block_cols[alpha_selectors.m_hi_selector].a * S);72907291// See if the A component of the principle axis is flipped relative to L. If so, we need to flip either RGB or A bounds.7292if (dist1 > dist0)7293{7294std::swap(minColor.c[0], maxColor.c[0]);7295std::swap(minColor.c[1], maxColor.c[1]);7296std::swap(minColor.c[2], maxColor.c[2]);7297}7298}72997300// 4433 44437301color32 trialMinColor, trialMaxColor;73027303trialMinColor.set_clamped((int)(minColor.c[0] * 15.0f + .5f), (int)(minColor.c[1] * 15.0f + .5f), (int)(minColor.c[2] * 7.0f + .5f), (int)(minColor.c[3] * 7.0f + .5f));7304trialMaxColor.set_clamped((int)(maxColor.c[0] * 15.0f + .5f), (int)(maxColor.c[1] * 15.0f + .5f), (int)(maxColor.c[2] * 15.0f + .5f), (int)(maxColor.c[3] * 7.0f + .5f));73057306pBlock->set_trans_low_color(trialMinColor.r, trialMinColor.g, trialMinColor.b, trialMinColor.a);7307pBlock->set_trans_high_color(trialMaxColor.r, trialMaxColor.g, trialMaxColor.b, trialMaxColor.a);73087309color32 color_a((trialMinColor.r << 1) | (trialMinColor.r >> 3), (trialMinColor.g << 1) | (trialMinColor.g >> 3), (trialMinColor.b << 2) | (trialMinColor.b >> 1), trialMinColor.a << 1);7310color32 color_b((trialMaxColor.r << 1) | (trialMaxColor.r >> 3), (trialMaxColor.g << 1) | (trialMaxColor.g >> 3), (trialMaxColor.b << 1) | (trialMaxColor.b >> 3), (trialMaxColor.a << 1) | 1);73117312color32 color0(convert_rgba_5554_to_8888(color_a));7313color32 color3(convert_rgba_5554_to_8888(color_b));73147315const int lr = color0.r;7316const int lg = color0.g;7317const int lb = color0.b;7318const int la = color0.a;73197320const int axis_r = color3.r - lr;7321const int axis_g = color3.g - lg;7322const int axis_b = color3.b - lb;7323const int axis_a = color3.a - la;7324const int len_a = (axis_r * axis_r) + (axis_g * axis_g) + (axis_b * axis_b) + (axis_a * axis_a);73257326const int thresh01 = (len_a * 3) / 16;7327const int thresh12 = len_a >> 1;7328const int thresh23 = (len_a * 13) / 16;73297330if ((axis_r | axis_g | axis_b) == 0)7331{7332int ca_sel[4];73337334for (uint32_t i = 0; i < 4; i++)7335{7336int ca = (block_cols[i].a - la) * axis_a;7337ca_sel[i] = (ca >= thresh23) + (ca >= thresh12) + (ca >= thresh01);7338}73397340for (uint32_t y = 0; y < 4; y++)7341{7342const uint32_t a_sels = alpha_selectors.m_selectors[y];73437344uint32_t sel = ca_sel[a_sels & 3] | (ca_sel[(a_sels >> 2) & 3] << 2) | (ca_sel[(a_sels >> 4) & 3] << 4) | (ca_sel[a_sels >> 6] << 6);73457346pBlock->m_modulation[y] = (uint8_t)sel;7347}7348}7349else7350{7351int cy[4], ca[4];73527353for (uint32_t i = 0; i < 4; i++)7354{7355cy[i] = (block_cols[i].r - lr) * axis_r + (block_cols[i].g - lg) * axis_g + (block_cols[i].b - lb) * axis_b;7356ca[i] = (block_cols[i].a - la) * axis_a;7357}73587359for (uint32_t y = 0; y < 4; y++)7360{7361const uint32_t c_sels = pSelector->m_selectors[y];7362const uint32_t a_sels = alpha_selectors.m_selectors[y];73637364const int d0 = cy[c_sels & 3] + ca[a_sels & 3];7365const int d1 = cy[(c_sels >> 2) & 3] + ca[(a_sels >> 2) & 3];7366const int d2 = cy[(c_sels >> 4) & 3] + ca[(a_sels >> 4) & 3];7367const int d3 = cy[c_sels >> 6] + ca[a_sels >> 6];73687369uint32_t sel = ((d0 >= thresh23) + (d0 >= thresh12) + (d0 >= thresh01)) |7370(((d1 >= thresh23) + (d1 >= thresh12) + (d1 >= thresh01)) << 2) |7371(((d2 >= thresh23) + (d2 >= thresh12) + (d2 >= thresh01)) << 4) |7372(((d3 >= thresh23) + (d3 >= thresh12) + (d3 >= thresh01)) << 6);73737374pBlock->m_modulation[y] = (uint8_t)sel;7375}7376}7377}73787379static void transcoder_init_pvrtc2()7380{7381for (uint32_t v = 0; v < 256; v++)7382{7383int best_l = 0, best_h = 0, lowest_err = INT_MAX;73847385for (uint32_t l = 0; l < 8; l++)7386{7387uint32_t le = (l << 1);7388le = (le << 4) | le;73897390for (uint32_t h = 0; h < 8; h++)7391{7392uint32_t he = (h << 1) | 1;7393he = (he << 4) | he;73947395uint32_t m = (le * 5 + he * 3) / 8;73967397int err = (int)labs((int)v - (int)m);7398if (err < lowest_err)7399{7400lowest_err = err;7401best_l = l;7402best_h = h;7403}7404}7405}74067407g_pvrtc2_alpha_match33[v].m_l = (uint8_t)best_l;7408g_pvrtc2_alpha_match33[v].m_h = (uint8_t)best_h;7409}74107411for (uint32_t v = 0; v < 256; v++)7412{7413int best_l = 0, best_h = 0, lowest_err = INT_MAX;74147415for (uint32_t l = 0; l < 8; l++)7416{7417uint32_t le = (l << 1);7418le = (le << 4) | le;74197420int err = (int)labs((int)v - (int)le);7421if (err < lowest_err)7422{7423lowest_err = err;7424best_l = l;7425best_h = l;7426}7427}74287429g_pvrtc2_alpha_match33_0[v].m_l = (uint8_t)best_l;7430g_pvrtc2_alpha_match33_0[v].m_h = (uint8_t)best_h;7431}74327433for (uint32_t v = 0; v < 256; v++)7434{7435int best_l = 0, best_h = 0, lowest_err = INT_MAX;74367437for (uint32_t h = 0; h < 8; h++)7438{7439uint32_t he = (h << 1) | 1;7440he = (he << 4) | he;74417442int err = (int)labs((int)v - (int)he);7443if (err < lowest_err)7444{7445lowest_err = err;7446best_l = h;7447best_h = h;7448}7449}74507451g_pvrtc2_alpha_match33_3[v].m_l = (uint8_t)best_l;7452g_pvrtc2_alpha_match33_3[v].m_h = (uint8_t)best_h;7453}74547455for (uint32_t v = 0; v < 256; v++)7456{7457int best_l = 0, best_h = 0, lowest_err = INT_MAX;74587459for (uint32_t l = 0; l < 8; l++)7460{7461uint32_t le = (l << 2) | (l >> 1);7462le = (le << 3) | (le >> 2);74637464for (uint32_t h = 0; h < 16; h++)7465{7466uint32_t he = (h << 1) | (h >> 3);7467he = (he << 3) | (he >> 2);74687469uint32_t m = (le * 5 + he * 3) / 8;74707471int err = (int)labs((int)v - (int)m);7472if (err < lowest_err)7473{7474lowest_err = err;7475best_l = l;7476best_h = h;7477}7478}7479}74807481g_pvrtc2_trans_match34[v].m_l = (uint8_t)best_l;7482g_pvrtc2_trans_match34[v].m_h = (uint8_t)best_h;7483}74847485for (uint32_t v = 0; v < 256; v++)7486{7487int best_l = 0, best_h = 0, lowest_err = INT_MAX;74887489for (uint32_t l = 0; l < 16; l++)7490{7491uint32_t le = (l << 1) | (l >> 3);7492le = (le << 3) | (le >> 2);74937494for (uint32_t h = 0; h < 16; h++)7495{7496uint32_t he = (h << 1) | (h >> 3);7497he = (he << 3) | (he >> 2);74987499uint32_t m = (le * 5 + he * 3) / 8;75007501int err = (int)labs((int)v - (int)m);7502if (err < lowest_err)7503{7504lowest_err = err;7505best_l = l;7506best_h = h;7507}7508}7509}75107511g_pvrtc2_trans_match44[v].m_l = (uint8_t)best_l;7512g_pvrtc2_trans_match44[v].m_h = (uint8_t)best_h;7513}7514}7515#endif // BASISD_SUPPORT_PVRTC275167517basisu_lowlevel_etc1s_transcoder::basisu_lowlevel_etc1s_transcoder() :7518m_pGlobal_codebook(nullptr),7519m_selector_history_buf_size(0)7520{7521}75227523bool basisu_lowlevel_etc1s_transcoder::decode_palettes(7524uint32_t num_endpoints, const uint8_t* pEndpoints_data, uint32_t endpoints_data_size,7525uint32_t num_selectors, const uint8_t* pSelectors_data, uint32_t selectors_data_size)7526{7527if (m_pGlobal_codebook)7528{7529BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 11\n");7530return false;7531}7532bitwise_decoder sym_codec;75337534huffman_decoding_table color5_delta_model0, color5_delta_model1, color5_delta_model2, inten_delta_model;75357536if (!sym_codec.init(pEndpoints_data, endpoints_data_size))7537{7538BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 0\n");7539return false;7540}75417542if (!sym_codec.read_huffman_table(color5_delta_model0))7543{7544BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 1\n");7545return false;7546}75477548if (!sym_codec.read_huffman_table(color5_delta_model1))7549{7550BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 1a\n");7551return false;7552}75537554if (!sym_codec.read_huffman_table(color5_delta_model2))7555{7556BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 2a\n");7557return false;7558}75597560if (!sym_codec.read_huffman_table(inten_delta_model))7561{7562BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 2b\n");7563return false;7564}75657566if (!color5_delta_model0.is_valid() || !color5_delta_model1.is_valid() || !color5_delta_model2.is_valid() || !inten_delta_model.is_valid())7567{7568BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 2b\n");7569return false;7570}75717572const bool endpoints_are_grayscale = sym_codec.get_bits(1) != 0;75737574m_local_endpoints.resize(num_endpoints);75757576color32 prev_color5(16, 16, 16, 0);7577uint32_t prev_inten = 0;75787579for (uint32_t i = 0; i < num_endpoints; i++)7580{7581uint32_t inten_delta = sym_codec.decode_huffman(inten_delta_model);7582m_local_endpoints[i].m_inten5 = static_cast<uint8_t>((inten_delta + prev_inten) & 7);7583prev_inten = m_local_endpoints[i].m_inten5;75847585for (uint32_t c = 0; c < (endpoints_are_grayscale ? 1U : 3U); c++)7586{7587int delta;7588if (prev_color5[c] <= basist::COLOR5_PAL0_PREV_HI)7589delta = sym_codec.decode_huffman(color5_delta_model0);7590else if (prev_color5[c] <= basist::COLOR5_PAL1_PREV_HI)7591delta = sym_codec.decode_huffman(color5_delta_model1);7592else7593delta = sym_codec.decode_huffman(color5_delta_model2);75947595int v = (prev_color5[c] + delta) & 31;75967597m_local_endpoints[i].m_color5[c] = static_cast<uint8_t>(v);75987599prev_color5[c] = static_cast<uint8_t>(v);7600}76017602if (endpoints_are_grayscale)7603{7604m_local_endpoints[i].m_color5[1] = m_local_endpoints[i].m_color5[0];7605m_local_endpoints[i].m_color5[2] = m_local_endpoints[i].m_color5[0];7606}7607}76087609sym_codec.stop();76107611m_local_selectors.resize(num_selectors);76127613if (!sym_codec.init(pSelectors_data, selectors_data_size))7614{7615BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 5\n");7616return false;7617}76187619basist::huffman_decoding_table delta_selector_pal_model;76207621const bool used_global_selector_cb = (sym_codec.get_bits(1) == 1);76227623if (used_global_selector_cb)7624{7625BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: global selector codebooks are unsupported\n");7626return false;7627}7628else7629{7630const bool used_hybrid_selector_cb = (sym_codec.get_bits(1) == 1);76317632if (used_hybrid_selector_cb)7633{7634BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: hybrid global selector codebooks are unsupported\n");7635return false;7636}76377638const bool used_raw_encoding = (sym_codec.get_bits(1) == 1);76397640if (used_raw_encoding)7641{7642for (uint32_t i = 0; i < num_selectors; i++)7643{7644for (uint32_t j = 0; j < 4; j++)7645{7646uint32_t cur_byte = sym_codec.get_bits(8);76477648for (uint32_t k = 0; k < 4; k++)7649m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);7650}76517652m_local_selectors[i].init_flags();7653}7654}7655else7656{7657if (!sym_codec.read_huffman_table(delta_selector_pal_model))7658{7659BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 10\n");7660return false;7661}76627663if ((num_selectors > 1) && (!delta_selector_pal_model.is_valid()))7664{7665BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_palettes: fail 10a\n");7666return false;7667}76687669uint8_t prev_bytes[4] = { 0, 0, 0, 0 };76707671for (uint32_t i = 0; i < num_selectors; i++)7672{7673if (!i)7674{7675for (uint32_t j = 0; j < 4; j++)7676{7677uint32_t cur_byte = sym_codec.get_bits(8);7678prev_bytes[j] = static_cast<uint8_t>(cur_byte);76797680for (uint32_t k = 0; k < 4; k++)7681m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);7682}7683m_local_selectors[i].init_flags();7684continue;7685}76867687for (uint32_t j = 0; j < 4; j++)7688{7689int delta_byte = sym_codec.decode_huffman(delta_selector_pal_model);76907691uint32_t cur_byte = delta_byte ^ prev_bytes[j];7692prev_bytes[j] = static_cast<uint8_t>(cur_byte);76937694for (uint32_t k = 0; k < 4; k++)7695m_local_selectors[i].set_selector(k, j, (cur_byte >> (k * 2)) & 3);7696}7697m_local_selectors[i].init_flags();7698}7699}7700}77017702sym_codec.stop();77037704return true;7705}77067707bool basisu_lowlevel_etc1s_transcoder::decode_tables(const uint8_t* pTable_data, uint32_t table_data_size)7708{7709basist::bitwise_decoder sym_codec;7710if (!sym_codec.init(pTable_data, table_data_size))7711{7712BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 0\n");7713return false;7714}77157716if (!sym_codec.read_huffman_table(m_endpoint_pred_model))7717{7718BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 1\n");7719return false;7720}77217722if (m_endpoint_pred_model.get_code_sizes().size() == 0)7723{7724BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 1a\n");7725return false;7726}77277728if (!sym_codec.read_huffman_table(m_delta_endpoint_model))7729{7730BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 2\n");7731return false;7732}77337734if (m_delta_endpoint_model.get_code_sizes().size() == 0)7735{7736BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 2a\n");7737return false;7738}77397740if (!sym_codec.read_huffman_table(m_selector_model))7741{7742BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 3\n");7743return false;7744}77457746if (m_selector_model.get_code_sizes().size() == 0)7747{7748BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 3a\n");7749return false;7750}77517752if (!sym_codec.read_huffman_table(m_selector_history_buf_rle_model))7753{7754BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 4\n");7755return false;7756}77577758if (m_selector_history_buf_rle_model.get_code_sizes().size() == 0)7759{7760BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 4a\n");7761return false;7762}77637764m_selector_history_buf_size = sym_codec.get_bits(13);7765// Check for bogus values.7766if (!m_selector_history_buf_size)7767{7768BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::decode_tables: fail 5\n");7769return false;7770}77717772sym_codec.stop();77737774return true;7775}77767777bool basisu_lowlevel_etc1s_transcoder::transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,7778uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const bool is_video, const bool is_alpha_slice, const uint32_t level_index, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels,7779basisu_transcoder_state* pState, bool transcode_alpha, void *pAlpha_blocks, uint32_t output_rows_in_pixels)7780{7781// 'pDst_blocks' unused when disabling *all* hardware transcode options7782// (and 'bc1_allow_threecolor_blocks' when disabling DXT)7783BASISU_NOTE_UNUSED(pDst_blocks);7784BASISU_NOTE_UNUSED(bc1_allow_threecolor_blocks);7785BASISU_NOTE_UNUSED(transcode_alpha);7786BASISU_NOTE_UNUSED(pAlpha_blocks);77877788assert(g_transcoder_initialized);7789if (!g_transcoder_initialized)7790{7791BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: Transcoder not globally initialized.\n");7792return false;7793}77947795if (!pState)7796pState = &m_def_state;77977798const uint32_t total_blocks = num_blocks_x * num_blocks_y;77997800if (!output_row_pitch_in_blocks_or_pixels)7801{7802if (basis_block_format_is_uncompressed(fmt))7803output_row_pitch_in_blocks_or_pixels = orig_width;7804else7805{7806if (fmt == block_format::cFXT1_RGB)7807output_row_pitch_in_blocks_or_pixels = (orig_width + 7) / 8;7808else7809output_row_pitch_in_blocks_or_pixels = num_blocks_x;7810}7811}78127813if (basis_block_format_is_uncompressed(fmt))7814{7815if (!output_rows_in_pixels)7816output_rows_in_pixels = orig_height;7817}78187819basisu::vector<uint32_t>* pPrev_frame_indices = nullptr;7820if (is_video)7821{7822// TODO: Add check to make sure the caller hasn't tried skipping past p-frames7823//const bool alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0;7824//const uint32_t level_index = slice_desc.m_level_index;78257826if (level_index >= basisu_transcoder_state::cMaxPrevFrameLevels)7827{7828BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: unsupported level_index\n");7829return false;7830}78317832pPrev_frame_indices = &pState->m_prev_frame_indices[is_alpha_slice][level_index];7833if (pPrev_frame_indices->size() < total_blocks)7834pPrev_frame_indices->resize(total_blocks);7835}78367837basist::bitwise_decoder sym_codec;78387839if (!sym_codec.init(pImage_data, image_data_size))7840{7841BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: sym_codec.init failed\n");7842return false;7843}78447845approx_move_to_front selector_history_buf(m_selector_history_buf_size);78467847uint32_t cur_selector_rle_count = 0;78487849decoder_etc_block block;7850memset(&block, 0, sizeof(block));78517852//block.set_flip_bit(true);7853// Setting the flip bit to false to be compatible with the Khronos KDFS.7854block.set_flip_bit(false);78557856block.set_diff_bit(true);78577858void* pPVRTC_work_mem = nullptr;7859uint32_t* pPVRTC_endpoints = nullptr;7860if ((fmt == block_format::cPVRTC1_4_RGB) || (fmt == block_format::cPVRTC1_4_RGBA))7861{7862pPVRTC_work_mem = malloc(num_blocks_x * num_blocks_y * (sizeof(decoder_etc_block) + sizeof(uint32_t)));7863if (!pPVRTC_work_mem)7864{7865BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: malloc failed\n");7866return false;7867}7868pPVRTC_endpoints = (uint32_t*) & ((decoder_etc_block*)pPVRTC_work_mem)[num_blocks_x * num_blocks_y];7869}78707871if (pState->m_block_endpoint_preds[0].size() < num_blocks_x)7872{7873pState->m_block_endpoint_preds[0].resize(num_blocks_x);7874pState->m_block_endpoint_preds[1].resize(num_blocks_x);7875}78767877uint32_t cur_pred_bits = 0;7878int prev_endpoint_pred_sym = 0;7879int endpoint_pred_repeat_count = 0;7880uint32_t prev_endpoint_index = 0;7881const endpoint_vec& endpoints = m_pGlobal_codebook ? m_pGlobal_codebook->m_local_endpoints : m_local_endpoints;7882const selector_vec& selectors = m_pGlobal_codebook ? m_pGlobal_codebook->m_local_selectors : m_local_selectors;7883if (!endpoints.size() || !selectors.size())7884{7885BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: global codebooks must be unpacked first\n");7886return false;7887}78887889const uint32_t SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX = (uint32_t)selectors.size();7890const uint32_t SELECTOR_HISTORY_BUF_RLE_SYMBOL_INDEX = m_selector_history_buf_size + SELECTOR_HISTORY_BUF_FIRST_SYMBOL_INDEX;78917892for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)7893{7894const uint32_t cur_block_endpoint_pred_array = block_y & 1;78957896for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)7897{7898// Decode endpoint index predictor symbols7899if ((block_x & 1) == 0)7900{7901if ((block_y & 1) == 0)7902{7903if (endpoint_pred_repeat_count)7904{7905endpoint_pred_repeat_count--;7906cur_pred_bits = prev_endpoint_pred_sym;7907}7908else7909{7910cur_pred_bits = sym_codec.decode_huffman(m_endpoint_pred_model);7911if (cur_pred_bits == ENDPOINT_PRED_REPEAT_LAST_SYMBOL)7912{7913endpoint_pred_repeat_count = sym_codec.decode_vlc(ENDPOINT_PRED_COUNT_VLC_BITS) + ENDPOINT_PRED_MIN_REPEAT_COUNT - 1;79147915cur_pred_bits = prev_endpoint_pred_sym;7916}7917else7918{7919prev_endpoint_pred_sym = cur_pred_bits;7920}7921}79227923pState->m_block_endpoint_preds[cur_block_endpoint_pred_array ^ 1][block_x].m_pred_bits = (uint8_t)(cur_pred_bits >> 4);7924}7925else7926{7927cur_pred_bits = pState->m_block_endpoint_preds[cur_block_endpoint_pred_array][block_x].m_pred_bits;7928}7929}79307931// Decode endpoint index7932uint32_t endpoint_index, selector_index = 0;79337934const uint32_t pred = cur_pred_bits & 3;7935cur_pred_bits >>= 2;79367937if (pred == 0)7938{7939// Left7940if (!block_x)7941{7942BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (0)\n");7943if (pPVRTC_work_mem)7944free(pPVRTC_work_mem);7945return false;7946}79477948endpoint_index = prev_endpoint_index;7949}7950else if (pred == 1)7951{7952// Upper7953if (!block_y)7954{7955BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (1)\n");7956if (pPVRTC_work_mem)7957free(pPVRTC_work_mem);7958return false;7959}79607961endpoint_index = pState->m_block_endpoint_preds[cur_block_endpoint_pred_array ^ 1][block_x].m_endpoint_index;7962}7963else if (pred == 2)7964{7965if (is_video)7966{7967assert(pred == CR_ENDPOINT_PRED_INDEX);7968endpoint_index = (*pPrev_frame_indices)[block_x + block_y * num_blocks_x];7969selector_index = endpoint_index >> 16;7970endpoint_index &= 0xFFFFU;7971}7972else7973{7974// Upper left7975if ((!block_x) || (!block_y))7976{7977BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (2)\n");7978if (pPVRTC_work_mem)7979free(pPVRTC_work_mem);7980return false;7981}79827983endpoint_index = pState->m_block_endpoint_preds[cur_block_endpoint_pred_array ^ 1][block_x - 1].m_endpoint_index;7984}7985}7986else7987{7988// Decode and apply delta7989const uint32_t delta_sym = sym_codec.decode_huffman(m_delta_endpoint_model);79907991endpoint_index = delta_sym + prev_endpoint_index;7992if (endpoint_index >= endpoints.size())7993endpoint_index -= (int)endpoints.size();7994}79957996pState->m_block_endpoint_preds[cur_block_endpoint_pred_array][block_x].m_endpoint_index = (uint16_t)endpoint_index;79977998prev_endpoint_index = endpoint_index;79998000// Decode selector index8001if ((!is_video) || (pred != CR_ENDPOINT_PRED_INDEX))8002{8003int selector_sym;8004if (cur_selector_rle_count > 0)8005{8006cur_selector_rle_count--;80078008selector_sym = (int)selectors.size();8009}8010else8011{8012selector_sym = sym_codec.decode_huffman(m_selector_model);80138014if (selector_sym == static_cast<int>(SELECTOR_HISTORY_BUF_RLE_SYMBOL_INDEX))8015{8016int run_sym = sym_codec.decode_huffman(m_selector_history_buf_rle_model);80178018if (run_sym == (SELECTOR_HISTORY_BUF_RLE_COUNT_TOTAL - 1))8019cur_selector_rle_count = sym_codec.decode_vlc(7) + SELECTOR_HISTORY_BUF_RLE_COUNT_THRESH;8020else8021cur_selector_rle_count = run_sym + SELECTOR_HISTORY_BUF_RLE_COUNT_THRESH;80228023if (cur_selector_rle_count > total_blocks)8024{8025// The file is corrupted or we've got a bug.8026BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (3)\n");8027if (pPVRTC_work_mem)8028free(pPVRTC_work_mem);8029return false;8030}80318032selector_sym = (int)selectors.size();80338034cur_selector_rle_count--;8035}8036}80378038if (selector_sym >= (int)selectors.size())8039{8040assert(m_selector_history_buf_size > 0);80418042int history_buf_index = selector_sym - (int)selectors.size();80438044if (history_buf_index >= (int)selector_history_buf.size())8045{8046// The file is corrupted or we've got a bug.8047BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (4)\n");8048if (pPVRTC_work_mem)8049free(pPVRTC_work_mem);8050return false;8051}80528053selector_index = selector_history_buf[history_buf_index];80548055if (history_buf_index != 0)8056selector_history_buf.use(history_buf_index);8057}8058else8059{8060selector_index = selector_sym;80618062if (m_selector_history_buf_size)8063selector_history_buf.add(selector_index);8064}8065}80668067if ((endpoint_index >= endpoints.size()) || (selector_index >= selectors.size()))8068{8069// The file is corrupted or we've got a bug.8070BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: invalid datastream (5)\n");8071if (pPVRTC_work_mem)8072free(pPVRTC_work_mem);8073return false;8074}80758076if (is_video)8077(*pPrev_frame_indices)[block_x + block_y * num_blocks_x] = endpoint_index | (selector_index << 16);80788079#if BASISD_ENABLE_DEBUG_FLAGS8080if ((g_debug_flags & cDebugFlagVisCRs) && ((fmt == block_format::cETC1) || (fmt == block_format::cBC1)))8081{8082if ((is_video) && (pred == 2))8083{8084decoder_etc_block* pDst_block = reinterpret_cast<decoder_etc_block*>(static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes);8085memset(pDst_block, 0xFF, 8);8086continue;8087}8088}8089#endif80908091const endpoint* pEndpoints = &endpoints[endpoint_index];8092const selector* pSelector = &selectors[selector_index];80938094switch (fmt)8095{8096case block_format::cETC1:8097{8098decoder_etc_block* pDst_block = reinterpret_cast<decoder_etc_block*>(static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes);80998100block.set_base5_color(decoder_etc_block::pack_color5(pEndpoints->m_color5, false));8101block.set_inten_table(0, pEndpoints->m_inten5);8102block.set_inten_table(1, pEndpoints->m_inten5);81038104pDst_block->m_uint32[0] = block.m_uint32[0];8105pDst_block->set_raw_selector_bits(pSelector->m_bytes[0], pSelector->m_bytes[1], pSelector->m_bytes[2], pSelector->m_bytes[3]);81068107break;8108}8109case block_format::cBC1:8110{8111#if BASISD_SUPPORT_DXT18112void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8113#if BASISD_ENABLE_DEBUG_FLAGS8114if (g_debug_flags & (cDebugFlagVisBC1Sels | cDebugFlagVisBC1Endpoints))8115convert_etc1s_to_dxt1_vis(static_cast<dxt1_block*>(pDst_block), pEndpoints, pSelector, bc1_allow_threecolor_blocks);8116else8117#endif8118convert_etc1s_to_dxt1(static_cast<dxt1_block*>(pDst_block), pEndpoints, pSelector, bc1_allow_threecolor_blocks);8119#else8120assert(0);8121#endif8122break;8123}8124case block_format::cBC4:8125{8126#if BASISD_SUPPORT_DXT5A8127void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8128convert_etc1s_to_dxt5a(static_cast<dxt5a_block*>(pDst_block), pEndpoints, pSelector);8129#else8130assert(0);8131#endif8132break;8133}8134case block_format::cPVRTC1_4_RGB:8135{8136#if BASISD_SUPPORT_PVRTC18137block.set_base5_color(decoder_etc_block::pack_color5(pEndpoints->m_color5, false));8138block.set_inten_table(0, pEndpoints->m_inten5);8139block.set_inten_table(1, pEndpoints->m_inten5);8140block.set_raw_selector_bits(pSelector->m_bytes[0], pSelector->m_bytes[1], pSelector->m_bytes[2], pSelector->m_bytes[3]);81418142((decoder_etc_block*)pPVRTC_work_mem)[block_x + block_y * num_blocks_x] = block;81438144const color32& base_color = pEndpoints->m_color5;8145const uint32_t inten_table = pEndpoints->m_inten5;81468147const uint32_t low_selector = pSelector->m_lo_selector;8148const uint32_t high_selector = pSelector->m_hi_selector;81498150// Get block's RGB bounding box8151color32 block_colors[2];8152decoder_etc_block::get_block_colors5_bounds(block_colors, base_color, inten_table, low_selector, high_selector);81538154assert(block_colors[0][0] <= block_colors[1][0]);8155assert(block_colors[0][1] <= block_colors[1][1]);8156assert(block_colors[0][2] <= block_colors[1][2]);81578158// Set PVRTC1 endpoints to floor/ceil of bounding box's coordinates.8159pvrtc4_block temp;8160temp.set_opaque_endpoint_floor(0, block_colors[0]);8161temp.set_opaque_endpoint_ceil(1, block_colors[1]);81628163pPVRTC_endpoints[block_x + block_y * num_blocks_x] = temp.m_endpoints;8164#else8165assert(0);8166#endif81678168break;8169}8170case block_format::cPVRTC1_4_RGBA:8171{8172#if BASISD_SUPPORT_PVRTC18173assert(pAlpha_blocks);81748175block.set_base5_color(decoder_etc_block::pack_color5(pEndpoints->m_color5, false));8176block.set_inten_table(0, pEndpoints->m_inten5);8177block.set_inten_table(1, pEndpoints->m_inten5);8178block.set_raw_selector_bits(pSelector->m_selectors[0], pSelector->m_selectors[1], pSelector->m_selectors[2], pSelector->m_selectors[3]);81798180((decoder_etc_block*)pPVRTC_work_mem)[block_x + block_y * num_blocks_x] = block;81818182// Get block's RGBA bounding box8183const color32& base_color = pEndpoints->m_color5;8184const uint32_t inten_table = pEndpoints->m_inten5;8185const uint32_t low_selector = pSelector->m_lo_selector;8186const uint32_t high_selector = pSelector->m_hi_selector;8187color32 block_colors[2];8188decoder_etc_block::get_block_colors5_bounds(block_colors, base_color, inten_table, low_selector, high_selector);81898190assert(block_colors[0][0] <= block_colors[1][0]);8191assert(block_colors[0][1] <= block_colors[1][1]);8192assert(block_colors[0][2] <= block_colors[1][2]);81938194const uint16_t* pAlpha_block = reinterpret_cast<uint16_t*>(static_cast<uint8_t*>(pAlpha_blocks) + (block_x + block_y * num_blocks_x) * sizeof(uint32_t));81958196const endpoint* pAlpha_endpoints = &endpoints[pAlpha_block[0]];8197const selector* pAlpha_selector = &selectors[pAlpha_block[1]];81988199const color32& alpha_base_color = pAlpha_endpoints->m_color5;8200const uint32_t alpha_inten_table = pAlpha_endpoints->m_inten5;8201const uint32_t alpha_low_selector = pAlpha_selector->m_lo_selector;8202const uint32_t alpha_high_selector = pAlpha_selector->m_hi_selector;8203uint32_t alpha_block_colors[2];8204decoder_etc_block::get_block_colors5_bounds_g(alpha_block_colors, alpha_base_color, alpha_inten_table, alpha_low_selector, alpha_high_selector);8205assert(alpha_block_colors[0] <= alpha_block_colors[1]);8206block_colors[0].a = (uint8_t)alpha_block_colors[0];8207block_colors[1].a = (uint8_t)alpha_block_colors[1];82088209// Set PVRTC1 endpoints to floor/ceil of bounding box's coordinates.8210pvrtc4_block temp;8211temp.set_endpoint_floor(0, block_colors[0]);8212temp.set_endpoint_ceil(1, block_colors[1]);82138214pPVRTC_endpoints[block_x + block_y * num_blocks_x] = temp.m_endpoints;8215#else8216assert(0);8217#endif82188219break;8220}8221case block_format::cBC7: // for more consistency with UASTC8222case block_format::cBC7_M5_COLOR:8223{8224#if BASISD_SUPPORT_BC7_MODE58225void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8226convert_etc1s_to_bc7_m5_color(pDst_block, pEndpoints, pSelector);8227#else8228assert(0);8229#endif8230break;8231}8232case block_format::cBC7_M5_ALPHA:8233{8234#if BASISD_SUPPORT_BC7_MODE58235void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8236convert_etc1s_to_bc7_m5_alpha(pDst_block, pEndpoints, pSelector);8237#else8238assert(0);8239#endif8240break;8241}8242case block_format::cETC2_EAC_A8:8243{8244#if BASISD_SUPPORT_ETC2_EAC_A88245void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8246convert_etc1s_to_etc2_eac_a8(static_cast<eac_block*>(pDst_block), pEndpoints, pSelector);8247#else8248assert(0);8249#endif8250break;8251}8252case block_format::cASTC_4x4:8253{8254#if BASISD_SUPPORT_ASTC8255void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8256convert_etc1s_to_astc_4x4(pDst_block, pEndpoints, pSelector, transcode_alpha, &endpoints[0], &selectors[0]);8257#else8258assert(0);8259#endif8260break;8261}8262case block_format::cATC_RGB:8263{8264#if BASISD_SUPPORT_ATC8265void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8266convert_etc1s_to_atc(pDst_block, pEndpoints, pSelector);8267#else8268assert(0);8269#endif8270break;8271}8272case block_format::cFXT1_RGB:8273{8274#if BASISD_SUPPORT_FXT18275const uint32_t fxt1_block_x = block_x >> 1;8276const uint32_t fxt1_block_y = block_y;8277const uint32_t fxt1_subblock = block_x & 1;82788279void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (fxt1_block_x + fxt1_block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;82808281convert_etc1s_to_fxt1(pDst_block, pEndpoints, pSelector, fxt1_subblock);8282#else8283assert(0);8284#endif8285break;8286}8287case block_format::cPVRTC2_4_RGB:8288{8289#if BASISD_SUPPORT_PVRTC28290void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8291convert_etc1s_to_pvrtc2_rgb(pDst_block, pEndpoints, pSelector);8292#endif8293break;8294}8295case block_format::cPVRTC2_4_RGBA:8296{8297#if BASISD_SUPPORT_PVRTC28298assert(transcode_alpha);82998300void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;83018302convert_etc1s_to_pvrtc2_rgba(pDst_block, pEndpoints, pSelector, &endpoints[0], &selectors[0]);8303#endif8304break;8305}8306case block_format::cIndices:8307{8308uint16_t* pDst_block = reinterpret_cast<uint16_t *>(static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes);8309pDst_block[0] = static_cast<uint16_t>(endpoint_index);8310pDst_block[1] = static_cast<uint16_t>(selector_index);8311break;8312}8313case block_format::cA32:8314{8315assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes);8316uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t);83178318const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);8319const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);83208321int colors[4];8322decoder_etc_block::get_block_colors5_g(colors, pEndpoints->m_color5, pEndpoints->m_inten5);83238324if (max_x == 4)8325{8326for (uint32_t y = 0; y < max_y; y++)8327{8328const uint32_t s = pSelector->m_selectors[y];83298330pDst_pixels[3] = static_cast<uint8_t>(colors[s & 3]);8331pDst_pixels[3+4] = static_cast<uint8_t>(colors[(s >> 2) & 3]);8332pDst_pixels[3+8] = static_cast<uint8_t>(colors[(s >> 4) & 3]);8333pDst_pixels[3+12] = static_cast<uint8_t>(colors[(s >> 6) & 3]);83348335pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint32_t);8336}8337}8338else8339{8340for (uint32_t y = 0; y < max_y; y++)8341{8342const uint32_t s = pSelector->m_selectors[y];83438344for (uint32_t x = 0; x < max_x; x++)8345pDst_pixels[3 + 4 * x] = static_cast<uint8_t>(colors[(s >> (x * 2)) & 3]);83468347pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint32_t);8348}8349}83508351break;8352}8353case block_format::cRGB32:8354{8355assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes);8356uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t);83578358const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);8359const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);83608361color32 colors[4];8362decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);83638364for (uint32_t y = 0; y < max_y; y++)8365{8366const uint32_t s = pSelector->m_selectors[y];83678368for (uint32_t x = 0; x < max_x; x++)8369{8370const color32& c = colors[(s >> (x * 2)) & 3];83718372pDst_pixels[0 + 4 * x] = c.r;8373pDst_pixels[1 + 4 * x] = c.g;8374pDst_pixels[2 + 4 * x] = c.b;8375}83768377pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint32_t);8378}83798380break;8381}8382case block_format::cRGBA32:8383{8384assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes);8385uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t);83868387const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);8388const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);83898390color32 colors[4];8391decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);83928393for (uint32_t y = 0; y < max_y; y++)8394{8395const uint32_t s = pSelector->m_selectors[y];83968397for (uint32_t x = 0; x < max_x; x++)8398{8399const color32& c = colors[(s >> (x * 2)) & 3];84008401pDst_pixels[0 + 4 * x] = c.r;8402pDst_pixels[1 + 4 * x] = c.g;8403pDst_pixels[2 + 4 * x] = c.b;8404pDst_pixels[3 + 4 * x] = 255;8405}84068407pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint32_t);8408}84098410break;8411}8412case block_format::cRGB565:8413case block_format::cBGR565:8414{8415assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);8416uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);84178418const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);8419const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);84208421color32 colors[4];8422decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);84238424uint16_t packed_colors[4];8425if (fmt == block_format::cRGB565)8426{8427for (uint32_t i = 0; i < 4; i++)8428{8429packed_colors[i] = static_cast<uint16_t>((mul_8(colors[i].r, 31) << 11) | (mul_8(colors[i].g, 63) << 5) | mul_8(colors[i].b, 31));8430if (BASISD_IS_BIG_ENDIAN)8431packed_colors[i] = byteswap_uint16(packed_colors[i]);8432}8433}8434else8435{8436for (uint32_t i = 0; i < 4; i++)8437{8438packed_colors[i] = static_cast<uint16_t>((mul_8(colors[i].b, 31) << 11) | (mul_8(colors[i].g, 63) << 5) | mul_8(colors[i].r, 31));8439if (BASISD_IS_BIG_ENDIAN)8440packed_colors[i] = byteswap_uint16(packed_colors[i]);8441}8442}84438444for (uint32_t y = 0; y < max_y; y++)8445{8446const uint32_t s = pSelector->m_selectors[y];84478448for (uint32_t x = 0; x < max_x; x++)8449reinterpret_cast<uint16_t *>(pDst_pixels)[x] = packed_colors[(s >> (x * 2)) & 3];84508451pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);8452}84538454break;8455}8456case block_format::cRGBA4444_COLOR:8457{8458assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);8459uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);84608461const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);8462const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);84638464color32 colors[4];8465decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);84668467uint16_t packed_colors[4];8468for (uint32_t i = 0; i < 4; i++)8469{8470packed_colors[i] = static_cast<uint16_t>((mul_8(colors[i].r, 15) << 12) | (mul_8(colors[i].g, 15) << 8) | (mul_8(colors[i].b, 15) << 4));8471}84728473for (uint32_t y = 0; y < max_y; y++)8474{8475const uint32_t s = pSelector->m_selectors[y];84768477for (uint32_t x = 0; x < max_x; x++)8478{8479uint16_t cur = reinterpret_cast<uint16_t*>(pDst_pixels)[x];8480if (BASISD_IS_BIG_ENDIAN)8481cur = byteswap_uint16(cur);84828483cur = (cur & 0xF) | packed_colors[(s >> (x * 2)) & 3];84848485if (BASISD_IS_BIG_ENDIAN)8486cur = byteswap_uint16(cur);84878488reinterpret_cast<uint16_t*>(pDst_pixels)[x] = cur;8489}84908491pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);8492}84938494break;8495}8496case block_format::cRGBA4444_COLOR_OPAQUE:8497{8498assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);8499uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);85008501const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);8502const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);85038504color32 colors[4];8505decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);85068507uint16_t packed_colors[4];8508for (uint32_t i = 0; i < 4; i++)8509{8510packed_colors[i] = static_cast<uint16_t>((mul_8(colors[i].r, 15) << 12) | (mul_8(colors[i].g, 15) << 8) | (mul_8(colors[i].b, 15) << 4) | 0xF);8511if (BASISD_IS_BIG_ENDIAN)8512packed_colors[i] = byteswap_uint16(packed_colors[i]);8513}85148515for (uint32_t y = 0; y < max_y; y++)8516{8517const uint32_t s = pSelector->m_selectors[y];85188519for (uint32_t x = 0; x < max_x; x++)8520reinterpret_cast<uint16_t*>(pDst_pixels)[x] = packed_colors[(s >> (x * 2)) & 3];85218522pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);8523}85248525break;8526}8527case block_format::cRGBA4444_ALPHA:8528{8529assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);8530uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);85318532const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);8533const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);85348535color32 colors[4];8536decoder_etc_block::get_block_colors5(colors, pEndpoints->m_color5, pEndpoints->m_inten5);85378538uint16_t packed_colors[4];8539for (uint32_t i = 0; i < 4; i++)8540{8541packed_colors[i] = mul_8(colors[i].g, 15);8542if (BASISD_IS_BIG_ENDIAN)8543packed_colors[i] = byteswap_uint16(packed_colors[i]);8544}85458546for (uint32_t y = 0; y < max_y; y++)8547{8548const uint32_t s = pSelector->m_selectors[y];85498550for (uint32_t x = 0; x < max_x; x++)8551{8552reinterpret_cast<uint16_t*>(pDst_pixels)[x] = packed_colors[(s >> (x * 2)) & 3];8553}85548555pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);8556}85578558break;8559}8560case block_format::cETC2_EAC_R11:8561{8562#if BASISD_SUPPORT_ETC2_EAC_RG118563void* pDst_block = static_cast<uint8_t*>(pDst_blocks) + (block_x + block_y * output_row_pitch_in_blocks_or_pixels) * output_block_or_pixel_stride_in_bytes;8564convert_etc1s_to_etc2_eac_r11(static_cast<eac_block*>(pDst_block), pEndpoints, pSelector);8565#else8566assert(0);8567#endif8568break;8569}8570default:8571{8572assert(0);8573break;8574}8575}85768577} // block_x85788579} // block-y85808581if (endpoint_pred_repeat_count != 0)8582{8583BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_slice: endpoint_pred_repeat_count != 0. The file is corrupted or this is a bug\n");8584return false;8585}85868587//assert(endpoint_pred_repeat_count == 0);85888589#if BASISD_SUPPORT_PVRTC18590// PVRTC post process - create per-pixel modulation values.8591if (fmt == block_format::cPVRTC1_4_RGB)8592fixup_pvrtc1_4_modulation_rgb((decoder_etc_block*)pPVRTC_work_mem, pPVRTC_endpoints, pDst_blocks, num_blocks_x, num_blocks_y);8593else if (fmt == block_format::cPVRTC1_4_RGBA)8594fixup_pvrtc1_4_modulation_rgba((decoder_etc_block*)pPVRTC_work_mem, pPVRTC_endpoints, pDst_blocks, num_blocks_x, num_blocks_y, pAlpha_blocks, &endpoints[0], &selectors[0]);8595#endif // BASISD_SUPPORT_PVRTC185968597if (pPVRTC_work_mem)8598free(pPVRTC_work_mem);85998600return true;8601}86028603bool basis_validate_output_buffer_size(transcoder_texture_format target_format,8604uint32_t output_blocks_buf_size_in_blocks_or_pixels,8605uint32_t orig_width, uint32_t orig_height,8606uint32_t output_row_pitch_in_blocks_or_pixels,8607uint32_t output_rows_in_pixels,8608uint32_t total_slice_blocks)8609{8610if (basis_transcoder_format_is_uncompressed(target_format))8611{8612// Assume the output buffer is orig_width by orig_height8613if (!output_row_pitch_in_blocks_or_pixels)8614output_row_pitch_in_blocks_or_pixels = orig_width;86158616if (!output_rows_in_pixels)8617output_rows_in_pixels = orig_height;86188619// Now make sure the output buffer is large enough, or we'll overwrite memory.8620if (output_blocks_buf_size_in_blocks_or_pixels < (output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels))8621{8622BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output_blocks_buf_size_in_blocks_or_pixels < (output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels)\n");8623return false;8624}8625}8626else if (target_format == transcoder_texture_format::cTFFXT1_RGB)8627{8628const uint32_t num_blocks_fxt1_x = (orig_width + 7) / 8;8629const uint32_t num_blocks_fxt1_y = (orig_height + 3) / 4;8630const uint32_t total_blocks_fxt1 = num_blocks_fxt1_x * num_blocks_fxt1_y;86318632if (output_blocks_buf_size_in_blocks_or_pixels < total_blocks_fxt1)8633{8634BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output_blocks_buf_size_in_blocks_or_pixels < total_blocks_fxt1\n");8635return false;8636}8637}8638else8639{8640if (output_blocks_buf_size_in_blocks_or_pixels < total_slice_blocks)8641{8642BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output_blocks_buf_size_in_blocks_or_pixels < transcode_image\n");8643return false;8644}8645}8646return true;8647}86488649bool basisu_lowlevel_etc1s_transcoder::transcode_image(8650transcoder_texture_format target_format,8651void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,8652const uint8_t* pCompressed_data, uint32_t compressed_data_length,8653uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,8654uint32_t rgb_offset, uint32_t rgb_length, uint32_t alpha_offset, uint32_t alpha_length,8655uint32_t decode_flags,8656bool basis_file_has_alpha_slices,8657bool is_video,8658uint32_t output_row_pitch_in_blocks_or_pixels,8659basisu_transcoder_state* pState,8660uint32_t output_rows_in_pixels)8661{8662if (((uint64_t)rgb_offset + rgb_length) > (uint64_t)compressed_data_length)8663{8664BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: source data buffer too small (color)\n");8665return false;8666}86678668if (alpha_length)8669{8670if (((uint64_t)alpha_offset + alpha_length) > (uint64_t)compressed_data_length)8671{8672BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: source data buffer too small (alpha)\n");8673return false;8674}8675}8676else8677{8678assert(!basis_file_has_alpha_slices);8679}86808681if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGB) || (target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA))8682{8683if ((!basisu::is_pow2(num_blocks_x * 4)) || (!basisu::is_pow2(num_blocks_y * 4)))8684{8685// PVRTC1 only supports power of 2 dimensions8686BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC1 only supports power of 2 dimensions\n");8687return false;8688}8689}86908691if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA) && (!basis_file_has_alpha_slices))8692{8693// Switch to PVRTC1 RGB if the input doesn't have alpha.8694target_format = transcoder_texture_format::cTFPVRTC1_4_RGB;8695}86968697const bool transcode_alpha_data_to_opaque_formats = (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0;8698const uint32_t bytes_per_block_or_pixel = basis_get_bytes_per_block_or_pixel(target_format);8699const uint32_t total_slice_blocks = num_blocks_x * num_blocks_y;87008701if (!basis_validate_output_buffer_size(target_format, output_blocks_buf_size_in_blocks_or_pixels, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, output_rows_in_pixels, total_slice_blocks))8702{8703BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: output buffer size too small\n");8704return false;8705}87068707bool status = false;87088709const uint8_t* pData = pCompressed_data + rgb_offset;8710uint32_t data_len = rgb_length;8711bool is_alpha_slice = false;87128713// If the caller wants us to transcode the mip level's alpha data, then use the next slice.8714if ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats))8715{8716pData = pCompressed_data + alpha_offset;8717data_len = alpha_length;8718is_alpha_slice = true;8719}87208721switch (target_format)8722{8723case transcoder_texture_format::cTFETC1_RGB:8724{8725//status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8726status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cETC1, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);87278728if (!status)8729{8730BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC1 failed\n");8731}8732break;8733}8734case transcoder_texture_format::cTFBC1_RGB:8735{8736#if !BASISD_SUPPORT_DXT18737BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: BC1/DXT1 unsupported\n");8738return false;8739#else8740// status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8741status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cBC1, bytes_per_block_or_pixel, true, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8742if (!status)8743{8744BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC1 failed\n");8745}8746break;8747#endif8748}8749case transcoder_texture_format::cTFBC4_R:8750{8751#if !BASISD_SUPPORT_DXT5A8752BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: BC4/DXT5A unsupported\n");8753return false;8754#else8755//status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8756status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8757if (!status)8758{8759BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC4 failed\n");8760}8761break;8762#endif8763}8764case transcoder_texture_format::cTFPVRTC1_4_RGB:8765{8766#if !BASISD_SUPPORT_PVRTC18767BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC1 4 unsupported\n");8768return false;8769#else8770// output_row_pitch_in_blocks_or_pixels is actually ignored because we're transcoding to PVRTC1. (Print a dev warning if it's != 0?)8771//status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8772status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cPVRTC1_4_RGB, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8773if (!status)8774{8775BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to PVRTC1 4 RGB failed\n");8776}8777break;8778#endif8779}8780case transcoder_texture_format::cTFPVRTC1_4_RGBA:8781{8782#if !BASISD_SUPPORT_PVRTC18783BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC1 4 unsupported\n");8784return false;8785#else8786assert(basis_file_has_alpha_slices);8787assert(alpha_length);87888789// Temp buffer to hold alpha block endpoint/selector indices8790basisu::vector<uint32_t> temp_block_indices(total_slice_blocks);87918792// First transcode alpha data to temp buffer8793//status = transcode_slice(pData, data_size, slice_index + 1, &temp_block_indices[0], total_slice_blocks, block_format::cIndices, sizeof(uint32_t), decode_flags, pSlice_descs[slice_index].m_num_blocks_x, pState);8794status = transcode_slice(&temp_block_indices[0], num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cIndices, sizeof(uint32_t), false, is_video, true, level_index, orig_width, orig_height, num_blocks_x, pState, false, nullptr, 0);8795if (!status)8796{8797BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to PVRTC1 4 RGBA failed (0)\n");8798}8799else8800{8801// output_row_pitch_in_blocks_or_pixels is actually ignored because we're transcoding to PVRTC1. (Print a dev warning if it's != 0?)8802//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGBA, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState, &temp_block_indices[0]);8803status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cPVRTC1_4_RGBA, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, &temp_block_indices[0], 0);8804if (!status)8805{8806BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to PVRTC1 4 RGBA failed (1)\n");8807}8808}88098810break;8811#endif8812}8813case transcoder_texture_format::cTFBC7_RGBA:8814case transcoder_texture_format::cTFBC7_ALT:8815{8816#if !BASISD_SUPPORT_BC7_MODE58817BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: BC7 unsupported\n");8818return false;8819#else8820assert(bytes_per_block_or_pixel == 16);8821// We used to support transcoding just alpha to BC7 - but is that useful at all?88228823// First transcode the color slice. The cBC7_M5_COLOR transcoder will output opaque mode 5 blocks.8824//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7_M5_COLOR, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8825status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cBC7_M5_COLOR, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);88268827if ((status) && (basis_file_has_alpha_slices))8828{8829// Now transcode the alpha slice. The cBC7_M5_ALPHA transcoder will now change the opaque mode 5 blocks to blocks with alpha.8830//status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7_M5_ALPHA, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8831status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cBC7_M5_ALPHA, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8832}88338834if (!status)8835{8836BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC7 failed (0)\n");8837}88388839break;8840#endif8841}8842case transcoder_texture_format::cTFETC2_RGBA:8843{8844#if !BASISD_SUPPORT_ETC2_EAC_A88845BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: ETC2 EAC A8 unsupported\n");8846return false;8847#else8848assert(bytes_per_block_or_pixel == 16);88498850if (basis_file_has_alpha_slices)8851{8852// First decode the alpha data8853//status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_A8, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8854status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cETC2_EAC_A8, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8855}8856else8857{8858//write_opaque_alpha_blocks(pSlice_descs[slice_index].m_num_blocks_x, pSlice_descs[slice_index].m_num_blocks_y, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_A8, 16, output_row_pitch_in_blocks_or_pixels);8859basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, pOutput_blocks, block_format::cETC2_EAC_A8, 16, output_row_pitch_in_blocks_or_pixels);8860status = true;8861}88628863if (status)8864{8865// Now decode the color data8866//status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8867status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cETC1, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8868if (!status)8869{8870BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2 RGB failed\n");8871}8872}8873else8874{8875BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2 A failed\n");8876}8877break;8878#endif8879}8880case transcoder_texture_format::cTFBC3_RGBA:8881{8882#if !BASISD_SUPPORT_DXT18883BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: DXT1 unsupported\n");8884return false;8885#elif !BASISD_SUPPORT_DXT5A8886BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: DXT5A unsupported\n");8887return false;8888#else8889assert(bytes_per_block_or_pixel == 16);88908891// First decode the alpha data8892if (basis_file_has_alpha_slices)8893{8894//status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8895status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8896}8897else8898{8899basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, pOutput_blocks, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);8900status = true;8901}89028903if (status)8904{8905// Now decode the color data. Forbid 3 color blocks, which aren't allowed in BC3.8906//status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, 16, decode_flags | cDecodeFlagsBC1ForbidThreeColorBlocks, output_row_pitch_in_blocks_or_pixels, pState);8907status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cBC1, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8908if (!status)8909{8910BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC3 RGB failed\n");8911}8912}8913else8914{8915BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC3 A failed\n");8916}89178918break;8919#endif8920}8921case transcoder_texture_format::cTFBC5_RG:8922{8923#if !BASISD_SUPPORT_DXT5A8924BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: DXT5A unsupported\n");8925return false;8926#else8927assert(bytes_per_block_or_pixel == 16);89288929//bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,8930// uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const bool is_video, const bool is_alpha_slice, const uint32_t level_index, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels = 0,8931// basisu_transcoder_state* pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0);89328933// Decode the R data (actually the green channel of the color data slice in the basis file)8934//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8935status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8936if (status)8937{8938if (basis_file_has_alpha_slices)8939{8940// Decode the G data (actually the green channel of the alpha data slice in the basis file)8941//status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8942status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8943if (!status)8944{8945BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC5 1 failed\n");8946}8947}8948else8949{8950basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, (uint8_t*)pOutput_blocks + 8, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);8951status = true;8952}8953}8954else8955{8956BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to BC5 channel 0 failed\n");8957}8958break;8959#endif8960}8961case transcoder_texture_format::cTFASTC_4x4_RGBA:8962{8963#if !BASISD_SUPPORT_ASTC8964BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: ASTC unsupported\n");8965return false;8966#else8967assert(bytes_per_block_or_pixel == 16);89688969if (basis_file_has_alpha_slices)8970{8971// First decode the alpha data to the output (we're using the output texture as a temp buffer here).8972//status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cIndices, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8973status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cIndices, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);8974if (status)8975{8976// Now decode the color data and transcode to ASTC. The transcoder function will read the alpha selector data from the output texture as it converts and8977// transcode both the alpha and color data at the same time to ASTC.8978//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, 16, decode_flags | cDecodeFlagsOutputHasAlphaIndices, output_row_pitch_in_blocks_or_pixels, pState);8979status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cASTC_4x4, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, true, nullptr, output_rows_in_pixels);8980}8981}8982else8983//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);8984status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cASTC_4x4, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);89858986if (!status)8987{8988BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ASTC failed (0)\n");8989}89908991break;8992#endif8993}8994case transcoder_texture_format::cTFATC_RGB:8995{8996#if !BASISD_SUPPORT_ATC8997BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: ATC unsupported\n");8998return false;8999#else9000//status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cATC_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9001status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cATC_RGB, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9002if (!status)9003{9004BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ATC_RGB failed\n");9005}9006break;9007#endif9008}9009case transcoder_texture_format::cTFATC_RGBA:9010{9011#if !BASISD_SUPPORT_ATC9012BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: ATC unsupported\n");9013return false;9014#elif !BASISD_SUPPORT_DXT5A9015BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: DXT5A unsupported\n");9016return false;9017#else9018assert(bytes_per_block_or_pixel == 16);90199020// First decode the alpha data9021if (basis_file_has_alpha_slices)9022{9023//status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9024status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cBC4, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9025}9026else9027{9028basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, pOutput_blocks, block_format::cBC4, 16, output_row_pitch_in_blocks_or_pixels);9029status = true;9030}90319032if (status)9033{9034//status = transcode_slice(pData, data_size, slice_index, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cATC_RGB, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9035status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cATC_RGB, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9036if (!status)9037{9038BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ATC RGB failed\n");9039}9040}9041else9042{9043BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ATC A failed\n");9044}9045break;9046#endif9047}9048case transcoder_texture_format::cTFPVRTC2_4_RGB:9049{9050#if !BASISD_SUPPORT_PVRTC29051BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC2 unsupported\n");9052return false;9053#else9054//status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9055status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cPVRTC2_4_RGB, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9056if (!status)9057{9058BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to cPVRTC2_4_RGB failed\n");9059}9060break;9061#endif9062}9063case transcoder_texture_format::cTFPVRTC2_4_RGBA:9064{9065#if !BASISD_SUPPORT_PVRTC29066BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: PVRTC2 unsupported\n");9067return false;9068#else9069if (basis_file_has_alpha_slices)9070{9071// First decode the alpha data to the output (we're using the output texture as a temp buffer here).9072//status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cIndices, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9073status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cIndices, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9074if (!status)9075{9076BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to failed\n");9077}9078else9079{9080// Now decode the color data and transcode to PVRTC2 RGBA.9081//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGBA, bytes_per_block_or_pixel, decode_flags | cDecodeFlagsOutputHasAlphaIndices, output_row_pitch_in_blocks_or_pixels, pState);9082status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cPVRTC2_4_RGBA, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, true, nullptr, output_rows_in_pixels);9083}9084}9085else9086//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC2_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9087status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cPVRTC2_4_RGB, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);90889089if (!status)9090{9091BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to cPVRTC2_4_RGBA failed\n");9092}90939094break;9095#endif9096}9097case transcoder_texture_format::cTFRGBA32:9098{9099// Raw 32bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.91009101// First decode the alpha data9102if (basis_file_has_alpha_slices)9103//status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cA32, sizeof(uint32_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);9104status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cA32, sizeof(uint32_t), false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9105else9106status = true;91079108if (status)9109{9110//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, basis_file_has_alpha_slices ? block_format::cRGB32 : block_format::cRGBA32, sizeof(uint32_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);9111status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, basis_file_has_alpha_slices ? block_format::cRGB32 : block_format::cRGBA32, sizeof(uint32_t), false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9112if (!status)9113{9114BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGBA32 RGB failed\n");9115}9116}9117else9118{9119BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGBA32 A failed\n");9120}91219122break;9123}9124case transcoder_texture_format::cTFRGB565:9125case transcoder_texture_format::cTFBGR565:9126{9127// Raw 16bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.91289129//status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, (fmt == transcoder_texture_format::cTFRGB565) ? block_format::cRGB565 : block_format::cBGR565, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);9130status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, (target_format == transcoder_texture_format::cTFRGB565) ? block_format::cRGB565 : block_format::cBGR565, sizeof(uint16_t), false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9131if (!status)9132{9133BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGB565 RGB failed\n");9134}91359136break;9137}9138case transcoder_texture_format::cTFRGBA4444:9139{9140// Raw 16bpp pixels, decoded in the usual raster order (NOT block order) into an image in memory.91419142// First decode the alpha data9143if (basis_file_has_alpha_slices)9144//status = transcode_slice(pData, data_size, slice_index + 1, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);9145status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cRGBA4444_ALPHA, sizeof(uint16_t), false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9146else9147status = true;91489149if (status)9150{9151//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, basis_file_has_alpha_slices ? block_format::cRGBA4444_COLOR : block_format::cRGBA4444_COLOR_OPAQUE, sizeof(uint16_t), decode_flags, output_row_pitch_in_blocks_or_pixels, pState, nullptr, output_rows_in_pixels);9152status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, basis_file_has_alpha_slices ? block_format::cRGBA4444_COLOR : block_format::cRGBA4444_COLOR_OPAQUE, sizeof(uint16_t), false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9153if (!status)9154{9155BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGBA4444 RGB failed\n");9156}9157}9158else9159{9160BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to RGBA4444 A failed\n");9161}91629163break;9164}9165case transcoder_texture_format::cTFFXT1_RGB:9166{9167#if !BASISD_SUPPORT_FXT19168BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: FXT1 unsupported\n");9169return false;9170#else9171//status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cFXT1_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9172status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cFXT1_RGB, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9173if (!status)9174{9175BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to FXT1_RGB failed\n");9176}9177break;9178#endif9179}9180case transcoder_texture_format::cTFETC2_EAC_R11:9181{9182#if !BASISD_SUPPORT_ETC2_EAC_RG119183BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: EAC_RG11 unsupported\n");9184return false;9185#else9186//status = transcode_slice(pData, data_size, slice_index_to_decode, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9187status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pData, data_len, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, false, is_video, is_alpha_slice, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9188if (!status)9189{9190BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2_EAC_R11 failed\n");9191}91929193break;9194#endif9195}9196case transcoder_texture_format::cTFETC2_EAC_RG11:9197{9198#if !BASISD_SUPPORT_ETC2_EAC_RG119199BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: EAC_RG11 unsupported\n");9200return false;9201#else9202assert(bytes_per_block_or_pixel == 16);92039204if (basis_file_has_alpha_slices)9205{9206// First decode the alpha data to G9207//status = transcode_slice(pData, data_size, slice_index + 1, (uint8_t*)pOutput_blocks + 8, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9208status = transcode_slice((uint8_t *)pOutput_blocks + 8, num_blocks_x, num_blocks_y, pCompressed_data + alpha_offset, alpha_length, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, false, is_video, true, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9209}9210else9211{9212basisu_transcoder::write_opaque_alpha_blocks(num_blocks_x, num_blocks_y, (uint8_t*)pOutput_blocks + 8, block_format::cETC2_EAC_R11, 16, output_row_pitch_in_blocks_or_pixels);9213status = true;9214}92159216if (status)9217{9218// Now decode the color data to R9219//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, 16, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9220status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + rgb_offset, rgb_length, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, false, is_video, false, level_index, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, false, nullptr, output_rows_in_pixels);9221if (!status)9222{9223BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2_EAC_R11 R failed\n");9224}9225}9226else9227{9228BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: transcode_slice() to ETC2_EAC_R11 G failed\n");9229}92309231break;9232#endif9233}9234default:9235{9236assert(0);9237BASISU_DEVEL_ERROR("basisu_lowlevel_etc1s_transcoder::transcode_image: Invalid fmt\n");9238break;9239}9240}92419242return status;9243}92449245basisu_lowlevel_uastc_transcoder::basisu_lowlevel_uastc_transcoder()9246{9247}92489249bool basisu_lowlevel_uastc_transcoder::transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,9250uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels,9251basisu_transcoder_state* pState, uint32_t output_rows_in_pixels, int channel0, int channel1, uint32_t decode_flags)9252{9253BASISU_NOTE_UNUSED(pState);9254BASISU_NOTE_UNUSED(bc1_allow_threecolor_blocks);92559256assert(g_transcoder_initialized);9257if (!g_transcoder_initialized)9258{9259BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_slice: Transcoder not globally initialized.\n");9260return false;9261}92629263#if BASISD_SUPPORT_UASTC9264const uint32_t total_blocks = num_blocks_x * num_blocks_y;92659266if (!output_row_pitch_in_blocks_or_pixels)9267{9268if (basis_block_format_is_uncompressed(fmt))9269output_row_pitch_in_blocks_or_pixels = orig_width;9270else9271{9272if (fmt == block_format::cFXT1_RGB)9273output_row_pitch_in_blocks_or_pixels = (orig_width + 7) / 8;9274else9275output_row_pitch_in_blocks_or_pixels = num_blocks_x;9276}9277}92789279if (basis_block_format_is_uncompressed(fmt))9280{9281if (!output_rows_in_pixels)9282output_rows_in_pixels = orig_height;9283}92849285uint32_t total_expected_block_bytes = sizeof(uastc_block) * total_blocks;9286if (image_data_size < total_expected_block_bytes)9287{9288BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_slice: image_data_size < total_expected_block_bytes The file is corrupted or this is a bug.\n");9289return false;9290}92919292const uastc_block* pSource_block = reinterpret_cast<const uastc_block *>(pImage_data);92939294const bool high_quality = (decode_flags & cDecodeFlagsHighQuality) != 0;9295const bool from_alpha = has_alpha && (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0;92969297bool status = false;9298if ((fmt == block_format::cPVRTC1_4_RGB) || (fmt == block_format::cPVRTC1_4_RGBA))9299{9300if (fmt == block_format::cPVRTC1_4_RGBA)9301transcode_uastc_to_pvrtc1_4_rgba((const uastc_block*)pImage_data, pDst_blocks, num_blocks_x, num_blocks_y, high_quality);9302else9303transcode_uastc_to_pvrtc1_4_rgb((const uastc_block *)pImage_data, pDst_blocks, num_blocks_x, num_blocks_y, high_quality, from_alpha);9304}9305else9306{9307for (uint32_t block_y = 0; block_y < num_blocks_y; ++block_y)9308{9309void* pDst_block = (uint8_t*)pDst_blocks + block_y * output_row_pitch_in_blocks_or_pixels * output_block_or_pixel_stride_in_bytes;93109311for (uint32_t block_x = 0; block_x < num_blocks_x; ++block_x, ++pSource_block, pDst_block = (uint8_t *)pDst_block + output_block_or_pixel_stride_in_bytes)9312{9313switch (fmt)9314{9315case block_format::cUASTC_4x4:9316{9317memcpy(pDst_block, pSource_block, sizeof(uastc_block));9318status = true;9319break;9320}9321case block_format::cETC1:9322{9323if (from_alpha)9324status = transcode_uastc_to_etc1(*pSource_block, pDst_block, 3);9325else9326status = transcode_uastc_to_etc1(*pSource_block, pDst_block);9327break;9328}9329case block_format::cETC2_RGBA:9330{9331status = transcode_uastc_to_etc2_rgba(*pSource_block, pDst_block);9332break;9333}9334case block_format::cBC1:9335{9336status = transcode_uastc_to_bc1(*pSource_block, pDst_block, high_quality);9337break;9338}9339case block_format::cBC3:9340{9341status = transcode_uastc_to_bc3(*pSource_block, pDst_block, high_quality);9342break;9343}9344case block_format::cBC4:9345{9346if (channel0 < 0)9347channel0 = 0;9348status = transcode_uastc_to_bc4(*pSource_block, pDst_block, high_quality, channel0);9349break;9350}9351case block_format::cBC5:9352{9353if (channel0 < 0)9354channel0 = 0;9355if (channel1 < 0)9356channel1 = 3;9357status = transcode_uastc_to_bc5(*pSource_block, pDst_block, high_quality, channel0, channel1);9358break;9359}9360case block_format::cBC7:9361case block_format::cBC7_M5_COLOR: // for consistently with ETC1S9362{9363status = transcode_uastc_to_bc7(*pSource_block, pDst_block);9364break;9365}9366case block_format::cASTC_4x4:9367{9368status = transcode_uastc_to_astc(*pSource_block, pDst_block);9369break;9370}9371case block_format::cETC2_EAC_R11:9372{9373if (channel0 < 0)9374channel0 = 0;9375status = transcode_uastc_to_etc2_eac_r11(*pSource_block, pDst_block, high_quality, channel0);9376break;9377}9378case block_format::cETC2_EAC_RG11:9379{9380if (channel0 < 0)9381channel0 = 0;9382if (channel1 < 0)9383channel1 = 3;9384status = transcode_uastc_to_etc2_eac_rg11(*pSource_block, pDst_block, high_quality, channel0, channel1);9385break;9386}9387case block_format::cRGBA32:9388{9389color32 block_pixels[4][4];9390status = unpack_uastc(*pSource_block, (color32 *)block_pixels, false);93919392assert(sizeof(uint32_t) == output_block_or_pixel_stride_in_bytes);9393uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint32_t);93949395const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);9396const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);93979398for (uint32_t y = 0; y < max_y; y++)9399{9400for (uint32_t x = 0; x < max_x; x++)9401{9402const color32& c = block_pixels[y][x];94039404pDst_pixels[0 + 4 * x] = c.r;9405pDst_pixels[1 + 4 * x] = c.g;9406pDst_pixels[2 + 4 * x] = c.b;9407pDst_pixels[3 + 4 * x] = c.a;9408}94099410pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint32_t);9411}94129413break;9414}9415case block_format::cRGB565:9416case block_format::cBGR565:9417{9418color32 block_pixels[4][4];9419status = unpack_uastc(*pSource_block, (color32*)block_pixels, false);94209421assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);9422uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);94239424const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);9425const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);94269427for (uint32_t y = 0; y < max_y; y++)9428{9429for (uint32_t x = 0; x < max_x; x++)9430{9431const color32& c = block_pixels[y][x];94329433const uint16_t packed = (fmt == block_format::cRGB565) ? static_cast<uint16_t>((mul_8(c.r, 31) << 11) | (mul_8(c.g, 63) << 5) | mul_8(c.b, 31)) :9434static_cast<uint16_t>((mul_8(c.b, 31) << 11) | (mul_8(c.g, 63) << 5) | mul_8(c.r, 31));94359436pDst_pixels[x * 2 + 0] = (uint8_t)(packed & 0xFF);9437pDst_pixels[x * 2 + 1] = (uint8_t)((packed >> 8) & 0xFF);9438}94399440pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);9441}94429443break;9444}9445case block_format::cRGBA4444:9446{9447color32 block_pixels[4][4];9448status = unpack_uastc(*pSource_block, (color32*)block_pixels, false);94499450assert(sizeof(uint16_t) == output_block_or_pixel_stride_in_bytes);9451uint8_t* pDst_pixels = static_cast<uint8_t*>(pDst_blocks) + (block_x * 4 + block_y * 4 * output_row_pitch_in_blocks_or_pixels) * sizeof(uint16_t);94529453const uint32_t max_x = basisu::minimum<int>(4, (int)output_row_pitch_in_blocks_or_pixels - (int)block_x * 4);9454const uint32_t max_y = basisu::minimum<int>(4, (int)output_rows_in_pixels - (int)block_y * 4);94559456for (uint32_t y = 0; y < max_y; y++)9457{9458for (uint32_t x = 0; x < max_x; x++)9459{9460const color32& c = block_pixels[y][x];94619462const uint16_t packed = static_cast<uint16_t>((mul_8(c.r, 15) << 12) | (mul_8(c.g, 15) << 8) | (mul_8(c.b, 15) << 4) | mul_8(c.a, 15));94639464pDst_pixels[x * 2 + 0] = (uint8_t)(packed & 0xFF);9465pDst_pixels[x * 2 + 1] = (uint8_t)((packed >> 8) & 0xFF);9466}94679468pDst_pixels += output_row_pitch_in_blocks_or_pixels * sizeof(uint16_t);9469}9470break;9471}9472default:9473assert(0);9474break;94759476}94779478if (!status)9479{9480BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_slice: Transcoder failed to unpack a UASTC block - this is a bug, or the data was corrupted\n");9481return false;9482}94839484} // block_x94859486} // block_y9487}94889489return true;9490#else9491BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_slice: UASTC is unsupported\n");94929493BASISU_NOTE_UNUSED(decode_flags);9494BASISU_NOTE_UNUSED(channel0);9495BASISU_NOTE_UNUSED(channel1);9496BASISU_NOTE_UNUSED(output_rows_in_pixels);9497BASISU_NOTE_UNUSED(output_row_pitch_in_blocks_or_pixels);9498BASISU_NOTE_UNUSED(output_block_or_pixel_stride_in_bytes);9499BASISU_NOTE_UNUSED(fmt);9500BASISU_NOTE_UNUSED(image_data_size);9501BASISU_NOTE_UNUSED(pImage_data);9502BASISU_NOTE_UNUSED(num_blocks_x);9503BASISU_NOTE_UNUSED(num_blocks_y);9504BASISU_NOTE_UNUSED(pDst_blocks);95059506return false;9507#endif9508}95099510bool basisu_lowlevel_uastc_transcoder::transcode_image(9511transcoder_texture_format target_format,9512void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,9513const uint8_t* pCompressed_data, uint32_t compressed_data_length,9514uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,9515uint32_t slice_offset, uint32_t slice_length,9516uint32_t decode_flags,9517bool has_alpha,9518bool is_video,9519uint32_t output_row_pitch_in_blocks_or_pixels,9520basisu_transcoder_state* pState,9521uint32_t output_rows_in_pixels,9522int channel0, int channel1)9523{9524BASISU_NOTE_UNUSED(is_video);9525BASISU_NOTE_UNUSED(level_index);95269527if (((uint64_t)slice_offset + slice_length) > (uint64_t)compressed_data_length)9528{9529BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: source data buffer too small\n");9530return false;9531}95329533if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGB) || (target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA))9534{9535if ((!basisu::is_pow2(num_blocks_x * 4)) || (!basisu::is_pow2(num_blocks_y * 4)))9536{9537// PVRTC1 only supports power of 2 dimensions9538BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: PVRTC1 only supports power of 2 dimensions\n");9539return false;9540}9541}95429543if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA) && (!has_alpha))9544{9545// Switch to PVRTC1 RGB if the input doesn't have alpha.9546target_format = transcoder_texture_format::cTFPVRTC1_4_RGB;9547}95489549const bool transcode_alpha_data_to_opaque_formats = (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0;9550const uint32_t bytes_per_block_or_pixel = basis_get_bytes_per_block_or_pixel(target_format);9551const uint32_t total_slice_blocks = num_blocks_x * num_blocks_y;95529553if (!basis_validate_output_buffer_size(target_format, output_blocks_buf_size_in_blocks_or_pixels, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, output_rows_in_pixels, total_slice_blocks))9554{9555BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: output buffer size too small\n");9556return false;9557}95589559bool status = false;95609561// UASTC4x49562switch (target_format)9563{9564case transcoder_texture_format::cTFETC1_RGB:9565{9566//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9567status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC1,9568bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1);95699570if (!status)9571{9572BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ETC1 failed\n");9573}9574break;9575}9576case transcoder_texture_format::cTFETC2_RGBA:9577{9578//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_RGBA, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9579status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_RGBA,9580bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1);9581if (!status)9582{9583BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ETC2 failed\n");9584}9585break;9586}9587case transcoder_texture_format::cTFBC1_RGB:9588{9589// TODO: ETC1S allows BC1 from alpha channel. That doesn't seem actually useful, though.9590//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9591status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC1,9592bytes_per_block_or_pixel, true, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1);9593if (!status)9594{9595BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC1 failed\n");9596}9597break;9598}9599case transcoder_texture_format::cTFBC3_RGBA:9600{9601//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC3, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9602status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC3,9603bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1);9604if (!status)9605{9606BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC3 failed\n");9607}9608break;9609}9610case transcoder_texture_format::cTFBC4_R:9611{9612//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState,9613// nullptr, 0,9614// ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0);9615status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC4,9616bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels,9617((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0);9618if (!status)9619{9620BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC4 failed\n");9621}9622break;9623}9624case transcoder_texture_format::cTFBC5_RG:9625{9626//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC5, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState,9627// nullptr, 0,9628// 0, 3);9629status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC5,9630bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels,96310, 3);9632if (!status)9633{9634BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC5 failed\n");9635}9636break;9637}9638case transcoder_texture_format::cTFBC7_RGBA:9639case transcoder_texture_format::cTFBC7_ALT:9640{9641//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9642status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC7,9643bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);9644if (!status)9645{9646BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC7 failed\n");9647}9648break;9649}9650case transcoder_texture_format::cTFPVRTC1_4_RGB:9651{9652//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9653status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cPVRTC1_4_RGB,9654bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);9655if (!status)9656{9657BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to PVRTC1 RGB 4bpp failed\n");9658}9659break;9660}9661case transcoder_texture_format::cTFPVRTC1_4_RGBA:9662{9663//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGBA, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9664status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cPVRTC1_4_RGBA,9665bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);9666if (!status)9667{9668BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to PVRTC1 RGBA 4bpp failed\n");9669}9670break;9671}9672case transcoder_texture_format::cTFASTC_4x4_RGBA:9673{9674//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9675status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cASTC_4x4,9676bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);9677if (!status)9678{9679BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ASTC 4x4 failed\n");9680}9681break;9682}9683case transcoder_texture_format::cTFATC_RGB:9684case transcoder_texture_format::cTFATC_RGBA:9685{9686BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: UASTC->ATC currently unsupported\n");9687return false;9688}9689case transcoder_texture_format::cTFFXT1_RGB:9690{9691BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: UASTC->FXT1 currently unsupported\n");9692return false;9693}9694case transcoder_texture_format::cTFPVRTC2_4_RGB:9695{9696BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: UASTC->PVRTC2 currently unsupported\n");9697return false;9698}9699case transcoder_texture_format::cTFPVRTC2_4_RGBA:9700{9701BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: UASTC->PVRTC2 currently unsupported\n");9702return false;9703}9704case transcoder_texture_format::cTFETC2_EAC_R11:9705{9706//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState,9707// nullptr, 0,9708// ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0);9709status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_EAC_R11,9710bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels,9711((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0);9712if (!status)9713{9714BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to EAC R11 failed\n");9715}9716break;9717}9718case transcoder_texture_format::cTFETC2_EAC_RG11:9719{9720//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_RG11, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState,9721// nullptr, 0,9722// 0, 3);9723status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_EAC_RG11,9724bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels,97250, 3);9726if (!status)9727{9728BASISU_DEVEL_ERROR("basisu_basisu_lowlevel_uastc_transcodertranscoder::transcode_image: transcode_slice() to EAC RG11 failed\n");9729}9730break;9731}9732case transcoder_texture_format::cTFRGBA32:9733{9734//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA32, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9735status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGBA32,9736bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);9737if (!status)9738{9739BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGBA32 failed\n");9740}9741break;9742}9743case transcoder_texture_format::cTFRGB565:9744{9745//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGB565, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9746status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGB565,9747bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);9748if (!status)9749{9750BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGB565 failed\n");9751}9752break;9753}9754case transcoder_texture_format::cTFBGR565:9755{9756//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBGR565, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9757status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBGR565,9758bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);9759if (!status)9760{9761BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGB565 failed\n");9762}9763break;9764}9765case transcoder_texture_format::cTFRGBA4444:9766{9767//status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA4444, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState);9768status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGBA4444,9769bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);9770if (!status)9771{9772BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGBA4444 failed\n");9773}9774break;9775}9776default:9777{9778assert(0);9779BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: Invalid format\n");9780break;9781}9782}97839784return status;9785}97869787basisu_transcoder::basisu_transcoder() :9788m_ready_to_transcode(false)9789{9790}97919792bool basisu_transcoder::validate_file_checksums(const void* pData, uint32_t data_size, bool full_validation) const9793{9794if (!validate_header(pData, data_size))9795return false;97969797const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);97989799#if !BASISU_NO_HEADER_OR_DATA_CRC16_CHECKS9800if (crc16(&pHeader->m_data_size, sizeof(basis_file_header) - BASISU_OFFSETOF(basis_file_header, m_data_size), 0) != pHeader->m_header_crc16)9801{9802BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: header CRC check failed\n");9803return false;9804}98059806if (full_validation)9807{9808if (crc16(reinterpret_cast<const uint8_t*>(pData) + sizeof(basis_file_header), pHeader->m_data_size, 0) != pHeader->m_data_crc16)9809{9810BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: data CRC check failed\n");9811return false;9812}9813}9814#endif98159816return true;9817}98189819bool basisu_transcoder::validate_header_quick(const void* pData, uint32_t data_size) const9820{9821if (data_size <= sizeof(basis_file_header))9822return false;98239824const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);98259826if ((pHeader->m_sig != basis_file_header::cBASISSigValue) || (pHeader->m_ver != BASISD_SUPPORTED_BASIS_VERSION) || (pHeader->m_header_size != sizeof(basis_file_header)))9827{9828BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: header has an invalid signature, or file version is unsupported\n");9829return false;9830}98319832uint32_t expected_file_size = sizeof(basis_file_header) + pHeader->m_data_size;9833if (data_size < expected_file_size)9834{9835BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: source buffer is too small\n");9836return false;9837}98389839if ((!pHeader->m_total_slices) || (!pHeader->m_total_images))9840{9841BASISU_DEVEL_ERROR("basisu_transcoder::validate_header_quick: header is invalid\n");9842return false;9843}98449845if ((pHeader->m_slice_desc_file_ofs >= data_size) ||9846((data_size - pHeader->m_slice_desc_file_ofs) < (sizeof(basis_slice_desc) * pHeader->m_total_slices))9847)9848{9849BASISU_DEVEL_ERROR("basisu_transcoder::validate_header_quick: passed in buffer is too small or data is corrupted\n");9850return false;9851}98529853return true;9854}98559856bool basisu_transcoder::validate_header(const void* pData, uint32_t data_size) const9857{9858if (data_size <= sizeof(basis_file_header))9859{9860BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: input source buffer is too small\n");9861return false;9862}98639864const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);98659866if ((pHeader->m_sig != basis_file_header::cBASISSigValue) || (pHeader->m_ver != BASISD_SUPPORTED_BASIS_VERSION) || (pHeader->m_header_size != sizeof(basis_file_header)))9867{9868BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: header has an invalid signature, or file version is unsupported\n");9869return false;9870}98719872uint32_t expected_file_size = sizeof(basis_file_header) + pHeader->m_data_size;9873if (data_size < expected_file_size)9874{9875BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: input source buffer is too small, or header is corrupted\n");9876return false;9877}98789879if ((!pHeader->m_total_images) || (!pHeader->m_total_slices))9880{9881BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: invalid basis file (total images or slices are 0)\n");9882return false;9883}98849885if (pHeader->m_total_images > pHeader->m_total_slices)9886{9887BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: invalid basis file (too many images)\n");9888return false;9889}98909891if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)9892{9893if (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices)9894{9895if (pHeader->m_total_slices & 1)9896{9897BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: invalid alpha .basis file\n");9898return false;9899}9900}99019902// This flag dates back to pre-Basis Universal, when .basis supported full ETC1 too.9903if ((pHeader->m_flags & cBASISHeaderFlagETC1S) == 0)9904{9905BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: Invalid .basis file (ETC1S check)\n");9906return false;9907}9908}9909else9910{9911if ((pHeader->m_flags & cBASISHeaderFlagETC1S) != 0)9912{9913BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: Invalid .basis file (ETC1S check)\n");9914return false;9915}9916}99179918if ((pHeader->m_slice_desc_file_ofs >= data_size) ||9919((data_size - pHeader->m_slice_desc_file_ofs) < (sizeof(basis_slice_desc) * pHeader->m_total_slices))9920)9921{9922BASISU_DEVEL_ERROR("basisu_transcoder::validate_header_quick: passed in buffer is too small or data is corrupted\n");9923return false;9924}99259926return true;9927}99289929basis_texture_type basisu_transcoder::get_texture_type(const void* pData, uint32_t data_size) const9930{9931if (!validate_header_quick(pData, data_size))9932{9933BASISU_DEVEL_ERROR("basisu_transcoder::get_texture_type: header validation failed\n");9934return cBASISTexType2DArray;9935}99369937const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);99389939basis_texture_type btt = static_cast<basis_texture_type>(static_cast<uint8_t>(pHeader->m_tex_type));99409941if (btt >= cBASISTexTypeTotal)9942{9943BASISU_DEVEL_ERROR("basisu_transcoder::validate_header_quick: header's texture type field is invalid\n");9944return cBASISTexType2DArray;9945}99469947return btt;9948}99499950bool basisu_transcoder::get_userdata(const void* pData, uint32_t data_size, uint32_t& userdata0, uint32_t& userdata1) const9951{9952if (!validate_header_quick(pData, data_size))9953{9954BASISU_DEVEL_ERROR("basisu_transcoder::get_userdata: header validation failed\n");9955return false;9956}99579958const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);99599960userdata0 = pHeader->m_userdata0;9961userdata1 = pHeader->m_userdata1;9962return true;9963}99649965uint32_t basisu_transcoder::get_total_images(const void* pData, uint32_t data_size) const9966{9967if (!validate_header_quick(pData, data_size))9968{9969BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: header validation failed\n");9970return 0;9971}99729973const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);99749975return pHeader->m_total_images;9976}99779978basis_tex_format basisu_transcoder::get_tex_format(const void* pData, uint32_t data_size) const9979{9980if (!validate_header_quick(pData, data_size))9981{9982BASISU_DEVEL_ERROR("basisu_transcoder::get_total_images: header validation failed\n");9983return basis_tex_format::cETC1S;9984}99859986const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);99879988return (basis_tex_format)(uint32_t)pHeader->m_tex_format;9989}99909991bool basisu_transcoder::get_image_info(const void* pData, uint32_t data_size, basisu_image_info& image_info, uint32_t image_index) const9992{9993if (!validate_header_quick(pData, data_size))9994{9995BASISU_DEVEL_ERROR("basisu_transcoder::get_image_info: header validation failed\n");9996return false;9997}99989999int slice_index = find_first_slice_index(pData, data_size, image_index, 0);10000if (slice_index < 0)10001{10002BASISU_DEVEL_ERROR("basisu_transcoder::get_image_info: invalid slice index\n");10003return false;10004}1000510006const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);1000710008if (image_index >= pHeader->m_total_images)10009{10010BASISU_DEVEL_ERROR("basisu_transcoder::get_image_info: invalid image_index\n");10011return false;10012}1001310014const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(static_cast<const uint8_t*>(pData) + pHeader->m_slice_desc_file_ofs);1001510016uint32_t total_levels = 1;10017for (uint32_t i = slice_index + 1; i < pHeader->m_total_slices; i++)10018if (pSlice_descs[i].m_image_index == image_index)10019total_levels = basisu::maximum<uint32_t>(total_levels, pSlice_descs[i].m_level_index + 1);10020else10021break;1002210023if (total_levels > 16)10024{10025BASISU_DEVEL_ERROR("basisu_transcoder::get_image_info: invalid image_index\n");10026return false;10027}1002810029const basis_slice_desc& slice_desc = pSlice_descs[slice_index];1003010031image_info.m_image_index = image_index;10032image_info.m_total_levels = total_levels;1003310034image_info.m_alpha_flag = false;1003510036// For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha.10037if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)10038image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;10039else10040image_info.m_alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0;1004110042image_info.m_iframe_flag = (slice_desc.m_flags & cSliceDescFlagsFrameIsIFrame) != 0;1004310044image_info.m_width = slice_desc.m_num_blocks_x * 4;10045image_info.m_height = slice_desc.m_num_blocks_y * 4;10046image_info.m_orig_width = slice_desc.m_orig_width;10047image_info.m_orig_height = slice_desc.m_orig_height;10048image_info.m_num_blocks_x = slice_desc.m_num_blocks_x;10049image_info.m_num_blocks_y = slice_desc.m_num_blocks_y;10050image_info.m_total_blocks = image_info.m_num_blocks_x * image_info.m_num_blocks_y;10051image_info.m_first_slice_index = slice_index;1005210053return true;10054}1005510056uint32_t basisu_transcoder::get_total_image_levels(const void* pData, uint32_t data_size, uint32_t image_index) const10057{10058if (!validate_header_quick(pData, data_size))10059{10060BASISU_DEVEL_ERROR("basisu_transcoder::get_total_image_levels: header validation failed\n");10061return false;10062}1006310064int slice_index = find_first_slice_index(pData, data_size, image_index, 0);10065if (slice_index < 0)10066{10067BASISU_DEVEL_ERROR("basisu_transcoder::get_total_image_levels: failed finding slice\n");10068return false;10069}1007010071const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);1007210073if (image_index >= pHeader->m_total_images)10074{10075BASISU_DEVEL_ERROR("basisu_transcoder::get_total_image_levels: invalid image_index\n");10076return false;10077}1007810079const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(static_cast<const uint8_t*>(pData) + pHeader->m_slice_desc_file_ofs);1008010081uint32_t total_levels = 1;10082for (uint32_t i = slice_index + 1; i < pHeader->m_total_slices; i++)10083if (pSlice_descs[i].m_image_index == image_index)10084total_levels = basisu::maximum<uint32_t>(total_levels, pSlice_descs[i].m_level_index + 1);10085else10086break;1008710088const uint32_t cMaxSupportedLevels = 16;10089if (total_levels > cMaxSupportedLevels)10090{10091BASISU_DEVEL_ERROR("basisu_transcoder::get_total_image_levels: invalid image levels!\n");10092return false;10093}1009410095return total_levels;10096}1009710098bool basisu_transcoder::get_image_level_desc(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, uint32_t& orig_width, uint32_t& orig_height, uint32_t& total_blocks) const10099{10100if (!validate_header_quick(pData, data_size))10101{10102BASISU_DEVEL_ERROR("basisu_transcoder::get_image_level_desc: header validation failed\n");10103return false;10104}1010510106int slice_index = find_first_slice_index(pData, data_size, image_index, level_index);10107if (slice_index < 0)10108{10109BASISU_DEVEL_ERROR("basisu_transcoder::get_image_level_desc: failed finding slice\n");10110return false;10111}1011210113const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);1011410115if (image_index >= pHeader->m_total_images)10116{10117BASISU_DEVEL_ERROR("basisu_transcoder::get_image_level_desc: invalid image_index\n");10118return false;10119}1012010121const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(static_cast<const uint8_t*>(pData) + pHeader->m_slice_desc_file_ofs);1012210123const basis_slice_desc& slice_desc = pSlice_descs[slice_index];1012410125orig_width = slice_desc.m_orig_width;10126orig_height = slice_desc.m_orig_height;10127total_blocks = slice_desc.m_num_blocks_x * slice_desc.m_num_blocks_y;1012810129return true;10130}1013110132bool basisu_transcoder::get_image_level_info(const void* pData, uint32_t data_size, basisu_image_level_info& image_info, uint32_t image_index, uint32_t level_index) const10133{10134if (!validate_header_quick(pData, data_size))10135{10136BASISU_DEVEL_ERROR("basisu_transcoder::get_image_level_info: validate_file_checksums failed\n");10137return false;10138}1013910140int slice_index = find_first_slice_index(pData, data_size, image_index, level_index);10141if (slice_index < 0)10142{10143BASISU_DEVEL_ERROR("basisu_transcoder::get_image_level_info: failed finding slice\n");10144return false;10145}1014610147const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);1014810149if (image_index >= pHeader->m_total_images)10150{10151BASISU_DEVEL_ERROR("basisu_transcoder::get_image_level_info: invalid image_index\n");10152return false;10153}1015410155const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(static_cast<const uint8_t*>(pData) + pHeader->m_slice_desc_file_ofs);1015610157const basis_slice_desc& slice_desc = pSlice_descs[slice_index];1015810159image_info.m_image_index = image_index;10160image_info.m_level_index = level_index;1016110162// For ETC1S, if anything has alpha all images have alpha. For UASTC, we only report alpha when the image actually has alpha.10163if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)10164image_info.m_alpha_flag = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;10165else10166image_info.m_alpha_flag = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0;1016710168image_info.m_iframe_flag = (slice_desc.m_flags & cSliceDescFlagsFrameIsIFrame) != 0;10169image_info.m_width = slice_desc.m_num_blocks_x * 4;10170image_info.m_height = slice_desc.m_num_blocks_y * 4;10171image_info.m_orig_width = slice_desc.m_orig_width;10172image_info.m_orig_height = slice_desc.m_orig_height;10173image_info.m_num_blocks_x = slice_desc.m_num_blocks_x;10174image_info.m_num_blocks_y = slice_desc.m_num_blocks_y;10175image_info.m_total_blocks = image_info.m_num_blocks_x * image_info.m_num_blocks_y;10176image_info.m_first_slice_index = slice_index;1017710178image_info.m_rgb_file_ofs = slice_desc.m_file_ofs;10179image_info.m_rgb_file_len = slice_desc.m_file_size;10180image_info.m_alpha_file_ofs = 0;10181image_info.m_alpha_file_len = 0;1018210183if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)10184{10185if (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices)10186{10187assert((slice_index + 1) < (int)pHeader->m_total_slices);10188image_info.m_alpha_file_ofs = pSlice_descs[slice_index + 1].m_file_ofs;10189image_info.m_alpha_file_len = pSlice_descs[slice_index + 1].m_file_size;10190}10191}1019210193return true;10194}1019510196bool basisu_transcoder::get_file_info(const void* pData, uint32_t data_size, basisu_file_info& file_info) const10197{10198if (!validate_file_checksums(pData, data_size, false))10199{10200BASISU_DEVEL_ERROR("basisu_transcoder::get_file_info: validate_file_checksums failed\n");10201return false;10202}1020310204const basis_file_header* pHeader = static_cast<const basis_file_header*>(pData);10205const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(static_cast<const uint8_t*>(pData) + pHeader->m_slice_desc_file_ofs);1020610207file_info.m_version = pHeader->m_ver;1020810209file_info.m_total_header_size = sizeof(basis_file_header) + pHeader->m_total_slices * sizeof(basis_slice_desc);1021010211file_info.m_total_selectors = pHeader->m_total_selectors;10212file_info.m_selector_codebook_ofs = pHeader->m_selector_cb_file_ofs;10213file_info.m_selector_codebook_size = pHeader->m_selector_cb_file_size;1021410215file_info.m_total_endpoints = pHeader->m_total_endpoints;10216file_info.m_endpoint_codebook_ofs = pHeader->m_endpoint_cb_file_ofs;10217file_info.m_endpoint_codebook_size = pHeader->m_endpoint_cb_file_size;1021810219file_info.m_tables_ofs = pHeader->m_tables_file_ofs;10220file_info.m_tables_size = pHeader->m_tables_file_size;1022110222file_info.m_tex_format = static_cast<basis_tex_format>(static_cast<int>(pHeader->m_tex_format));1022310224file_info.m_etc1s = (pHeader->m_tex_format == (int)basis_tex_format::cETC1S);1022510226file_info.m_y_flipped = (pHeader->m_flags & cBASISHeaderFlagYFlipped) != 0;10227file_info.m_has_alpha_slices = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;1022810229const uint32_t total_slices = pHeader->m_total_slices;1023010231file_info.m_slice_info.resize(total_slices);1023210233file_info.m_slices_size = 0;1023410235file_info.m_tex_type = static_cast<basis_texture_type>(static_cast<uint8_t>(pHeader->m_tex_type));1023610237if (file_info.m_tex_type > cBASISTexTypeTotal)10238{10239BASISU_DEVEL_ERROR("basisu_transcoder::get_file_info: invalid texture type, file is corrupted\n");10240return false;10241}1024210243file_info.m_us_per_frame = pHeader->m_us_per_frame;10244file_info.m_userdata0 = pHeader->m_userdata0;10245file_info.m_userdata1 = pHeader->m_userdata1;1024610247file_info.m_image_mipmap_levels.resize(0);10248file_info.m_image_mipmap_levels.resize(pHeader->m_total_images);1024910250file_info.m_total_images = pHeader->m_total_images;1025110252for (uint32_t i = 0; i < total_slices; i++)10253{10254file_info.m_slices_size += pSlice_descs[i].m_file_size;1025510256basisu_slice_info& slice_info = file_info.m_slice_info[i];1025710258slice_info.m_orig_width = pSlice_descs[i].m_orig_width;10259slice_info.m_orig_height = pSlice_descs[i].m_orig_height;10260slice_info.m_width = pSlice_descs[i].m_num_blocks_x * 4;10261slice_info.m_height = pSlice_descs[i].m_num_blocks_y * 4;10262slice_info.m_num_blocks_x = pSlice_descs[i].m_num_blocks_x;10263slice_info.m_num_blocks_y = pSlice_descs[i].m_num_blocks_y;10264slice_info.m_total_blocks = slice_info.m_num_blocks_x * slice_info.m_num_blocks_y;10265slice_info.m_compressed_size = pSlice_descs[i].m_file_size;10266slice_info.m_slice_index = i;10267slice_info.m_image_index = pSlice_descs[i].m_image_index;10268slice_info.m_level_index = pSlice_descs[i].m_level_index;10269slice_info.m_unpacked_slice_crc16 = pSlice_descs[i].m_slice_data_crc16;10270slice_info.m_alpha_flag = (pSlice_descs[i].m_flags & cSliceDescFlagsHasAlpha) != 0;10271slice_info.m_iframe_flag = (pSlice_descs[i].m_flags & cSliceDescFlagsFrameIsIFrame) != 0;1027210273if (pSlice_descs[i].m_image_index >= pHeader->m_total_images)10274{10275BASISU_DEVEL_ERROR("basisu_transcoder::get_file_info: slice desc's image index is invalid\n");10276return false;10277}1027810279file_info.m_image_mipmap_levels[pSlice_descs[i].m_image_index] = basisu::maximum<uint32_t>(file_info.m_image_mipmap_levels[pSlice_descs[i].m_image_index], pSlice_descs[i].m_level_index + 1);1028010281if (file_info.m_image_mipmap_levels[pSlice_descs[i].m_image_index] > 16)10282{10283BASISU_DEVEL_ERROR("basisu_transcoder::get_file_info: slice mipmap level is invalid\n");10284return false;10285}10286}1028710288return true;10289}1029010291bool basisu_transcoder::start_transcoding(const void* pData, uint32_t data_size)10292{10293if (!validate_header_quick(pData, data_size))10294{10295BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: header validation failed\n");10296return false;10297}1029810299const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);10300const uint8_t* pDataU8 = static_cast<const uint8_t*>(pData);1030110302if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)10303{10304if (m_lowlevel_etc1s_decoder.m_local_endpoints.size())10305{10306m_lowlevel_etc1s_decoder.clear();10307}1030810309if (pHeader->m_flags & cBASISHeaderFlagUsesGlobalCodebook)10310{10311if (!m_lowlevel_etc1s_decoder.get_global_codebooks())10312{10313BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: File uses global codebooks, but set_global_codebooks() has not been called\n");10314return false;10315}10316if (!m_lowlevel_etc1s_decoder.get_global_codebooks()->get_endpoints().size())10317{10318BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: Global codebooks must be unpacked first by calling start_transcoding()\n");10319return false;10320}10321if ((m_lowlevel_etc1s_decoder.get_global_codebooks()->get_endpoints().size() != pHeader->m_total_endpoints) ||10322(m_lowlevel_etc1s_decoder.get_global_codebooks()->get_selectors().size() != pHeader->m_total_selectors))10323{10324BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: Global codebook size mismatch (wrong codebooks for file).\n");10325return false;10326}10327if (!pHeader->m_tables_file_size)10328{10329BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted (2)\n");10330return false;10331}10332if (pHeader->m_tables_file_ofs > data_size)10333{10334BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (4)\n");10335return false;10336}10337if (pHeader->m_tables_file_size > (data_size - pHeader->m_tables_file_ofs))10338{10339BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (5)\n");10340return false;10341}10342}10343else10344{10345if (!pHeader->m_endpoint_cb_file_size || !pHeader->m_selector_cb_file_size || !pHeader->m_tables_file_size)10346{10347BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted (0)\n");10348return false;10349}1035010351if ((pHeader->m_endpoint_cb_file_ofs > data_size) || (pHeader->m_selector_cb_file_ofs > data_size) || (pHeader->m_tables_file_ofs > data_size))10352{10353BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (1)\n");10354return false;10355}1035610357if (pHeader->m_endpoint_cb_file_size > (data_size - pHeader->m_endpoint_cb_file_ofs))10358{10359BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (2)\n");10360return false;10361}1036210363if (pHeader->m_selector_cb_file_size > (data_size - pHeader->m_selector_cb_file_ofs))10364{10365BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");10366return false;10367}1036810369if (pHeader->m_tables_file_size > (data_size - pHeader->m_tables_file_ofs))10370{10371BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: file is corrupted or passed in buffer too small (3)\n");10372return false;10373}1037410375if (!m_lowlevel_etc1s_decoder.decode_palettes(10376pHeader->m_total_endpoints, pDataU8 + pHeader->m_endpoint_cb_file_ofs, pHeader->m_endpoint_cb_file_size,10377pHeader->m_total_selectors, pDataU8 + pHeader->m_selector_cb_file_ofs, pHeader->m_selector_cb_file_size))10378{10379BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: decode_palettes failed\n");10380return false;10381}10382}1038310384if (!m_lowlevel_etc1s_decoder.decode_tables(pDataU8 + pHeader->m_tables_file_ofs, pHeader->m_tables_file_size))10385{10386BASISU_DEVEL_ERROR("basisu_transcoder::start_transcoding: decode_tables failed\n");10387return false;10388}10389}10390else10391{10392// Nothing special to do for UASTC.10393if (m_lowlevel_etc1s_decoder.m_local_endpoints.size())10394{10395m_lowlevel_etc1s_decoder.clear();10396}10397}1039810399m_ready_to_transcode = true;1040010401return true;10402}1040310404bool basisu_transcoder::stop_transcoding()10405{10406m_lowlevel_etc1s_decoder.clear();1040710408m_ready_to_transcode = false;1040910410return true;10411}1041210413bool basisu_transcoder::transcode_slice(const void* pData, uint32_t data_size, uint32_t slice_index, void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels, block_format fmt,10414uint32_t output_block_or_pixel_stride_in_bytes, uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state* pState, void *pAlpha_blocks, uint32_t output_rows_in_pixels, int channel0, int channel1) const10415{10416if (!m_ready_to_transcode)10417{10418BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: must call start_transcoding first\n");10419return false;10420}1042110422if (decode_flags & cDecodeFlagsPVRTCDecodeToNextPow2)10423{10424// TODO: Not yet supported10425BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: cDecodeFlagsPVRTCDecodeToNextPow2 currently unsupported\n");10426return false;10427}1042810429if (!validate_header_quick(pData, data_size))10430{10431BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: header validation failed\n");10432return false;10433}1043410435const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);1043610437const uint8_t* pDataU8 = static_cast<const uint8_t*>(pData);1043810439if (slice_index >= pHeader->m_total_slices)10440{10441BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: slice_index >= pHeader->m_total_slices\n");10442return false;10443}1044410445const basis_slice_desc& slice_desc = reinterpret_cast<const basis_slice_desc*>(pDataU8 + pHeader->m_slice_desc_file_ofs)[slice_index];1044610447uint32_t total_4x4_blocks = slice_desc.m_num_blocks_x * slice_desc.m_num_blocks_y;1044810449if (basis_block_format_is_uncompressed(fmt))10450{10451// Assume the output buffer is orig_width by orig_height10452if (!output_row_pitch_in_blocks_or_pixels)10453output_row_pitch_in_blocks_or_pixels = slice_desc.m_orig_width;1045410455if (!output_rows_in_pixels)10456output_rows_in_pixels = slice_desc.m_orig_height;1045710458// Now make sure the output buffer is large enough, or we'll overwrite memory.10459if (output_blocks_buf_size_in_blocks_or_pixels < (output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels))10460{10461BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: output_blocks_buf_size_in_blocks_or_pixels < (output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels)\n");10462return false;10463}10464}10465else if (fmt == block_format::cFXT1_RGB)10466{10467const uint32_t num_blocks_fxt1_x = (slice_desc.m_orig_width + 7) / 8;10468const uint32_t num_blocks_fxt1_y = (slice_desc.m_orig_height + 3) / 4;10469const uint32_t total_blocks_fxt1 = num_blocks_fxt1_x * num_blocks_fxt1_y;1047010471if (output_blocks_buf_size_in_blocks_or_pixels < total_blocks_fxt1)10472{10473BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: output_blocks_buf_size_in_blocks_or_pixels < total_blocks_fxt1\n");10474return false;10475}10476}10477else10478{10479if (output_blocks_buf_size_in_blocks_or_pixels < total_4x4_blocks)10480{10481BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: output_blocks_buf_size_in_blocks_or_pixels < total_blocks\n");10482return false;10483}10484}1048510486if (fmt != block_format::cETC1)10487{10488if ((fmt == block_format::cPVRTC1_4_RGB) || (fmt == block_format::cPVRTC1_4_RGBA))10489{10490if ((!basisu::is_pow2(slice_desc.m_num_blocks_x * 4)) || (!basisu::is_pow2(slice_desc.m_num_blocks_y * 4)))10491{10492// PVRTC1 only supports power of 2 dimensions10493BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: PVRTC1 only supports power of 2 dimensions\n");10494return false;10495}10496}10497}1049810499if (slice_desc.m_file_ofs > data_size)10500{10501BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: invalid slice_desc.m_file_ofs, or passed in buffer too small\n");10502return false;10503}1050410505const uint32_t data_size_left = data_size - slice_desc.m_file_ofs;10506if (data_size_left < slice_desc.m_file_size)10507{10508BASISU_DEVEL_ERROR("basisu_transcoder::transcode_slice: invalid slice_desc.m_file_size, or passed in buffer too small\n");10509return false;10510}1051110512if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4)10513{10514return m_lowlevel_uastc_decoder.transcode_slice(pOutput_blocks, slice_desc.m_num_blocks_x, slice_desc.m_num_blocks_y,10515pDataU8 + slice_desc.m_file_ofs, slice_desc.m_file_size,10516fmt, output_block_or_pixel_stride_in_bytes, (decode_flags & cDecodeFlagsBC1ForbidThreeColorBlocks) == 0, *pHeader, slice_desc, output_row_pitch_in_blocks_or_pixels, pState,10517output_rows_in_pixels, channel0, channel1, decode_flags);10518}10519else10520{10521return m_lowlevel_etc1s_decoder.transcode_slice(pOutput_blocks, slice_desc.m_num_blocks_x, slice_desc.m_num_blocks_y,10522pDataU8 + slice_desc.m_file_ofs, slice_desc.m_file_size,10523fmt, output_block_or_pixel_stride_in_bytes, (decode_flags & cDecodeFlagsBC1ForbidThreeColorBlocks) == 0, *pHeader, slice_desc, output_row_pitch_in_blocks_or_pixels, pState,10524(decode_flags & cDecodeFlagsOutputHasAlphaIndices) != 0, pAlpha_blocks, output_rows_in_pixels);10525}10526}1052710528int basisu_transcoder::find_first_slice_index(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index) const10529{10530BASISU_NOTE_UNUSED(data_size);1053110532const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);10533const uint8_t* pDataU8 = static_cast<const uint8_t*>(pData);1053410535// For very large basis files this search could be painful10536// TODO: Binary search this10537for (uint32_t slice_iter = 0; slice_iter < pHeader->m_total_slices; slice_iter++)10538{10539const basis_slice_desc& slice_desc = reinterpret_cast<const basis_slice_desc*>(pDataU8 + pHeader->m_slice_desc_file_ofs)[slice_iter];10540if ((slice_desc.m_image_index == image_index) && (slice_desc.m_level_index == level_index))10541return slice_iter;10542}1054310544BASISU_DEVEL_ERROR("basisu_transcoder::find_first_slice_index: didn't find slice\n");1054510546return -1;10547}1054810549int basisu_transcoder::find_slice(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, bool alpha_data) const10550{10551if (!validate_header_quick(pData, data_size))10552{10553BASISU_DEVEL_ERROR("basisu_transcoder::find_slice: header validation failed\n");10554return false;10555}1055610557const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);10558const uint8_t* pDataU8 = static_cast<const uint8_t*>(pData);10559const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(pDataU8 + pHeader->m_slice_desc_file_ofs);1056010561// For very large basis files this search could be painful10562// TODO: Binary search this10563for (uint32_t slice_iter = 0; slice_iter < pHeader->m_total_slices; slice_iter++)10564{10565const basis_slice_desc& slice_desc = pSlice_descs[slice_iter];10566if ((slice_desc.m_image_index == image_index) && (slice_desc.m_level_index == level_index))10567{10568if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)10569{10570const bool slice_alpha = (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0;10571if (slice_alpha == alpha_data)10572return slice_iter;10573}10574else10575{10576return slice_iter;10577}10578}10579}1058010581BASISU_DEVEL_ERROR("basisu_transcoder::find_slice: didn't find slice\n");1058210583return -1;10584}1058510586void basisu_transcoder::write_opaque_alpha_blocks(10587uint32_t num_blocks_x, uint32_t num_blocks_y,10588void* pOutput_blocks, block_format fmt,10589uint32_t block_stride_in_bytes, uint32_t output_row_pitch_in_blocks_or_pixels)10590{10591// 'num_blocks_y', 'pOutput_blocks' & 'block_stride_in_bytes' unused10592// when disabling BASISD_SUPPORT_ETC2_EAC_A8 *and* BASISD_SUPPORT_DXT5A10593BASISU_NOTE_UNUSED(num_blocks_y);10594BASISU_NOTE_UNUSED(pOutput_blocks);10595BASISU_NOTE_UNUSED(block_stride_in_bytes);1059610597if (!output_row_pitch_in_blocks_or_pixels)10598output_row_pitch_in_blocks_or_pixels = num_blocks_x;1059910600if ((fmt == block_format::cETC2_EAC_A8) || (fmt == block_format::cETC2_EAC_R11))10601{10602#if BASISD_SUPPORT_ETC2_EAC_A810603eac_block blk;10604blk.m_base = 255;10605blk.m_multiplier = 1;10606blk.m_table = 13;1060710608// Selectors are all 4's10609memcpy(&blk.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));1061010611for (uint32_t y = 0; y < num_blocks_y; y++)10612{10613uint32_t dst_ofs = y * output_row_pitch_in_blocks_or_pixels * block_stride_in_bytes;10614for (uint32_t x = 0; x < num_blocks_x; x++)10615{10616memcpy((uint8_t*)pOutput_blocks + dst_ofs, &blk, sizeof(blk));10617dst_ofs += block_stride_in_bytes;10618}10619}10620#endif10621}10622else if (fmt == block_format::cBC4)10623{10624#if BASISD_SUPPORT_DXT5A10625dxt5a_block blk;10626blk.m_endpoints[0] = 255;10627blk.m_endpoints[1] = 255;10628memset(blk.m_selectors, 0, sizeof(blk.m_selectors));1062910630for (uint32_t y = 0; y < num_blocks_y; y++)10631{10632uint32_t dst_ofs = y * output_row_pitch_in_blocks_or_pixels * block_stride_in_bytes;10633for (uint32_t x = 0; x < num_blocks_x; x++)10634{10635memcpy((uint8_t*)pOutput_blocks + dst_ofs, &blk, sizeof(blk));10636dst_ofs += block_stride_in_bytes;10637}10638}10639#endif10640}10641}1064210643bool basisu_transcoder::transcode_image_level(10644const void* pData, uint32_t data_size,10645uint32_t image_index, uint32_t level_index,10646void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,10647transcoder_texture_format fmt,10648uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state *pState, uint32_t output_rows_in_pixels) const10649{10650const uint32_t bytes_per_block_or_pixel = basis_get_bytes_per_block_or_pixel(fmt);1065110652if (!m_ready_to_transcode)10653{10654BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: must call start_transcoding() first\n");10655return false;10656}1065710658//const bool transcode_alpha_data_to_opaque_formats = (decode_flags & cDecodeFlagsTranscodeAlphaDataToOpaqueFormats) != 0;1065910660if (decode_flags & cDecodeFlagsPVRTCDecodeToNextPow2)10661{10662BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: cDecodeFlagsPVRTCDecodeToNextPow2 currently unsupported\n");10663// TODO: Not yet supported10664return false;10665}1066610667if (!validate_header_quick(pData, data_size))10668{10669BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: header validation failed\n");10670return false;10671}1067210673const basis_file_header* pHeader = reinterpret_cast<const basis_file_header*>(pData);1067410675const uint8_t* pDataU8 = static_cast<const uint8_t*>(pData);1067610677const basis_slice_desc* pSlice_descs = reinterpret_cast<const basis_slice_desc*>(pDataU8 + pHeader->m_slice_desc_file_ofs);1067810679const bool basis_file_has_alpha_slices = (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) != 0;1068010681int slice_index = find_first_slice_index(pData, data_size, image_index, level_index);10682if (slice_index < 0)10683{10684BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: failed finding slice index\n");10685// Unable to find the requested image/level10686return false;10687}1068810689if ((fmt == transcoder_texture_format::cTFPVRTC1_4_RGBA) && (!basis_file_has_alpha_slices))10690{10691// Switch to PVRTC1 RGB if the input doesn't have alpha.10692fmt = transcoder_texture_format::cTFPVRTC1_4_RGB;10693}1069410695if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S)10696{10697if (pSlice_descs[slice_index].m_flags & cSliceDescFlagsHasAlpha)10698{10699BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has out of order alpha slice\n");1070010701// The first slice shouldn't have alpha data in a properly formed basis file10702return false;10703}1070410705if (basis_file_has_alpha_slices)10706{10707// The alpha data should immediately follow the color data, and have the same resolution.10708if ((slice_index + 1U) >= pHeader->m_total_slices)10709{10710BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has missing alpha slice\n");10711// basis file is missing the alpha slice10712return false;10713}1071410715// Basic sanity checks10716if ((pSlice_descs[slice_index + 1].m_flags & cSliceDescFlagsHasAlpha) == 0)10717{10718BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file has missing alpha slice (flag check)\n");10719// This slice should have alpha data10720return false;10721}1072210723if ((pSlice_descs[slice_index].m_num_blocks_x != pSlice_descs[slice_index + 1].m_num_blocks_x) || (pSlice_descs[slice_index].m_num_blocks_y != pSlice_descs[slice_index + 1].m_num_blocks_y))10724{10725BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: alpha basis file slice dimensions bad\n");10726// Alpha slice should have been the same res as the color slice10727return false;10728}10729}10730}1073110732bool status = false;1073310734const uint32_t total_slice_blocks = pSlice_descs[slice_index].m_num_blocks_x * pSlice_descs[slice_index].m_num_blocks_y;1073510736if (((fmt == transcoder_texture_format::cTFPVRTC1_4_RGB) || (fmt == transcoder_texture_format::cTFPVRTC1_4_RGBA)) && (output_blocks_buf_size_in_blocks_or_pixels > total_slice_blocks))10737{10738// The transcoder doesn't write beyond total_slice_blocks, so we need to clear the rest ourselves.10739// For GL usage, PVRTC1 4bpp image size is (max(width, 8)* max(height, 8) * 4 + 7) / 8.10740// However, for KTX and internally in Basis this formula isn't used, it's just ((width+3)/4) * ((height+3)/4) * bytes_per_block_or_pixel. This is all the transcoder actually writes to memory.10741memset(static_cast<uint8_t*>(pOutput_blocks) + total_slice_blocks * bytes_per_block_or_pixel, 0, (output_blocks_buf_size_in_blocks_or_pixels - total_slice_blocks) * bytes_per_block_or_pixel);10742}1074310744if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4)10745{10746const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index];1074710748// Use the container independent image transcode method.10749status = m_lowlevel_uastc_decoder.transcode_image(fmt,10750pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels,10751(const uint8_t*)pData, data_size, pSlice_desc->m_num_blocks_x, pSlice_desc->m_num_blocks_y, pSlice_desc->m_orig_width, pSlice_desc->m_orig_height, pSlice_desc->m_level_index,10752pSlice_desc->m_file_ofs, pSlice_desc->m_file_size,10753decode_flags, basis_file_has_alpha_slices, pHeader->m_tex_type == cBASISTexTypeVideoFrames, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);10754}10755else10756{10757// ETC1S10758const basis_slice_desc* pSlice_desc = &pSlice_descs[slice_index];10759const basis_slice_desc* pAlpha_slice_desc = basis_file_has_alpha_slices ? &pSlice_descs[slice_index + 1] : nullptr;1076010761assert((pSlice_desc->m_flags & cSliceDescFlagsHasAlpha) == 0);1076210763if (pAlpha_slice_desc)10764{10765// Basic sanity checks10766assert((pAlpha_slice_desc->m_flags & cSliceDescFlagsHasAlpha) != 0);10767assert(pSlice_desc->m_num_blocks_x == pAlpha_slice_desc->m_num_blocks_x);10768assert(pSlice_desc->m_num_blocks_y == pAlpha_slice_desc->m_num_blocks_y);10769assert(pSlice_desc->m_level_index == pAlpha_slice_desc->m_level_index);10770}1077110772// Use the container independent image transcode method.10773status = m_lowlevel_etc1s_decoder.transcode_image(fmt,10774pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels,10775(const uint8_t *)pData, data_size, pSlice_desc->m_num_blocks_x, pSlice_desc->m_num_blocks_y, pSlice_desc->m_orig_width, pSlice_desc->m_orig_height, pSlice_desc->m_level_index,10776pSlice_desc->m_file_ofs, pSlice_desc->m_file_size,10777(pAlpha_slice_desc != nullptr) ? (uint32_t)pAlpha_slice_desc->m_file_ofs : 0U, (pAlpha_slice_desc != nullptr) ? (uint32_t)pAlpha_slice_desc->m_file_size : 0U,10778decode_flags, basis_file_has_alpha_slices, pHeader->m_tex_type == cBASISTexTypeVideoFrames, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels);1077910780} // if (pHeader->m_tex_format == (int)basis_tex_format::cUASTC4x4)1078110782if (!status)10783{10784BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning false\n");10785}10786else10787{10788//BASISU_DEVEL_ERROR("basisu_transcoder::transcode_image_level: Returning true\n");10789}1079010791return status;10792}1079310794uint32_t basis_get_bytes_per_block_or_pixel(transcoder_texture_format fmt)10795{10796switch (fmt)10797{10798case transcoder_texture_format::cTFETC1_RGB:10799case transcoder_texture_format::cTFBC1_RGB:10800case transcoder_texture_format::cTFBC4_R:10801case transcoder_texture_format::cTFPVRTC1_4_RGB:10802case transcoder_texture_format::cTFPVRTC1_4_RGBA:10803case transcoder_texture_format::cTFATC_RGB:10804case transcoder_texture_format::cTFPVRTC2_4_RGB:10805case transcoder_texture_format::cTFPVRTC2_4_RGBA:10806case transcoder_texture_format::cTFETC2_EAC_R11:10807return 8;10808case transcoder_texture_format::cTFBC7_RGBA:10809case transcoder_texture_format::cTFBC7_ALT:10810case transcoder_texture_format::cTFETC2_RGBA:10811case transcoder_texture_format::cTFBC3_RGBA:10812case transcoder_texture_format::cTFBC5_RG:10813case transcoder_texture_format::cTFASTC_4x4_RGBA:10814case transcoder_texture_format::cTFATC_RGBA:10815case transcoder_texture_format::cTFFXT1_RGB:10816case transcoder_texture_format::cTFETC2_EAC_RG11:10817return 16;10818case transcoder_texture_format::cTFRGBA32:10819return sizeof(uint32_t);10820case transcoder_texture_format::cTFRGB565:10821case transcoder_texture_format::cTFBGR565:10822case transcoder_texture_format::cTFRGBA4444:10823return sizeof(uint16_t);10824default:10825assert(0);10826BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");10827break;10828}10829return 0;10830}1083110832const char* basis_get_format_name(transcoder_texture_format fmt)10833{10834switch (fmt)10835{10836case transcoder_texture_format::cTFETC1_RGB: return "ETC1_RGB";10837case transcoder_texture_format::cTFBC1_RGB: return "BC1_RGB";10838case transcoder_texture_format::cTFBC4_R: return "BC4_R";10839case transcoder_texture_format::cTFPVRTC1_4_RGB: return "PVRTC1_4_RGB";10840case transcoder_texture_format::cTFPVRTC1_4_RGBA: return "PVRTC1_4_RGBA";10841case transcoder_texture_format::cTFBC7_RGBA: return "BC7_RGBA";10842case transcoder_texture_format::cTFBC7_ALT: return "BC7_RGBA";10843case transcoder_texture_format::cTFETC2_RGBA: return "ETC2_RGBA";10844case transcoder_texture_format::cTFBC3_RGBA: return "BC3_RGBA";10845case transcoder_texture_format::cTFBC5_RG: return "BC5_RG";10846case transcoder_texture_format::cTFASTC_4x4_RGBA: return "ASTC_RGBA";10847case transcoder_texture_format::cTFATC_RGB: return "ATC_RGB";10848case transcoder_texture_format::cTFATC_RGBA: return "ATC_RGBA";10849case transcoder_texture_format::cTFRGBA32: return "RGBA32";10850case transcoder_texture_format::cTFRGB565: return "RGB565";10851case transcoder_texture_format::cTFBGR565: return "BGR565";10852case transcoder_texture_format::cTFRGBA4444: return "RGBA4444";10853case transcoder_texture_format::cTFFXT1_RGB: return "FXT1_RGB";10854case transcoder_texture_format::cTFPVRTC2_4_RGB: return "PVRTC2_4_RGB";10855case transcoder_texture_format::cTFPVRTC2_4_RGBA: return "PVRTC2_4_RGBA";10856case transcoder_texture_format::cTFETC2_EAC_R11: return "ETC2_EAC_R11";10857case transcoder_texture_format::cTFETC2_EAC_RG11: return "ETC2_EAC_RG11";10858default:10859assert(0);10860BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");10861break;10862}10863return "";10864}1086510866const char* basis_get_block_format_name(block_format fmt)10867{10868switch (fmt)10869{10870case block_format::cETC1: return "ETC1";10871case block_format::cBC1: return "BC1";10872case block_format::cPVRTC1_4_RGB: return "PVRTC1_4_RGB";10873case block_format::cPVRTC1_4_RGBA: return "PVRTC1_4_RGBA";10874case block_format::cBC7: return "BC7";10875case block_format::cETC2_RGBA: return "ETC2_RGBA";10876case block_format::cBC3: return "BC3";10877case block_format::cASTC_4x4: return "ASTC_4x4";10878case block_format::cATC_RGB: return "ATC_RGB";10879case block_format::cRGBA32: return "RGBA32";10880case block_format::cRGB565: return "RGB565";10881case block_format::cBGR565: return "BGR565";10882case block_format::cRGBA4444: return "RGBA4444";10883case block_format::cUASTC_4x4: return "UASTC_4x4";10884case block_format::cFXT1_RGB: return "FXT1_RGB";10885case block_format::cPVRTC2_4_RGB: return "PVRTC2_4_RGB";10886case block_format::cPVRTC2_4_RGBA: return "PVRTC2_4_RGBA";10887case block_format::cETC2_EAC_R11: return "ETC2_EAC_R11";10888case block_format::cETC2_EAC_RG11: return "ETC2_EAC_RG11";10889default:10890assert(0);10891BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");10892break;10893}10894return "";10895}1089610897const char* basis_get_texture_type_name(basis_texture_type tex_type)10898{10899switch (tex_type)10900{10901case cBASISTexType2D: return "2D";10902case cBASISTexType2DArray: return "2D array";10903case cBASISTexTypeCubemapArray: return "cubemap array";10904case cBASISTexTypeVideoFrames: return "video";10905case cBASISTexTypeVolume: return "3D";10906default:10907assert(0);10908BASISU_DEVEL_ERROR("basis_get_texture_type_name: Invalid tex_type\n");10909break;10910}10911return "";10912}1091310914bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt)10915{10916switch (fmt)10917{10918case transcoder_texture_format::cTFETC2_RGBA:10919case transcoder_texture_format::cTFBC3_RGBA:10920case transcoder_texture_format::cTFASTC_4x4_RGBA:10921case transcoder_texture_format::cTFBC7_RGBA:10922case transcoder_texture_format::cTFBC7_ALT:10923case transcoder_texture_format::cTFPVRTC1_4_RGBA:10924case transcoder_texture_format::cTFPVRTC2_4_RGBA:10925case transcoder_texture_format::cTFATC_RGBA:10926case transcoder_texture_format::cTFRGBA32:10927case transcoder_texture_format::cTFRGBA4444:10928return true;10929default:10930break;10931}10932return false;10933}1093410935basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt)10936{10937switch (fmt)10938{10939case transcoder_texture_format::cTFETC1_RGB: return basisu::texture_format::cETC1;10940case transcoder_texture_format::cTFBC1_RGB: return basisu::texture_format::cBC1;10941case transcoder_texture_format::cTFBC4_R: return basisu::texture_format::cBC4;10942case transcoder_texture_format::cTFPVRTC1_4_RGB: return basisu::texture_format::cPVRTC1_4_RGB;10943case transcoder_texture_format::cTFPVRTC1_4_RGBA: return basisu::texture_format::cPVRTC1_4_RGBA;10944case transcoder_texture_format::cTFBC7_RGBA: return basisu::texture_format::cBC7;10945case transcoder_texture_format::cTFBC7_ALT: return basisu::texture_format::cBC7;10946case transcoder_texture_format::cTFETC2_RGBA: return basisu::texture_format::cETC2_RGBA;10947case transcoder_texture_format::cTFBC3_RGBA: return basisu::texture_format::cBC3;10948case transcoder_texture_format::cTFBC5_RG: return basisu::texture_format::cBC5;10949case transcoder_texture_format::cTFASTC_4x4_RGBA: return basisu::texture_format::cASTC4x4;10950case transcoder_texture_format::cTFATC_RGB: return basisu::texture_format::cATC_RGB;10951case transcoder_texture_format::cTFATC_RGBA: return basisu::texture_format::cATC_RGBA_INTERPOLATED_ALPHA;10952case transcoder_texture_format::cTFRGBA32: return basisu::texture_format::cRGBA32;10953case transcoder_texture_format::cTFRGB565: return basisu::texture_format::cRGB565;10954case transcoder_texture_format::cTFBGR565: return basisu::texture_format::cBGR565;10955case transcoder_texture_format::cTFRGBA4444: return basisu::texture_format::cRGBA4444;10956case transcoder_texture_format::cTFFXT1_RGB: return basisu::texture_format::cFXT1_RGB;10957case transcoder_texture_format::cTFPVRTC2_4_RGB: return basisu::texture_format::cPVRTC2_4_RGBA;10958case transcoder_texture_format::cTFPVRTC2_4_RGBA: return basisu::texture_format::cPVRTC2_4_RGBA;10959case transcoder_texture_format::cTFETC2_EAC_R11: return basisu::texture_format::cETC2_R11_EAC;10960case transcoder_texture_format::cTFETC2_EAC_RG11: return basisu::texture_format::cETC2_RG11_EAC;10961default:10962assert(0);10963BASISU_DEVEL_ERROR("basis_get_basisu_texture_format: Invalid fmt\n");10964break;10965}10966return basisu::texture_format::cInvalidTextureFormat;10967}1096810969bool basis_transcoder_format_is_uncompressed(transcoder_texture_format tex_type)10970{10971switch (tex_type)10972{10973case transcoder_texture_format::cTFRGBA32:10974case transcoder_texture_format::cTFRGB565:10975case transcoder_texture_format::cTFBGR565:10976case transcoder_texture_format::cTFRGBA4444:10977return true;10978default:10979break;10980}10981return false;10982}1098310984bool basis_block_format_is_uncompressed(block_format blk_fmt)10985{10986switch (blk_fmt)10987{10988case block_format::cRGB32:10989case block_format::cRGBA32:10990case block_format::cA32:10991case block_format::cRGB565:10992case block_format::cBGR565:10993case block_format::cRGBA4444:10994case block_format::cRGBA4444_COLOR:10995case block_format::cRGBA4444_ALPHA:10996case block_format::cRGBA4444_COLOR_OPAQUE:10997return true;10998default:10999break;11000}11001return false;11002}1100311004uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt)11005{11006switch (fmt)11007{11008case transcoder_texture_format::cTFRGBA32:11009return sizeof(uint32_t);11010case transcoder_texture_format::cTFRGB565:11011case transcoder_texture_format::cTFBGR565:11012case transcoder_texture_format::cTFRGBA4444:11013return sizeof(uint16_t);11014default:11015break;11016}11017return 0;11018}1101911020uint32_t basis_get_block_width(transcoder_texture_format tex_type)11021{11022switch (tex_type)11023{11024case transcoder_texture_format::cTFFXT1_RGB:11025return 8;11026default:11027break;11028}11029return 4;11030}1103111032uint32_t basis_get_block_height(transcoder_texture_format tex_type)11033{11034BASISU_NOTE_UNUSED(tex_type);11035return 4;11036}1103711038bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt)11039{11040if (fmt == basis_tex_format::cUASTC4x4)11041{11042#if BASISD_SUPPORT_UASTC11043switch (tex_type)11044{11045// These niche formats aren't currently supported for UASTC - everything else is.11046case transcoder_texture_format::cTFPVRTC2_4_RGB:11047case transcoder_texture_format::cTFPVRTC2_4_RGBA:11048case transcoder_texture_format::cTFATC_RGB:11049case transcoder_texture_format::cTFATC_RGBA:11050case transcoder_texture_format::cTFFXT1_RGB:11051return false;11052default:11053return true;11054}11055#endif11056}11057else11058{11059switch (tex_type)11060{11061// ETC1 and uncompressed are always supported.11062case transcoder_texture_format::cTFETC1_RGB:11063case transcoder_texture_format::cTFRGBA32:11064case transcoder_texture_format::cTFRGB565:11065case transcoder_texture_format::cTFBGR565:11066case transcoder_texture_format::cTFRGBA4444:11067return true;11068#if BASISD_SUPPORT_DXT111069case transcoder_texture_format::cTFBC1_RGB:11070return true;11071#endif11072#if BASISD_SUPPORT_DXT5A11073case transcoder_texture_format::cTFBC4_R:11074case transcoder_texture_format::cTFBC5_RG:11075return true;11076#endif11077#if BASISD_SUPPORT_DXT1 && BASISD_SUPPORT_DXT5A11078case transcoder_texture_format::cTFBC3_RGBA:11079return true;11080#endif11081#if BASISD_SUPPORT_PVRTC111082case transcoder_texture_format::cTFPVRTC1_4_RGB:11083case transcoder_texture_format::cTFPVRTC1_4_RGBA:11084return true;11085#endif11086#if BASISD_SUPPORT_BC7_MODE511087case transcoder_texture_format::cTFBC7_RGBA:11088case transcoder_texture_format::cTFBC7_ALT:11089return true;11090#endif11091#if BASISD_SUPPORT_ETC2_EAC_A811092case transcoder_texture_format::cTFETC2_RGBA:11093return true;11094#endif11095#if BASISD_SUPPORT_ASTC11096case transcoder_texture_format::cTFASTC_4x4_RGBA:11097return true;11098#endif11099#if BASISD_SUPPORT_ATC11100case transcoder_texture_format::cTFATC_RGB:11101case transcoder_texture_format::cTFATC_RGBA:11102return true;11103#endif11104#if BASISD_SUPPORT_FXT111105case transcoder_texture_format::cTFFXT1_RGB:11106return true;11107#endif11108#if BASISD_SUPPORT_PVRTC211109case transcoder_texture_format::cTFPVRTC2_4_RGB:11110case transcoder_texture_format::cTFPVRTC2_4_RGBA:11111return true;11112#endif11113#if BASISD_SUPPORT_ETC2_EAC_RG1111114case transcoder_texture_format::cTFETC2_EAC_R11:11115case transcoder_texture_format::cTFETC2_EAC_RG11:11116return true;11117#endif11118default:11119break;11120}11121}1112211123return false;11124}1112511126// ------------------------------------------------------------------------------------------------------11127// UASTC11128// ------------------------------------------------------------------------------------------------------1112911130#if BASISD_SUPPORT_UASTC11131const astc_bc7_common_partition2_desc g_astc_bc7_common_partitions2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2] =11132{11133{ 0, 28, false }, { 1, 20, false }, { 2, 16, true }, { 3, 29, false },11134{ 4, 91, true }, { 5, 9, false }, { 6, 107, true }, { 7, 72, true },11135{ 8, 149, false }, { 9, 204, true }, { 10, 50, false }, { 11, 114, true },11136{ 12, 496, true }, { 13, 17, true }, { 14, 78, false }, { 15, 39, true },11137{ 17, 252, true }, { 18, 828, true }, { 19, 43, false }, { 20, 156, false },11138{ 21, 116, false }, { 22, 210, true }, { 23, 476, true }, { 24, 273, false },11139{ 25, 684, true }, { 26, 359, false }, { 29, 246, true }, { 32, 195, true },11140{ 33, 694, true }, { 52, 524, true }11141};1114211143const bc73_astc2_common_partition_desc g_bc7_3_astc2_common_partitions[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS] =11144{11145{ 10, 36, 4 }, { 11, 48, 4 }, { 0, 61, 3 }, { 2, 137, 4 },11146{ 8, 161, 5 }, { 13, 183, 4 }, { 1, 226, 2 }, { 33, 281, 2 },11147{ 40, 302, 3 }, { 20, 307, 4 }, { 21, 479, 0 }, { 58, 495, 3 },11148{ 3, 593, 0 }, { 32, 594, 2 }, { 59, 605, 1 }, { 34, 799, 3 },11149{ 20, 812, 1 }, { 14, 988, 4 }, { 31, 993, 3 }11150};1115111152const astc_bc7_common_partition3_desc g_astc_bc7_common_partitions3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3] =11153{11154{ 4, 260, 0 }, { 8, 74, 5 }, { 9, 32, 5 }, { 10, 156, 2 },11155{ 11, 183, 2 }, { 12, 15, 0 }, { 13, 745, 4 }, { 20, 0, 1 },11156{ 35, 335, 1 }, { 36, 902, 5 }, { 57, 254, 0 }11157};1115811159const uint8_t g_astc_to_bc7_partition_index_perm_tables[6][3] = { { 0, 1, 2 }, { 1, 2, 0 }, { 2, 0, 1 }, { 2, 1, 0 }, { 0, 2, 1 }, { 1, 0, 2 } };1116011161const uint8_t g_bc7_to_astc_partition_index_perm_tables[6][3] = { { 0, 1, 2 }, { 2, 0, 1 }, { 1, 2, 0 }, { 2, 1, 0 }, { 0, 2, 1 }, { 1, 0, 2 } };1116211163uint32_t bc7_convert_partition_index_3_to_2(uint32_t p, uint32_t k)11164{11165assert(k < 6);11166switch (k >> 1)11167{11168case 0:11169if (p <= 1)11170p = 0;11171else11172p = 1;11173break;11174case 1:11175if (p == 0)11176p = 0;11177else11178p = 1;11179break;11180case 2:11181if ((p == 0) || (p == 2))11182p = 0;11183else11184p = 1;11185break;11186}11187if (k & 1)11188p = 1 - p;11189return p;11190}1119111192static const uint8_t g_zero_pattern[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };1119311194const uint8_t g_astc_bc7_patterns2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][16] =11195{11196{ 0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1 }, { 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1 }, { 1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0 }, { 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1 },11197{ 1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,0 }, { 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1 }, { 1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0 }, { 1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,0 },11198{ 0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1 }, { 1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0 },11199{ 1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0 }, { 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0 },11200{ 1,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,1 }, { 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0 }, { 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0 },11201{ 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0 }, { 1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1 }, { 1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,0 }, { 0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0 },11202{ 1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1 }, { 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0 }, { 1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1 }, { 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0 },11203{ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0 }, { 1,0,0,1,0,0,1,1,0,1,1,0,1,1,0,0 }11204};1120511206const uint8_t g_astc_bc7_patterns3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][16] =11207{11208{ 0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2 }, { 1,1,1,1,1,1,1,1,0,0,0,0,2,2,2,2 }, { 1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2 }, { 1,1,1,1,2,2,2,2,0,0,0,0,0,0,0,0 },11209{ 1,1,2,0,1,1,2,0,1,1,2,0,1,1,2,0 }, { 0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2 }, { 0,2,1,1,0,2,1,1,0,2,1,1,0,2,1,1 }, { 2,0,0,0,2,0,0,0,2,1,1,1,2,1,1,1 },11210{ 2,0,1,2,2,0,1,2,2,0,1,2,2,0,1,2 }, { 1,1,1,1,0,0,0,0,2,2,2,2,1,1,1,1 }, { 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2 }11211};1121211213const uint8_t g_bc7_3_astc2_patterns2[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][16] =11214{11215{ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0 }, { 1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,1,1,0,0,1,1 },11216{ 1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1 }, { 0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0 }, { 0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1 }, { 0,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1 },11217{ 1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0 }, { 0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,0 }, { 1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0 },11218{ 0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, { 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0 }, { 1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0 },11219{ 1,1,1,1,1,1,1,1,1,0,0,0,1,0,0,0 }, { 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0 }, { 1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0 }11220};1122111222const uint8_t g_astc_bc7_pattern2_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][3] =11223{11224{ 0, 2 }, { 0, 3 }, { 1, 0 }, { 0, 3 }, { 7, 0 }, { 0, 2 }, { 3, 0 }, { 7, 0 },11225{ 0, 11 }, { 2, 0 }, { 0, 7 }, { 11, 0 }, { 3, 0 }, { 8, 0 }, { 0, 4 }, { 12, 0 },11226{ 1, 0 }, { 8, 0 }, { 0, 1 }, { 0, 2 }, { 0, 4 }, { 8, 0 }, { 1, 0 }, { 0, 2 },11227{ 4, 0 }, { 0, 1 }, { 4, 0 }, { 1, 0 }, { 4, 0 }, { 1, 0 }11228};1122911230const uint8_t g_astc_bc7_pattern3_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][3] =11231{11232{ 0, 8, 10 }, { 8, 0, 12 }, { 4, 0, 12 }, { 8, 0, 4 }, { 3, 0, 2 }, { 0, 1, 3 }, { 0, 2, 1 }, { 1, 9, 0 }, { 1, 2, 0 }, { 4, 0, 8 }, { 0, 6, 2 }11233};1123411235const uint8_t g_bc7_3_astc2_patterns2_anchors[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][3] =11236{11237{ 0, 4 }, { 0, 2 }, { 2, 0 }, { 0, 7 }, { 8, 0 }, { 0, 1 }, { 0, 3 }, { 0, 1 }, { 2, 0 }, { 0, 1 }, { 0, 8 }, { 2, 0 }, { 0, 1 }, { 0, 7 }, { 12, 0 }, { 2, 0 }, { 9, 0 }, { 0, 2 }, { 4, 0 }11238};1123911240const uint32_t g_uastc_mode_huff_codes[TOTAL_UASTC_MODES + 1][2] =11241{11242{ 0x1, 4 },11243{ 0x35, 6 },11244{ 0x1D, 5 },11245{ 0x3, 5 },1124611247{ 0x13, 5 },11248{ 0xB, 5 },11249{ 0x1B, 5 },11250{ 0x7, 5 },1125111252{ 0x17, 5 },11253{ 0xF, 5 },11254{ 0x2, 3 },11255{ 0x0, 2 },1125611257{ 0x6, 3 },11258{ 0x1F, 5 },11259{ 0xD, 5 },11260{ 0x5, 7 },1126111262{ 0x15, 6 },11263{ 0x25, 6 },11264{ 0x9, 4 },11265{ 0x45, 7 } // future expansion11266};1126711268// If g_uastc_mode_huff_codes[] changes this table must be updated!11269static const uint8_t g_uastc_huff_modes[128] =11270{1127111,0,10,3,11,15,12,7,11,18,10,5,11,14,12,9,11,0,10,4,11,16,12,8,11,18,10,6,11,2,12,13,11,0,10,3,11,17,12,7,11,18,10,5,11,14,12,9,11,0,10,4,11,1,12,8,11,18,10,6,11,2,12,13,11,0,10,3,11,1127219,12,7,11,18,10,5,11,14,12,9,11,0,10,4,11,16,12,8,11,18,10,6,11,2,12,13,11,0,10,3,11,17,12,7,11,18,10,5,11,14,12,9,11,0,10,4,11,1,12,8,11,18,10,6,11,2,12,1311273};1127411275const uint8_t g_uastc_mode_weight_bits[TOTAL_UASTC_MODES] = { 4, 2, 3, 2, 2, 3, 2, 2, 0, 2, 4, 2, 3, 1, 2, 4, 2, 2, 5 };11276const uint8_t g_uastc_mode_weight_ranges[TOTAL_UASTC_MODES] = { 8, 2, 5, 2, 2, 5, 2, 2, 0, 2, 8, 2, 5, 0, 2, 8, 2, 2, 11 };11277const uint8_t g_uastc_mode_endpoint_ranges[TOTAL_UASTC_MODES] = { 19, 20, 8, 7, 12, 20, 18, 12, 0, 8, 13, 13, 19, 20, 20, 20, 20, 20, 11 };11278const uint8_t g_uastc_mode_subsets[TOTAL_UASTC_MODES] = { 1, 1, 2, 3, 2, 1, 1, 2, 0, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1 };11279const uint8_t g_uastc_mode_planes[TOTAL_UASTC_MODES] = { 1, 1, 1, 1, 1, 1, 2, 1, 0, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1 };11280const uint8_t g_uastc_mode_comps[TOTAL_UASTC_MODES] = { 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 3 };11281const uint8_t g_uastc_mode_has_etc1_bias[TOTAL_UASTC_MODES] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 };11282const uint8_t g_uastc_mode_has_bc1_hint0[TOTAL_UASTC_MODES] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };11283const uint8_t g_uastc_mode_has_bc1_hint1[TOTAL_UASTC_MODES] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 };11284const uint8_t g_uastc_mode_cem[TOTAL_UASTC_MODES] = { 8, 8, 8, 8, 8, 8, 8, 8, 0, 12, 12, 12, 12, 12, 12, 4, 4, 4, 8 };11285const uint8_t g_uastc_mode_has_alpha[TOTAL_UASTC_MODES] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 };11286const uint8_t g_uastc_mode_is_la[TOTAL_UASTC_MODES] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0 };11287const uint8_t g_uastc_mode_total_hint_bits[TOTAL_UASTC_MODES] = { 15, 15, 15, 15, 15, 15, 15, 15, 0, 23, 17, 17, 17, 23, 23, 23, 23, 23, 15 };1128811289// bits, trits, quints11290const int g_astc_bise_range_table[TOTAL_ASTC_RANGES][3] =11291{11292{ 1, 0, 0 }, // 0-1 011293{ 0, 1, 0 }, // 0-2 111294{ 2, 0, 0 }, // 0-3 211295{ 0, 0, 1 }, // 0-4 31129611297{ 1, 1, 0 }, // 0-5 411298{ 3, 0, 0 }, // 0-7 511299{ 1, 0, 1 }, // 0-9 611300{ 2, 1, 0 }, // 0-11 71130111302{ 4, 0, 0 }, // 0-15 811303{ 2, 0, 1 }, // 0-19 911304{ 3, 1, 0 }, // 0-23 1011305{ 5, 0, 0 }, // 0-31 111130611307{ 3, 0, 1 }, // 0-39 1211308{ 4, 1, 0 }, // 0-47 1311309{ 6, 0, 0 }, // 0-63 1411310{ 4, 0, 1 }, // 0-79 151131111312{ 5, 1, 0 }, // 0-95 1611313{ 7, 0, 0 }, // 0-127 1711314{ 5, 0, 1 }, // 0-159 1811315{ 6, 1, 0 }, // 0-191 191131611317{ 8, 0, 0 }, // 0-255 2011318};1131911320int astc_get_levels(int range)11321{11322assert(range < (int)BC7ENC_TOTAL_ASTC_RANGES);11323return (1 + 2 * g_astc_bise_range_table[range][1] + 4 * g_astc_bise_range_table[range][2]) << g_astc_bise_range_table[range][0];11324}1132511326// g_astc_unquant[] is the inverse of g_astc_sorted_order_unquant[]11327astc_quant_bin g_astc_unquant[BC7ENC_TOTAL_ASTC_RANGES][256]; // [ASTC encoded endpoint index]1132811329// Taken right from the ASTC spec.11330static struct11331{11332const char* m_pB_str;11333uint32_t m_c;11334} g_astc_endpoint_unquant_params[BC7ENC_TOTAL_ASTC_RANGES] =11335{11336{ "", 0 },11337{ "", 0 },11338{ "", 0 },11339{ "", 0 },11340{ "000000000", 204, }, // 0-511341{ "", 0 },11342{ "000000000", 113, }, // 0-911343{ "b000b0bb0", 93 }, // 0-1111344{ "", 0 },11345{ "b0000bb00", 54 }, // 0-1911346{ "cb000cbcb", 44 }, // 0-2311347{ "", 0 },11348{ "cb0000cbc", 26 }, // 0-3911349{ "dcb000dcb", 22 }, // 0-4711350{ "", 0 },11351{ "dcb0000dc", 13 }, // 0-7911352{ "edcb000ed", 11 }, // 0-9511353{ "", 0 },11354{ "edcb0000e", 6 }, // 0-15911355{ "fedcb000f", 5 }, // 0-19111356{ "", 0 },11357};1135811359bool astc_is_valid_endpoint_range(uint32_t range)11360{11361if ((g_astc_bise_range_table[range][1] == 0) && (g_astc_bise_range_table[range][2] == 0))11362return true;1136311364return g_astc_endpoint_unquant_params[range].m_c != 0;11365}1136611367uint32_t unquant_astc_endpoint(uint32_t packed_bits, uint32_t packed_trits, uint32_t packed_quints, uint32_t range)11368{11369assert(range < BC7ENC_TOTAL_ASTC_RANGES);1137011371const uint32_t bits = g_astc_bise_range_table[range][0];11372const uint32_t trits = g_astc_bise_range_table[range][1];11373const uint32_t quints = g_astc_bise_range_table[range][2];1137411375uint32_t val = 0;11376if ((!trits) && (!quints))11377{11378assert(!packed_trits && !packed_quints);1137911380int bits_left = 8;11381while (bits_left > 0)11382{11383uint32_t v = packed_bits;1138411385int n = basisu::minimumi(bits_left, bits);11386if (n < (int)bits)11387v >>= (bits - n);1138811389assert(v < (1U << n));1139011391val |= (v << (bits_left - n));11392bits_left -= n;11393}11394}11395else11396{11397const uint32_t A = (packed_bits & 1) ? 511 : 0;11398const uint32_t C = g_astc_endpoint_unquant_params[range].m_c;11399const uint32_t D = trits ? packed_trits : packed_quints;1140011401assert(C);1140211403uint32_t B = 0;11404for (uint32_t i = 0; i < 9; i++)11405{11406B <<= 1;1140711408char c = g_astc_endpoint_unquant_params[range].m_pB_str[i];11409if (c != '0')11410{11411c -= 'a';11412B |= ((packed_bits >> c) & 1);11413}11414}1141511416val = D * C + B;11417val = val ^ A;11418val = (A & 0x80) | (val >> 2);11419}1142011421return val;11422}1142311424uint32_t unquant_astc_endpoint_val(uint32_t packed_val, uint32_t range)11425{11426assert(range < BC7ENC_TOTAL_ASTC_RANGES);11427assert(packed_val < (uint32_t)astc_get_levels(range));1142811429const uint32_t bits = g_astc_bise_range_table[range][0];11430const uint32_t trits = g_astc_bise_range_table[range][1];11431const uint32_t quints = g_astc_bise_range_table[range][2];1143211433if ((!trits) && (!quints))11434return unquant_astc_endpoint(packed_val, 0, 0, range);11435else if (trits)11436return unquant_astc_endpoint(packed_val & ((1 << bits) - 1), packed_val >> bits, 0, range);11437else11438return unquant_astc_endpoint(packed_val & ((1 << bits) - 1), 0, packed_val >> bits, range);11439}1144011441// BC7 - Various BC7 tables/helpers11442const uint32_t g_bc7_weights1[2] = { 0, 64 };11443const uint32_t g_bc7_weights2[4] = { 0, 21, 43, 64 };11444const uint32_t g_bc7_weights3[8] = { 0, 9, 18, 27, 37, 46, 55, 64 };11445const uint32_t g_bc7_weights4[16] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };11446const uint32_t g_astc_weights4[16] = { 0, 4, 8, 12, 17, 21, 25, 29, 35, 39, 43, 47, 52, 56, 60, 64 };11447const uint32_t g_astc_weights5[32] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64 };11448const uint32_t g_astc_weights_3levels[3] = { 0, 32, 64 };1144911450const uint8_t g_bc7_partition1[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };1145111452const uint8_t g_bc7_partition2[64 * 16] =11453{114540,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, 0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, 0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1, 0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,114550,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1, 0,0,0,1,0,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,114560,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1, 0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0, 0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0, 0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0, 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,114570,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0, 0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0, 0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, 0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0, 0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0, 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, 0,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0, 0,0,1,1,1,0,0,1,1,0,0,1,1,1,0,0,114580,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, 0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1, 0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0, 0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0, 0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0, 0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0, 0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1, 0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1,114590,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0, 0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0, 0,0,1,1,0,0,1,0,0,1,0,0,1,1,0,0, 0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0, 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 0,0,1,1,1,1,0,0,1,1,0,0,0,0,1,1, 0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1, 0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,114600,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0, 0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0, 0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0, 0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0, 0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,1, 0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,1,0,0,1,1,1,0,0, 0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0,114610,1,1,0,1,1,0,0,1,1,0,0,1,0,0,1, 0,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1, 0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1, 0,0,0,1,1,0,0,0,1,1,1,0,0,1,1,1, 0,0,0,0,1,1,1,1,0,0,1,1,0,0,1,1, 0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0, 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0, 0,1,0,0,0,1,0,0,0,1,1,1,0,1,1,111462};1146311464const uint8_t g_bc7_partition3[64 * 16] =11465{114660,0,1,1,0,0,1,1,0,2,2,1,2,2,2,2, 0,0,0,1,0,0,1,1,2,2,1,1,2,2,2,1, 0,0,0,0,2,0,0,1,2,2,1,1,2,2,1,1, 0,2,2,2,0,0,2,2,0,0,1,1,0,1,1,1, 0,0,0,0,0,0,0,0,1,1,2,2,1,1,2,2, 0,0,1,1,0,0,1,1,0,0,2,2,0,0,2,2, 0,0,2,2,0,0,2,2,1,1,1,1,1,1,1,1, 0,0,1,1,0,0,1,1,2,2,1,1,2,2,1,1,114670,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2, 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2, 0,0,1,2,0,0,1,2,0,0,1,2,0,0,1,2, 0,1,1,2,0,1,1,2,0,1,1,2,0,1,1,2, 0,1,2,2,0,1,2,2,0,1,2,2,0,1,2,2, 0,0,1,1,0,1,1,2,1,1,2,2,1,2,2,2, 0,0,1,1,2,0,0,1,2,2,0,0,2,2,2,0,114680,0,0,1,0,0,1,1,0,1,1,2,1,1,2,2, 0,1,1,1,0,0,1,1,2,0,0,1,2,2,0,0, 0,0,0,0,1,1,2,2,1,1,2,2,1,1,2,2, 0,0,2,2,0,0,2,2,0,0,2,2,1,1,1,1, 0,1,1,1,0,1,1,1,0,2,2,2,0,2,2,2, 0,0,0,1,0,0,0,1,2,2,2,1,2,2,2,1, 0,0,0,0,0,0,1,1,0,1,2,2,0,1,2,2, 0,0,0,0,1,1,0,0,2,2,1,0,2,2,1,0,114690,1,2,2,0,1,2,2,0,0,1,1,0,0,0,0, 0,0,1,2,0,0,1,2,1,1,2,2,2,2,2,2, 0,1,1,0,1,2,2,1,1,2,2,1,0,1,1,0, 0,0,0,0,0,1,1,0,1,2,2,1,1,2,2,1, 0,0,2,2,1,1,0,2,1,1,0,2,0,0,2,2, 0,1,1,0,0,1,1,0,2,0,0,2,2,2,2,2, 0,0,1,1,0,1,2,2,0,1,2,2,0,0,1,1, 0,0,0,0,2,0,0,0,2,2,1,1,2,2,2,1,114700,0,0,0,0,0,0,2,1,1,2,2,1,2,2,2, 0,2,2,2,0,0,2,2,0,0,1,2,0,0,1,1, 0,0,1,1,0,0,1,2,0,0,2,2,0,2,2,2, 0,1,2,0,0,1,2,0,0,1,2,0,0,1,2,0, 0,0,0,0,1,1,1,1,2,2,2,2,0,0,0,0, 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0, 0,1,2,0,2,0,1,2,1,2,0,1,0,1,2,0, 0,0,1,1,2,2,0,0,1,1,2,2,0,0,1,1,114710,0,1,1,1,1,2,2,2,2,0,0,0,0,1,1, 0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,2,1,2,1,2,1, 0,0,2,2,1,1,2,2,0,0,2,2,1,1,2,2, 0,0,2,2,0,0,1,1,0,0,2,2,0,0,1,1, 0,2,2,0,1,2,2,1,0,2,2,0,1,2,2,1, 0,1,0,1,2,2,2,2,2,2,2,2,0,1,0,1, 0,0,0,0,2,1,2,1,2,1,2,1,2,1,2,1,114720,1,0,1,0,1,0,1,0,1,0,1,2,2,2,2, 0,2,2,2,0,1,1,1,0,2,2,2,0,1,1,1, 0,0,0,2,1,1,1,2,0,0,0,2,1,1,1,2, 0,0,0,0,2,1,1,2,2,1,1,2,2,1,1,2, 0,2,2,2,0,1,1,1,0,1,1,1,0,2,2,2, 0,0,0,2,1,1,1,2,1,1,1,2,0,0,0,2, 0,1,1,0,0,1,1,0,0,1,1,0,2,2,2,2, 0,0,0,0,0,0,0,0,2,1,1,2,2,1,1,2,114730,1,1,0,0,1,1,0,2,2,2,2,2,2,2,2, 0,0,2,2,0,0,1,1,0,0,1,1,0,0,2,2, 0,0,2,2,1,1,2,2,1,1,2,2,0,0,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,2, 0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,1, 0,2,2,2,1,2,2,2,0,2,2,2,1,2,2,2, 0,1,0,1,2,2,2,2,2,2,2,2,2,2,2,2, 0,1,1,1,2,0,1,1,2,2,0,1,2,2,2,0,11474};1147511476const uint8_t g_bc7_table_anchor_index_second_subset[64] = { 15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15, 15, 2, 8, 2, 2, 8, 8,15, 2, 8, 2, 2, 8, 8, 2, 2, 15,15, 6, 8, 2, 8,15,15, 2, 8, 2, 2, 2,15,15, 6, 6, 2, 6, 8,15,15, 2, 2, 15,15,15,15,15, 2, 2,15 };1147711478const uint8_t g_bc7_table_anchor_index_third_subset_1[64] =11479{114803, 3,15,15, 8, 3,15,15, 8, 8, 6, 6, 6, 5, 3, 3, 3, 3, 8,15, 3, 3, 6,10, 5, 8, 8, 6, 8, 5,15,15, 8,15, 3, 5, 6,10, 8,15, 15, 3,15, 5,15,15,15,15, 3,15, 5, 5, 5, 8, 5,10, 5,10, 8,13,15,12, 3, 311481};1148211483const uint8_t g_bc7_table_anchor_index_third_subset_2[64] =11484{1148515, 8, 8, 3,15,15, 3, 8, 15,15,15,15,15,15,15, 8, 15, 8,15, 3,15, 8,15, 8, 3,15, 6,10,15,15,10, 8, 15, 3,15,10,10, 8, 9,10, 6,15, 8,15, 3, 6, 6, 8, 15, 3,15,15,15,15,15,15, 15,15,15,15, 3,15,15, 811486};1148711488const uint8_t g_bc7_num_subsets[8] = { 3, 2, 3, 2, 1, 1, 1, 2 };11489const uint8_t g_bc7_partition_bits[8] = { 4, 6, 6, 6, 0, 0, 0, 6 };11490const uint8_t g_bc7_color_index_bitcount[8] = { 3, 3, 2, 2, 2, 2, 4, 2 };1149111492const uint8_t g_bc7_mode_has_p_bits[8] = { 1, 1, 0, 1, 0, 0, 1, 1 };11493const uint8_t g_bc7_mode_has_shared_p_bits[8] = { 0, 1, 0, 0, 0, 0, 0, 0 };11494const uint8_t g_bc7_color_precision_table[8] = { 4, 6, 5, 7, 5, 7, 7, 5 };11495const int8_t g_bc7_alpha_precision_table[8] = { 0, 0, 0, 0, 6, 8, 7, 5 };1149611497const uint8_t g_bc7_alpha_index_bitcount[8] = { 0, 0, 0, 0, 3, 2, 4, 2 };1149811499endpoint_err g_bc7_mode_6_optimal_endpoints[256][2]; // [c][pbit]11500endpoint_err g_bc7_mode_5_optimal_endpoints[256]; // [c]1150111502static inline void bc7_set_block_bits(uint8_t* pBytes, uint32_t val, uint32_t num_bits, uint32_t* pCur_ofs)11503{11504assert((num_bits <= 32) && (val < (1ULL << num_bits)));11505while (num_bits)11506{11507const uint32_t n = basisu::minimumu(8 - (*pCur_ofs & 7), num_bits);11508pBytes[*pCur_ofs >> 3] |= (uint8_t)(val << (*pCur_ofs & 7));11509val >>= n;11510num_bits -= n;11511*pCur_ofs += n;11512}11513assert(*pCur_ofs <= 128);11514}1151511516// TODO: Optimize this.11517void encode_bc7_block(void* pBlock, const bc7_optimization_results* pResults)11518{11519const uint32_t best_mode = pResults->m_mode;1152011521const uint32_t total_subsets = g_bc7_num_subsets[best_mode];11522const uint32_t total_partitions = 1 << g_bc7_partition_bits[best_mode];11523//const uint32_t num_rotations = 1 << g_bc7_rotation_bits[best_mode];11524//const uint32_t num_index_selectors = (best_mode == 4) ? 2 : 1;1152511526const uint8_t* pPartition;11527if (total_subsets == 1)11528pPartition = &g_bc7_partition1[0];11529else if (total_subsets == 2)11530pPartition = &g_bc7_partition2[pResults->m_partition * 16];11531else11532pPartition = &g_bc7_partition3[pResults->m_partition * 16];1153311534uint8_t color_selectors[16];11535memcpy(color_selectors, pResults->m_selectors, 16);1153611537uint8_t alpha_selectors[16];11538memcpy(alpha_selectors, pResults->m_alpha_selectors, 16);1153911540color_quad_u8 low[3], high[3];11541memcpy(low, pResults->m_low, sizeof(low));11542memcpy(high, pResults->m_high, sizeof(high));1154311544uint32_t pbits[3][2];11545memcpy(pbits, pResults->m_pbits, sizeof(pbits));1154611547int anchor[3] = { -1, -1, -1 };1154811549for (uint32_t k = 0; k < total_subsets; k++)11550{11551uint32_t anchor_index = 0;11552if (k)11553{11554if ((total_subsets == 3) && (k == 1))11555anchor_index = g_bc7_table_anchor_index_third_subset_1[pResults->m_partition];11556else if ((total_subsets == 3) && (k == 2))11557anchor_index = g_bc7_table_anchor_index_third_subset_2[pResults->m_partition];11558else11559anchor_index = g_bc7_table_anchor_index_second_subset[pResults->m_partition];11560}1156111562anchor[k] = anchor_index;1156311564const uint32_t color_index_bits = get_bc7_color_index_size(best_mode, pResults->m_index_selector);11565const uint32_t num_color_indices = 1 << color_index_bits;1156611567if (color_selectors[anchor_index] & (num_color_indices >> 1))11568{11569for (uint32_t i = 0; i < 16; i++)11570if (pPartition[i] == k)11571color_selectors[i] = (uint8_t)((num_color_indices - 1) - color_selectors[i]);1157211573if (get_bc7_mode_has_seperate_alpha_selectors(best_mode))11574{11575for (uint32_t q = 0; q < 3; q++)11576{11577uint8_t t = low[k].m_c[q];11578low[k].m_c[q] = high[k].m_c[q];11579high[k].m_c[q] = t;11580}11581}11582else11583{11584color_quad_u8 tmp = low[k];11585low[k] = high[k];11586high[k] = tmp;11587}1158811589if (!g_bc7_mode_has_shared_p_bits[best_mode])11590{11591uint32_t t = pbits[k][0];11592pbits[k][0] = pbits[k][1];11593pbits[k][1] = t;11594}11595}1159611597if (get_bc7_mode_has_seperate_alpha_selectors(best_mode))11598{11599const uint32_t alpha_index_bits = get_bc7_alpha_index_size(best_mode, pResults->m_index_selector);11600const uint32_t num_alpha_indices = 1 << alpha_index_bits;1160111602if (alpha_selectors[anchor_index] & (num_alpha_indices >> 1))11603{11604for (uint32_t i = 0; i < 16; i++)11605if (pPartition[i] == k)11606alpha_selectors[i] = (uint8_t)((num_alpha_indices - 1) - alpha_selectors[i]);1160711608uint8_t t = low[k].m_c[3];11609low[k].m_c[3] = high[k].m_c[3];11610high[k].m_c[3] = t;11611}11612}11613}1161411615uint8_t* pBlock_bytes = (uint8_t*)(pBlock);11616memset(pBlock_bytes, 0, BC7ENC_BLOCK_SIZE);1161711618uint32_t cur_bit_ofs = 0;11619bc7_set_block_bits(pBlock_bytes, 1 << best_mode, best_mode + 1, &cur_bit_ofs);1162011621if ((best_mode == 4) || (best_mode == 5))11622bc7_set_block_bits(pBlock_bytes, pResults->m_rotation, 2, &cur_bit_ofs);1162311624if (best_mode == 4)11625bc7_set_block_bits(pBlock_bytes, pResults->m_index_selector, 1, &cur_bit_ofs);1162611627if (total_partitions > 1)11628bc7_set_block_bits(pBlock_bytes, pResults->m_partition, (total_partitions == 64) ? 6 : 4, &cur_bit_ofs);1162911630const uint32_t total_comps = (best_mode >= 4) ? 4 : 3;11631for (uint32_t comp = 0; comp < total_comps; comp++)11632{11633for (uint32_t subset = 0; subset < total_subsets; subset++)11634{11635bc7_set_block_bits(pBlock_bytes, low[subset].m_c[comp], (comp == 3) ? g_bc7_alpha_precision_table[best_mode] : g_bc7_color_precision_table[best_mode], &cur_bit_ofs);11636bc7_set_block_bits(pBlock_bytes, high[subset].m_c[comp], (comp == 3) ? g_bc7_alpha_precision_table[best_mode] : g_bc7_color_precision_table[best_mode], &cur_bit_ofs);11637}11638}1163911640if (g_bc7_mode_has_p_bits[best_mode])11641{11642for (uint32_t subset = 0; subset < total_subsets; subset++)11643{11644bc7_set_block_bits(pBlock_bytes, pbits[subset][0], 1, &cur_bit_ofs);11645if (!g_bc7_mode_has_shared_p_bits[best_mode])11646bc7_set_block_bits(pBlock_bytes, pbits[subset][1], 1, &cur_bit_ofs);11647}11648}1164911650for (uint32_t y = 0; y < 4; y++)11651{11652for (uint32_t x = 0; x < 4; x++)11653{11654int idx = x + y * 4;1165511656uint32_t n = pResults->m_index_selector ? get_bc7_alpha_index_size(best_mode, pResults->m_index_selector) : get_bc7_color_index_size(best_mode, pResults->m_index_selector);1165711658if ((idx == anchor[0]) || (idx == anchor[1]) || (idx == anchor[2]))11659n--;1166011661bc7_set_block_bits(pBlock_bytes, pResults->m_index_selector ? alpha_selectors[idx] : color_selectors[idx], n, &cur_bit_ofs);11662}11663}1166411665if (get_bc7_mode_has_seperate_alpha_selectors(best_mode))11666{11667for (uint32_t y = 0; y < 4; y++)11668{11669for (uint32_t x = 0; x < 4; x++)11670{11671int idx = x + y * 4;1167211673uint32_t n = pResults->m_index_selector ? get_bc7_color_index_size(best_mode, pResults->m_index_selector) : get_bc7_alpha_index_size(best_mode, pResults->m_index_selector);1167411675if ((idx == anchor[0]) || (idx == anchor[1]) || (idx == anchor[2]))11676n--;1167711678bc7_set_block_bits(pBlock_bytes, pResults->m_index_selector ? color_selectors[idx] : alpha_selectors[idx], n, &cur_bit_ofs);11679}11680}11681}1168211683assert(cur_bit_ofs == 128);11684}1168511686// ASTC11687static inline void astc_set_bits_1_to_9(uint32_t* pDst, int& bit_offset, uint32_t code, uint32_t codesize)11688{11689uint8_t* pBuf = reinterpret_cast<uint8_t*>(pDst);1169011691assert(codesize <= 9);11692if (codesize)11693{11694uint32_t byte_bit_offset = bit_offset & 7;11695uint32_t val = code << byte_bit_offset;1169611697uint32_t index = bit_offset >> 3;11698pBuf[index] |= (uint8_t)val;1169911700if (codesize > (8 - byte_bit_offset))11701pBuf[index + 1] |= (uint8_t)(val >> 8);1170211703bit_offset += codesize;11704}11705}1170611707void pack_astc_solid_block(void* pDst_block, const color32& color)11708{11709uint32_t r = color[0], g = color[1], b = color[2];11710uint32_t a = color[3];1171111712uint32_t* pOutput = static_cast<uint32_t*>(pDst_block);11713uint8_t* pBytes = reinterpret_cast<uint8_t*>(pDst_block);1171411715pBytes[0] = 0xfc; pBytes[1] = 0xfd; pBytes[2] = 0xff; pBytes[3] = 0xff;1171611717pOutput[1] = 0xffffffff;11718pOutput[2] = 0;11719pOutput[3] = 0;1172011721int bit_pos = 64;11722astc_set_bits(reinterpret_cast<uint32_t*>(pDst_block), bit_pos, r | (r << 8), 16);11723astc_set_bits(reinterpret_cast<uint32_t*>(pDst_block), bit_pos, g | (g << 8), 16);11724astc_set_bits(reinterpret_cast<uint32_t*>(pDst_block), bit_pos, b | (b << 8), 16);11725astc_set_bits(reinterpret_cast<uint32_t*>(pDst_block), bit_pos, a | (a << 8), 16);11726}1172711728// See 23.21 https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.inline.html#_partition_pattern_generation11729#ifdef _DEBUG11730static inline uint32_t astc_hash52(uint32_t v)11731{11732uint32_t p = v;11733p ^= p >> 15; p -= p << 17; p += p << 7; p += p << 4;11734p ^= p >> 5; p += p << 16; p ^= p >> 7; p ^= p >> 3;11735p ^= p << 6; p ^= p >> 17;11736return p;11737}1173811739int astc_compute_texel_partition(int seed, int x, int y, int z, int partitioncount, bool small_block)11740{11741if (small_block)11742{11743x <<= 1; y <<= 1; z <<= 1;11744}11745seed += (partitioncount - 1) * 1024;11746uint32_t rnum = astc_hash52(seed);11747uint8_t seed1 = rnum & 0xF;11748uint8_t seed2 = (rnum >> 4) & 0xF;11749uint8_t seed3 = (rnum >> 8) & 0xF;11750uint8_t seed4 = (rnum >> 12) & 0xF;11751uint8_t seed5 = (rnum >> 16) & 0xF;11752uint8_t seed6 = (rnum >> 20) & 0xF;11753uint8_t seed7 = (rnum >> 24) & 0xF;11754uint8_t seed8 = (rnum >> 28) & 0xF;11755uint8_t seed9 = (rnum >> 18) & 0xF;11756uint8_t seed10 = (rnum >> 22) & 0xF;11757uint8_t seed11 = (rnum >> 26) & 0xF;11758uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF;1175911760seed1 *= seed1; seed2 *= seed2;11761seed3 *= seed3; seed4 *= seed4;11762seed5 *= seed5; seed6 *= seed6;11763seed7 *= seed7; seed8 *= seed8;11764seed9 *= seed9; seed10 *= seed10;11765seed11 *= seed11; seed12 *= seed12;1176611767int sh1, sh2, sh3;11768if (seed & 1)11769{11770sh1 = (seed & 2 ? 4 : 5); sh2 = (partitioncount == 3 ? 6 : 5);11771}11772else11773{11774sh1 = (partitioncount == 3 ? 6 : 5); sh2 = (seed & 2 ? 4 : 5);11775}11776sh3 = (seed & 0x10) ? sh1 : sh2;1177711778seed1 >>= sh1; seed2 >>= sh2; seed3 >>= sh1; seed4 >>= sh2;11779seed5 >>= sh1; seed6 >>= sh2; seed7 >>= sh1; seed8 >>= sh2;11780seed9 >>= sh3; seed10 >>= sh3; seed11 >>= sh3; seed12 >>= sh3;1178111782int a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);11783int b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);11784int c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);11785int d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);1178611787a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F;1178811789if (partitioncount < 4) d = 0;11790if (partitioncount < 3) c = 0;1179111792if (a >= b && a >= c && a >= d)11793return 0;11794else if (b >= c && b >= d)11795return 1;11796else if (c >= d)11797return 2;11798else11799return 3;11800}11801#endif1180211803static const uint8_t g_astc_quint_encode[125] =11804{118050, 1, 2, 3, 4, 8, 9, 10, 11, 12, 16, 17, 18, 19, 20, 24, 25, 26, 27, 28, 5, 13, 21, 29, 6, 32, 33, 34, 35, 36, 40, 41, 42, 43, 44, 48, 49, 50, 51, 52, 56, 57,1180658, 59, 60, 37, 45, 53, 61, 14, 64, 65, 66, 67, 68, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 88, 89, 90, 91, 92, 69, 77, 85, 93, 22, 96, 97, 98, 99, 100, 104,11807105, 106, 107, 108, 112, 113, 114, 115, 116, 120, 121, 122, 123, 124, 101, 109, 117, 125, 30, 102, 103, 70, 71, 38, 110, 111, 78, 79, 46, 118, 119, 86, 87, 54,11808126, 127, 94, 95, 62, 39, 47, 55, 63, 3111809};1181011811// Encodes 3 values to output, usable for any range that uses quints and bits11812static inline void astc_encode_quints(uint32_t* pOutput, const uint8_t* pValues, int& bit_pos, int n)11813{11814// First extract the trits and the bits from the 5 input values11815int quints = 0, bits[3];11816const uint32_t bit_mask = (1 << n) - 1;11817for (int i = 0; i < 3; i++)11818{11819static const int s_muls[3] = { 1, 5, 25 };1182011821const int t = pValues[i] >> n;1182211823quints += t * s_muls[i];11824bits[i] = pValues[i] & bit_mask;11825}1182611827// Encode the quints, by inverting the bit manipulations done by the decoder, converting 3 quints into 7-bits.11828// See https://www.khronos.org/registry/DataFormat/specs/1.2/dataformat.1.2.html#astc-integer-sequence-encoding1182911830assert(quints < 125);11831const int T = g_astc_quint_encode[quints];1183211833// Now interleave the 7 encoded quint bits with the bits to form the encoded output. See table 95-96.11834astc_set_bits(pOutput, bit_pos, bits[0] | (astc_extract_bits(T, 0, 2) << n) | (bits[1] << (3 + n)) | (astc_extract_bits(T, 3, 4) << (3 + n * 2)) |11835(bits[2] << (5 + n * 2)) | (astc_extract_bits(T, 5, 6) << (5 + n * 3)), 7 + n * 3);11836}1183711838// Packs values using ASTC's BISE to output buffer.11839static void astc_pack_bise(uint32_t* pDst, const uint8_t* pSrc_vals, int bit_pos, int num_vals, int range)11840{11841uint32_t temp[5] = { 0, 0, 0, 0, 0 };1184211843const int num_bits = g_astc_bise_range_table[range][0];1184411845int group_size = 0;11846if (g_astc_bise_range_table[range][1])11847group_size = 5;11848else if (g_astc_bise_range_table[range][2])11849group_size = 3;1185011851if (group_size)11852{11853// Range has trits or quints - pack each group of 5 or 3 values11854const int total_groups = (group_size == 5) ? ((num_vals + 4) / 5) : ((num_vals + 2) / 3);1185511856for (int group_index = 0; group_index < total_groups; group_index++)11857{11858uint8_t vals[5] = { 0, 0, 0, 0, 0 };1185911860const int limit = basisu::minimum(group_size, num_vals - group_index * group_size);11861for (int i = 0; i < limit; i++)11862vals[i] = pSrc_vals[group_index * group_size + i];1186311864if (group_size == 5)11865astc_encode_trits(temp, vals, bit_pos, num_bits);11866else11867astc_encode_quints(temp, vals, bit_pos, num_bits);11868}11869}11870else11871{11872for (int i = 0; i < num_vals; i++)11873astc_set_bits_1_to_9(temp, bit_pos, pSrc_vals[i], num_bits);11874}1187511876pDst[0] |= temp[0]; pDst[1] |= temp[1];11877pDst[2] |= temp[2]; pDst[3] |= temp[3];11878}1187911880const uint32_t ASTC_BLOCK_MODE_BITS = 11;11881const uint32_t ASTC_PART_BITS = 2;11882const uint32_t ASTC_CEM_BITS = 4;11883const uint32_t ASTC_PARTITION_INDEX_BITS = 10;11884const uint32_t ASTC_CCS_BITS = 2;1188511886const uint32_t g_uastc_mode_astc_block_mode[TOTAL_UASTC_MODES] = { 0x242, 0x42, 0x53, 0x42, 0x42, 0x53, 0x442, 0x42, 0, 0x42, 0x242, 0x442, 0x53, 0x441, 0x42, 0x242, 0x42, 0x442, 0x253 };1188711888bool pack_astc_block(uint32_t* pDst, const astc_block_desc* pBlock, uint32_t uastc_mode)11889{11890assert(uastc_mode < TOTAL_UASTC_MODES);11891uint8_t* pDst_bytes = reinterpret_cast<uint8_t*>(pDst);1189211893const int total_weights = pBlock->m_dual_plane ? 32 : 16;1189411895// Set mode bits - see Table 146-14711896uint32_t mode = g_uastc_mode_astc_block_mode[uastc_mode];11897pDst_bytes[0] = (uint8_t)mode;11898pDst_bytes[1] = (uint8_t)(mode >> 8);1189911900memset(pDst_bytes + 2, 0, 16 - 2);1190111902int bit_pos = ASTC_BLOCK_MODE_BITS;1190311904// We only support 1-5 bit weight indices11905assert(!g_astc_bise_range_table[pBlock->m_weight_range][1] && !g_astc_bise_range_table[pBlock->m_weight_range][2]);11906const int bits_per_weight = g_astc_bise_range_table[pBlock->m_weight_range][0];1190711908// See table 143 - PART11909astc_set_bits_1_to_9(pDst, bit_pos, pBlock->m_subsets - 1, ASTC_PART_BITS);1191011911if (pBlock->m_subsets == 1)11912astc_set_bits_1_to_9(pDst, bit_pos, pBlock->m_cem, ASTC_CEM_BITS);11913else11914{11915// See table 14511916astc_set_bits(pDst, bit_pos, pBlock->m_partition_seed, ASTC_PARTITION_INDEX_BITS);1191711918// Table 150 - we assume all CEM's are equal, so write 2 0's along with the CEM11919astc_set_bits_1_to_9(pDst, bit_pos, (pBlock->m_cem << 2) & 63, ASTC_CEM_BITS + 2);11920}1192111922if (pBlock->m_dual_plane)11923{11924const int total_weight_bits = total_weights * bits_per_weight;1192511926// See Illegal Encodings 23.2411927// https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.inline.html#_illegal_encodings11928assert((total_weight_bits >= 24) && (total_weight_bits <= 96));1192911930int ccs_bit_pos = 128 - total_weight_bits - ASTC_CCS_BITS;11931astc_set_bits_1_to_9(pDst, ccs_bit_pos, pBlock->m_ccs, ASTC_CCS_BITS);11932}1193311934const int num_cem_pairs = (1 + (pBlock->m_cem >> 2)) * pBlock->m_subsets;11935assert(num_cem_pairs <= 9);1193611937astc_pack_bise(pDst, pBlock->m_endpoints, bit_pos, num_cem_pairs * 2, g_uastc_mode_endpoint_ranges[uastc_mode]);1193811939// Write the weight bits in reverse bit order.11940switch (bits_per_weight)11941{11942case 1:11943{11944const uint32_t N = 1;11945for (int i = 0; i < total_weights; i++)11946{11947const uint32_t ofs = 128 - N - i;11948assert((ofs >> 3) < 16);11949pDst_bytes[ofs >> 3] |= (pBlock->m_weights[i] << (ofs & 7));11950}11951break;11952}11953case 2:11954{11955const uint32_t N = 2;11956for (int i = 0; i < total_weights; i++)11957{11958static const uint8_t s_reverse_bits2[4] = { 0, 2, 1, 3 };11959const uint32_t ofs = 128 - N - (i * N);11960assert((ofs >> 3) < 16);11961pDst_bytes[ofs >> 3] |= (s_reverse_bits2[pBlock->m_weights[i]] << (ofs & 7));11962}11963break;11964}11965case 3:11966{11967const uint32_t N = 3;11968for (int i = 0; i < total_weights; i++)11969{11970static const uint8_t s_reverse_bits3[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };1197111972const uint32_t ofs = 128 - N - (i * N);11973const uint32_t rev = s_reverse_bits3[pBlock->m_weights[i]] << (ofs & 7);1197411975uint32_t index = ofs >> 3;11976assert(index < 16);11977pDst_bytes[index++] |= rev & 0xFF;11978if (index < 16)11979pDst_bytes[index++] |= (rev >> 8);11980}11981break;11982}11983case 4:11984{11985const uint32_t N = 4;11986for (int i = 0; i < total_weights; i++)11987{11988static const uint8_t s_reverse_bits4[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };11989const int ofs = 128 - N - (i * N);11990assert(ofs >= 0 && (ofs >> 3) < 16);11991pDst_bytes[ofs >> 3] |= (s_reverse_bits4[pBlock->m_weights[i]] << (ofs & 7));11992}11993break;11994}11995case 5:11996{11997const uint32_t N = 5;11998for (int i = 0; i < total_weights; i++)11999{12000static const uint8_t s_reverse_bits5[32] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };1200112002const uint32_t ofs = 128 - N - (i * N);12003const uint32_t rev = s_reverse_bits5[pBlock->m_weights[i]] << (ofs & 7);1200412005uint32_t index = ofs >> 3;12006assert(index < 16);12007pDst_bytes[index++] |= rev & 0xFF;12008if (index < 16)12009pDst_bytes[index++] |= (rev >> 8);12010}1201112012break;12013}12014default:12015assert(0);12016break;12017}1201812019return true;12020}1202112022const uint8_t* get_anchor_indices(uint32_t subsets, uint32_t mode, uint32_t common_pattern, const uint8_t*& pPartition_pattern)12023{12024const uint8_t* pSubset_anchor_indices = g_zero_pattern;12025pPartition_pattern = g_zero_pattern;1202612027if (subsets >= 2)12028{12029if (subsets == 3)12030{12031pPartition_pattern = &g_astc_bc7_patterns3[common_pattern][0];12032pSubset_anchor_indices = &g_astc_bc7_pattern3_anchors[common_pattern][0];12033}12034else if (mode == 7)12035{12036pPartition_pattern = &g_bc7_3_astc2_patterns2[common_pattern][0];12037pSubset_anchor_indices = &g_bc7_3_astc2_patterns2_anchors[common_pattern][0];12038}12039else12040{12041pPartition_pattern = &g_astc_bc7_patterns2[common_pattern][0];12042pSubset_anchor_indices = &g_astc_bc7_pattern2_anchors[common_pattern][0];12043}12044}1204512046return pSubset_anchor_indices;12047}1204812049static inline uint32_t read_bit(const uint8_t* pBuf, uint32_t& bit_offset)12050{12051uint32_t byte_bits = pBuf[bit_offset >> 3] >> (bit_offset & 7);12052bit_offset += 1;12053return byte_bits & 1;12054}1205512056static inline uint32_t read_bits1_to_9(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)12057{12058assert(codesize <= 9);12059if (!codesize)12060return 0;1206112062if ((BASISD_IS_BIG_ENDIAN) || (!BASISD_USE_UNALIGNED_WORD_READS) || (bit_offset >= 112))12063{12064const uint8_t* pBytes = &pBuf[bit_offset >> 3U];1206512066uint32_t byte_bit_offset = bit_offset & 7U;1206712068uint32_t bits = pBytes[0] >> byte_bit_offset;12069uint32_t bits_read = basisu::minimum<int>(codesize, 8 - byte_bit_offset);1207012071uint32_t bits_remaining = codesize - bits_read;12072if (bits_remaining)12073bits |= ((uint32_t)pBytes[1]) << bits_read;1207412075bit_offset += codesize;1207612077return bits & ((1U << codesize) - 1U);12078}1207912080uint32_t byte_bit_offset = bit_offset & 7U;12081const uint16_t w = *(const uint16_t *)(&pBuf[bit_offset >> 3U]);12082bit_offset += codesize;12083return (w >> byte_bit_offset) & ((1U << codesize) - 1U);12084}1208512086inline uint64_t read_bits64(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)12087{12088assert(codesize <= 64U);12089uint64_t bits = 0;12090uint32_t total_bits = 0;1209112092while (total_bits < codesize)12093{12094uint32_t byte_bit_offset = bit_offset & 7U;12095uint32_t bits_to_read = basisu::minimum<int>(codesize - total_bits, 8U - byte_bit_offset);1209612097uint32_t byte_bits = pBuf[bit_offset >> 3U] >> byte_bit_offset;12098byte_bits &= ((1U << bits_to_read) - 1U);1209912100bits |= ((uint64_t)(byte_bits) << total_bits);1210112102total_bits += bits_to_read;12103bit_offset += bits_to_read;12104}1210512106return bits;12107}1210812109static inline uint32_t read_bits1_to_9_fst(const uint8_t* pBuf, uint32_t& bit_offset, uint32_t codesize)12110{12111assert(codesize <= 9);12112if (!codesize)12113return 0;12114assert(bit_offset < 112);1211512116if ((BASISD_IS_BIG_ENDIAN) || (!BASISD_USE_UNALIGNED_WORD_READS))12117{12118const uint8_t* pBytes = &pBuf[bit_offset >> 3U];1211912120uint32_t byte_bit_offset = bit_offset & 7U;1212112122uint32_t bits = pBytes[0] >> byte_bit_offset;12123uint32_t bits_read = basisu::minimum<int>(codesize, 8 - byte_bit_offset);1212412125uint32_t bits_remaining = codesize - bits_read;12126if (bits_remaining)12127bits |= ((uint32_t)pBytes[1]) << bits_read;1212812129bit_offset += codesize;1213012131return bits & ((1U << codesize) - 1U);12132}1213312134uint32_t byte_bit_offset = bit_offset & 7U;12135const uint16_t w = *(const uint16_t*)(&pBuf[bit_offset >> 3U]);12136bit_offset += codesize;12137return (w >> byte_bit_offset)& ((1U << codesize) - 1U);12138}1213912140bool unpack_uastc(const uastc_block& blk, unpacked_uastc_block& unpacked, bool blue_contract_check, bool read_hints)12141{12142//memset(&unpacked, 0, sizeof(unpacked));1214312144#if 012145uint8_t table[128];12146memset(table, 0xFF, sizeof(table));1214712148{12149for (uint32_t mode = 0; mode <= TOTAL_UASTC_MODES; mode++)12150{12151const uint32_t code = g_uastc_mode_huff_codes[mode][0];12152const uint32_t codesize = g_uastc_mode_huff_codes[mode][1];1215312154table[code] = mode;1215512156uint32_t bits_left = 7 - codesize;12157for (uint32_t i = 0; i < (1 << bits_left); i++)12158table[code | (i << codesize)] = mode;12159}1216012161for (uint32_t i = 0; i < 128; i++)12162printf("%u,", table[i]);12163exit(0);12164}12165#endif1216612167const int mode = g_uastc_huff_modes[blk.m_bytes[0] & 127];12168if (mode >= (int)TOTAL_UASTC_MODES)12169return false;1217012171unpacked.m_mode = mode;1217212173uint32_t bit_ofs = g_uastc_mode_huff_codes[mode][1];1217412175if (mode == UASTC_MODE_INDEX_SOLID_COLOR)12176{12177unpacked.m_solid_color.r = (uint8_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);12178unpacked.m_solid_color.g = (uint8_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);12179unpacked.m_solid_color.b = (uint8_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);12180unpacked.m_solid_color.a = (uint8_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);1218112182if (read_hints)12183{12184unpacked.m_etc1_flip = false;12185unpacked.m_etc1_diff = read_bit(blk.m_bytes, bit_ofs) != 0;12186unpacked.m_etc1_inten0 = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 3);12187unpacked.m_etc1_inten1 = 0;12188unpacked.m_etc1_selector = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 2);12189unpacked.m_etc1_r = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);12190unpacked.m_etc1_g = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);12191unpacked.m_etc1_b = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);12192unpacked.m_etc1_bias = 0;12193unpacked.m_etc2_hints = 0;12194}1219512196return true;12197}1219812199if (read_hints)12200{12201if (g_uastc_mode_has_bc1_hint0[mode])12202unpacked.m_bc1_hint0 = read_bit(blk.m_bytes, bit_ofs) != 0;12203else12204unpacked.m_bc1_hint0 = false;1220512206if (g_uastc_mode_has_bc1_hint1[mode])12207unpacked.m_bc1_hint1 = read_bit(blk.m_bytes, bit_ofs) != 0;12208else12209unpacked.m_bc1_hint1 = false;1221012211unpacked.m_etc1_flip = read_bit(blk.m_bytes, bit_ofs) != 0;12212unpacked.m_etc1_diff = read_bit(blk.m_bytes, bit_ofs) != 0;12213unpacked.m_etc1_inten0 = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 3);12214unpacked.m_etc1_inten1 = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 3);1221512216if (g_uastc_mode_has_etc1_bias[mode])12217unpacked.m_etc1_bias = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);12218else12219unpacked.m_etc1_bias = 0;1222012221if (g_uastc_mode_has_alpha[mode])12222{12223unpacked.m_etc2_hints = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 8);12224//assert(unpacked.m_etc2_hints > 0);12225}12226else12227unpacked.m_etc2_hints = 0;12228}12229else12230bit_ofs += g_uastc_mode_total_hint_bits[mode];1223112232uint32_t subsets = 1;12233switch (mode)12234{12235case 2:12236case 4:12237case 7:12238case 9:12239case 16:12240unpacked.m_common_pattern = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 5);12241subsets = 2;12242break;12243case 3:12244unpacked.m_common_pattern = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 4);12245subsets = 3;12246break;12247default:12248break;12249}1225012251uint32_t part_seed = 0;12252switch (mode)12253{12254case 2:12255case 4:12256case 9:12257case 16:12258if (unpacked.m_common_pattern >= TOTAL_ASTC_BC7_COMMON_PARTITIONS2)12259return false;1226012261part_seed = g_astc_bc7_common_partitions2[unpacked.m_common_pattern].m_astc;12262break;12263case 3:12264if (unpacked.m_common_pattern >= TOTAL_ASTC_BC7_COMMON_PARTITIONS3)12265return false;1226612267part_seed = g_astc_bc7_common_partitions3[unpacked.m_common_pattern].m_astc;12268break;12269case 7:12270if (unpacked.m_common_pattern >= TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS)12271return false;1227212273part_seed = g_bc7_3_astc2_common_partitions[unpacked.m_common_pattern].m_astc2;12274break;12275default:12276break;12277}1227812279uint32_t total_planes = 1;12280switch (mode)12281{12282case 6:12283case 11:12284case 13:12285unpacked.m_astc.m_ccs = (int)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, 2);12286total_planes = 2;12287break;12288case 17:12289unpacked.m_astc.m_ccs = 3;12290total_planes = 2;12291break;12292default:12293break;12294}1229512296unpacked.m_astc.m_dual_plane = (total_planes == 2);1229712298unpacked.m_astc.m_subsets = subsets;12299unpacked.m_astc.m_partition_seed = part_seed;1230012301const uint32_t total_comps = g_uastc_mode_comps[mode];1230212303const uint32_t weight_bits = g_uastc_mode_weight_bits[mode];1230412305unpacked.m_astc.m_weight_range = g_uastc_mode_weight_ranges[mode];1230612307const uint32_t total_values = total_comps * 2 * subsets;12308const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[mode];1230912310const uint32_t cem = g_uastc_mode_cem[mode];12311unpacked.m_astc.m_cem = cem;1231212313const uint32_t ep_bits = g_astc_bise_range_table[endpoint_range][0];12314const uint32_t ep_trits = g_astc_bise_range_table[endpoint_range][1];12315const uint32_t ep_quints = g_astc_bise_range_table[endpoint_range][2];1231612317uint32_t total_tqs = 0;12318uint32_t bundle_size = 0, mul = 0;12319if (ep_trits)12320{12321total_tqs = (total_values + 4) / 5;12322bundle_size = 5;12323mul = 3;12324}12325else if (ep_quints)12326{12327total_tqs = (total_values + 2) / 3;12328bundle_size = 3;12329mul = 5;12330}1233112332uint32_t tq_values[8];12333for (uint32_t i = 0; i < total_tqs; i++)12334{12335uint32_t num_bits = ep_trits ? 8 : 7;12336if (i == (total_tqs - 1))12337{12338uint32_t num_remaining = total_values - (total_tqs - 1) * bundle_size;12339if (ep_trits)12340{12341switch (num_remaining)12342{12343case 1: num_bits = 2; break;12344case 2: num_bits = 4; break;12345case 3: num_bits = 5; break;12346case 4: num_bits = 7; break;12347default: break;12348}12349}12350else if (ep_quints)12351{12352switch (num_remaining)12353{12354case 1: num_bits = 3; break;12355case 2: num_bits = 5; break;12356default: break;12357}12358}12359}1236012361tq_values[i] = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, num_bits);12362} // i1236312364uint32_t accum = 0;12365uint32_t accum_remaining = 0;12366uint32_t next_tq_index = 0;1236712368for (uint32_t i = 0; i < total_values; i++)12369{12370uint32_t value = (uint32_t)read_bits1_to_9_fst(blk.m_bytes, bit_ofs, ep_bits);1237112372if (total_tqs)12373{12374if (!accum_remaining)12375{12376assert(next_tq_index < total_tqs);12377accum = tq_values[next_tq_index++];12378accum_remaining = bundle_size;12379}1238012381// TODO: Optimize with tables12382uint32_t v = accum % mul;12383accum /= mul;12384accum_remaining--;1238512386value |= (v << ep_bits);12387}1238812389unpacked.m_astc.m_endpoints[i] = (uint8_t)value;12390}1239112392const uint8_t* pPartition_pattern;12393const uint8_t* pSubset_anchor_indices = get_anchor_indices(subsets, mode, unpacked.m_common_pattern, pPartition_pattern);1239412395#ifdef _DEBUG12396for (uint32_t i = 0; i < 16; i++)12397assert(pPartition_pattern[i] == astc_compute_texel_partition(part_seed, i & 3, i >> 2, 0, subsets, true));1239812399for (uint32_t subset_index = 0; subset_index < subsets; subset_index++)12400{12401uint32_t anchor_index = 0;1240212403for (uint32_t i = 0; i < 16; i++)12404{12405if (pPartition_pattern[i] == subset_index)12406{12407anchor_index = i;12408break;12409}12410}1241112412assert(pSubset_anchor_indices[subset_index] == anchor_index);12413}12414#endif1241512416#if 012417const uint32_t total_planes_shift = total_planes - 1;12418for (uint32_t i = 0; i < 16 * total_planes; i++)12419{12420uint32_t num_bits = weight_bits;12421for (uint32_t s = 0; s < subsets; s++)12422{12423if (pSubset_anchor_indices[s] == (i >> total_planes_shift))12424{12425num_bits--;12426break;12427}12428}1242912430unpacked.m_astc.m_weights[i] = (uint8_t)read_bits1_to_9(blk.m_bytes, bit_ofs, num_bits);12431}12432#endif1243312434if (mode == 18)12435{12436// Mode 18 is the only mode with more than 64 weight bits.12437for (uint32_t i = 0; i < 16; i++)12438unpacked.m_astc.m_weights[i] = (uint8_t)read_bits1_to_9(blk.m_bytes, bit_ofs, i ? weight_bits : (weight_bits - 1));12439}12440else12441{12442// All other modes have <= 64 weight bits.12443uint64_t bits;1244412445// Read the weight bits12446if ((BASISD_IS_BIG_ENDIAN) || (!BASISD_USE_UNALIGNED_WORD_READS))12447bits = read_bits64(blk.m_bytes, bit_ofs, basisu::minimum<int>(64, 128 - (int)bit_ofs));12448else12449{12450bits = blk.m_dwords[2];12451bits |= (((uint64_t)blk.m_dwords[3]) << 32U);1245212453if (bit_ofs >= 64U)12454bits >>= (bit_ofs - 64U);12455else12456{12457assert(bit_ofs >= 56U);1245812459uint32_t bits_needed = 64U - bit_ofs;12460bits <<= bits_needed;12461bits |= (blk.m_bytes[7] >> (8U - bits_needed));12462}12463}1246412465bit_ofs = 0;1246612467const uint32_t mask = (1U << weight_bits) - 1U;12468const uint32_t anchor_mask = (1U << (weight_bits - 1U)) - 1U;1246912470if (total_planes == 2)12471{12472// Dual plane modes always have a single subset, and the first 2 weights are anchors.1247312474unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask);12475bit_ofs += (weight_bits - 1);1247612477unpacked.m_astc.m_weights[1] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask);12478bit_ofs += (weight_bits - 1);1247912480for (uint32_t i = 2; i < 32; i++)12481{12482unpacked.m_astc.m_weights[i] = (uint8_t)((uint32_t)(bits >> bit_ofs) & mask);12483bit_ofs += weight_bits;12484}12485}12486else12487{12488if (subsets == 1)12489{12490// Specialize the single subset case.12491if (weight_bits == 4)12492{12493assert(bit_ofs == 0);1249412495// Specialize the most common case: 4-bit weights.12496unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits) & 7);12497unpacked.m_astc.m_weights[1] = (uint8_t)((uint32_t)(bits >> 3) & 15);12498unpacked.m_astc.m_weights[2] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 1)) & 15);12499unpacked.m_astc.m_weights[3] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 2)) & 15);1250012501unpacked.m_astc.m_weights[4] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 3)) & 15);12502unpacked.m_astc.m_weights[5] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 4)) & 15);12503unpacked.m_astc.m_weights[6] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 5)) & 15);12504unpacked.m_astc.m_weights[7] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 6)) & 15);1250512506unpacked.m_astc.m_weights[8] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 7)) & 15);12507unpacked.m_astc.m_weights[9] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 8)) & 15);12508unpacked.m_astc.m_weights[10] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 9)) & 15);12509unpacked.m_astc.m_weights[11] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 10)) & 15);1251012511unpacked.m_astc.m_weights[12] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 11)) & 15);12512unpacked.m_astc.m_weights[13] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 12)) & 15);12513unpacked.m_astc.m_weights[14] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 13)) & 15);12514unpacked.m_astc.m_weights[15] = (uint8_t)((uint32_t)(bits >> (3 + 4 * 14)) & 15);12515}12516else12517{12518// First weight is always an anchor.12519unpacked.m_astc.m_weights[0] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask);12520bit_ofs += (weight_bits - 1);1252112522for (uint32_t i = 1; i < 16; i++)12523{12524unpacked.m_astc.m_weights[i] = (uint8_t)((uint32_t)(bits >> bit_ofs) & mask);12525bit_ofs += weight_bits;12526}12527}12528}12529else12530{12531const uint32_t a0 = pSubset_anchor_indices[0], a1 = pSubset_anchor_indices[1], a2 = pSubset_anchor_indices[2];1253212533for (uint32_t i = 0; i < 16; i++)12534{12535if ((i == a0) || (i == a1) || (i == a2))12536{12537unpacked.m_astc.m_weights[i] = (uint8_t)((uint32_t)(bits >> bit_ofs) & anchor_mask);12538bit_ofs += (weight_bits - 1);12539}12540else12541{12542unpacked.m_astc.m_weights[i] = (uint8_t)((uint32_t)(bits >> bit_ofs) & mask);12543bit_ofs += weight_bits;12544}12545}12546}12547}12548}1254912550if ((blue_contract_check) && (total_comps >= 3))12551{12552// We only need to disable ASTC Blue Contraction when we'll be packing to ASTC. The other transcoders don't care.12553bool invert_subset[3] = { false, false, false };12554bool any_flag = false;1255512556for (uint32_t subset_index = 0; subset_index < subsets; subset_index++)12557{12558const int s0 = g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 0]].m_unquant +12559g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 2]].m_unquant +12560g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 4]].m_unquant;1256112562const int s1 = g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 1]].m_unquant +12563g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 3]].m_unquant +12564g_astc_unquant[endpoint_range][unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + 5]].m_unquant;1256512566if (s1 < s0)12567{12568for (uint32_t c = 0; c < total_comps; c++)12569std::swap(unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + c * 2 + 0], unpacked.m_astc.m_endpoints[subset_index * total_comps * 2 + c * 2 + 1]);1257012571invert_subset[subset_index] = true;12572any_flag = true;12573}12574}1257512576if (any_flag)12577{12578const uint32_t weight_mask = (1 << weight_bits) - 1;1257912580for (uint32_t i = 0; i < 16; i++)12581{12582uint32_t subset = pPartition_pattern[i];1258312584if (invert_subset[subset])12585{12586unpacked.m_astc.m_weights[i * total_planes] = (uint8_t)(weight_mask - unpacked.m_astc.m_weights[i * total_planes]);1258712588if (total_planes == 2)12589unpacked.m_astc.m_weights[i * total_planes + 1] = (uint8_t)(weight_mask - unpacked.m_astc.m_weights[i * total_planes + 1]);12590}12591}12592}12593}1259412595return true;12596}1259712598static const uint32_t* g_astc_weight_tables[6] = { nullptr, g_bc7_weights1, g_bc7_weights2, g_bc7_weights3, g_astc_weights4, g_astc_weights5 };1259912600bool unpack_uastc(uint32_t mode, uint32_t common_pattern, const color32& solid_color, const astc_block_desc& astc, color32* pPixels, bool srgb)12601{12602if (mode == UASTC_MODE_INDEX_SOLID_COLOR)12603{12604for (uint32_t i = 0; i < 16; i++)12605pPixels[i] = solid_color;12606return true;12607}1260812609color32 endpoints[3][2];1261012611const uint32_t total_subsets = g_uastc_mode_subsets[mode];12612const uint32_t total_comps = basisu::minimum<uint32_t>(4U, g_uastc_mode_comps[mode]);12613const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[mode];12614const uint32_t total_planes = g_uastc_mode_planes[mode];12615const uint32_t weight_bits = g_uastc_mode_weight_bits[mode];12616const uint32_t weight_levels = 1 << weight_bits;1261712618for (uint32_t subset_index = 0; subset_index < total_subsets; subset_index++)12619{12620if (total_comps == 2)12621{12622const uint32_t ll = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + 0 * 2 + 0]].m_unquant;12623const uint32_t lh = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + 0 * 2 + 1]].m_unquant;1262412625const uint32_t al = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + 1 * 2 + 0]].m_unquant;12626const uint32_t ah = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + 1 * 2 + 1]].m_unquant;1262712628endpoints[subset_index][0].set_noclamp_rgba(ll, ll, ll, al);12629endpoints[subset_index][1].set_noclamp_rgba(lh, lh, lh, ah);12630}12631else12632{12633for (uint32_t comp_index = 0; comp_index < total_comps; comp_index++)12634{12635endpoints[subset_index][0][comp_index] = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + comp_index * 2 + 0]].m_unquant;12636endpoints[subset_index][1][comp_index] = g_astc_unquant[endpoint_range][astc.m_endpoints[subset_index * total_comps * 2 + comp_index * 2 + 1]].m_unquant;12637}12638for (uint32_t comp_index = total_comps; comp_index < 4; comp_index++)12639{12640endpoints[subset_index][0][comp_index] = 255;12641endpoints[subset_index][1][comp_index] = 255;12642}12643}12644}1264512646color32 block_colors[3][32];1264712648const uint32_t* pWeights = g_astc_weight_tables[weight_bits];1264912650for (uint32_t subset_index = 0; subset_index < total_subsets; subset_index++)12651{12652for (uint32_t l = 0; l < weight_levels; l++)12653{12654if (total_comps == 2)12655{12656const uint8_t lc = (uint8_t)astc_interpolate(endpoints[subset_index][0][0], endpoints[subset_index][1][0], pWeights[l], srgb);12657const uint8_t ac = (uint8_t)astc_interpolate(endpoints[subset_index][0][3], endpoints[subset_index][1][3], pWeights[l], srgb);1265812659block_colors[subset_index][l].set(lc, lc, lc, ac);12660}12661else12662{12663uint32_t comp_index;12664for (comp_index = 0; comp_index < total_comps; comp_index++)12665block_colors[subset_index][l][comp_index] = (uint8_t)astc_interpolate(endpoints[subset_index][0][comp_index], endpoints[subset_index][1][comp_index], pWeights[l], srgb);1266612667for (; comp_index < 4; comp_index++)12668block_colors[subset_index][l][comp_index] = 255;12669}12670}12671}1267212673const uint8_t* pPartition_pattern = g_zero_pattern;1267412675if (total_subsets >= 2)12676{12677if (total_subsets == 3)12678pPartition_pattern = &g_astc_bc7_patterns3[common_pattern][0];12679else if (mode == 7)12680pPartition_pattern = &g_bc7_3_astc2_patterns2[common_pattern][0];12681else12682pPartition_pattern = &g_astc_bc7_patterns2[common_pattern][0];1268312684#ifdef _DEBUG12685for (uint32_t i = 0; i < 16; i++)12686{12687assert(pPartition_pattern[i] == (uint8_t)astc_compute_texel_partition(astc.m_partition_seed, i & 3, i >> 2, 0, total_subsets, true));12688}12689#endif12690}1269112692if (total_planes == 1)12693{12694if (total_subsets == 1)12695{12696for (uint32_t i = 0; i < 16; i++)12697{12698assert(astc.m_weights[i] < weight_levels);12699pPixels[i] = block_colors[0][astc.m_weights[i]];12700}12701}12702else12703{12704for (uint32_t i = 0; i < 16; i++)12705{12706assert(astc.m_weights[i] < weight_levels);12707pPixels[i] = block_colors[pPartition_pattern[i]][astc.m_weights[i]];12708}12709}12710}12711else12712{12713assert(total_subsets == 1);1271412715for (uint32_t i = 0; i < 16; i++)12716{12717const uint32_t subset_index = 0; // pPartition_pattern[i];1271812719const uint32_t weight_index0 = astc.m_weights[i * 2];12720const uint32_t weight_index1 = astc.m_weights[i * 2 + 1];1272112722assert(weight_index0 < weight_levels && weight_index1 < weight_levels);1272312724color32& c = pPixels[i];12725for (uint32_t comp = 0; comp < 4; comp++)12726{12727if ((int)comp == astc.m_ccs)12728c[comp] = block_colors[subset_index][weight_index1][comp];12729else12730c[comp] = block_colors[subset_index][weight_index0][comp];12731}12732}12733}1273412735return true;12736}1273712738bool unpack_uastc(const unpacked_uastc_block& unpacked_blk, color32* pPixels, bool srgb)12739{12740return unpack_uastc(unpacked_blk.m_mode, unpacked_blk.m_common_pattern, unpacked_blk.m_solid_color, unpacked_blk.m_astc, pPixels, srgb);12741}1274212743bool unpack_uastc(const uastc_block& blk, color32* pPixels, bool srgb)12744{12745unpacked_uastc_block unpacked_blk;1274612747if (!unpack_uastc(blk, unpacked_blk, false, false))12748return false;1274912750return unpack_uastc(unpacked_blk, pPixels, srgb);12751}1275212753// Determines the best shared pbits to use to encode xl/xh12754static void determine_shared_pbits(12755uint32_t total_comps, uint32_t comp_bits, float xl[4], float xh[4],12756color_quad_u8& bestMinColor, color_quad_u8& bestMaxColor, uint32_t best_pbits[2])12757{12758const uint32_t total_bits = comp_bits + 1;12759assert(total_bits >= 4 && total_bits <= 8);1276012761const int iscalep = (1 << total_bits) - 1;12762const float scalep = (float)iscalep;1276312764float best_err = 1e+9f;1276512766for (int p = 0; p < 2; p++)12767{12768color_quad_u8 xMinColor, xMaxColor;12769for (uint32_t c = 0; c < 4; c++)12770{12771xMinColor.m_c[c] = (uint8_t)(clampi(((int)((xl[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));12772xMaxColor.m_c[c] = (uint8_t)(clampi(((int)((xh[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));12773}1277412775color_quad_u8 scaledLow, scaledHigh;1277612777for (uint32_t i = 0; i < 4; i++)12778{12779scaledLow.m_c[i] = (xMinColor.m_c[i] << (8 - total_bits));12780scaledLow.m_c[i] |= (scaledLow.m_c[i] >> total_bits);12781assert(scaledLow.m_c[i] <= 255);1278212783scaledHigh.m_c[i] = (xMaxColor.m_c[i] << (8 - total_bits));12784scaledHigh.m_c[i] |= (scaledHigh.m_c[i] >> total_bits);12785assert(scaledHigh.m_c[i] <= 255);12786}1278712788float err = 0;12789for (uint32_t i = 0; i < total_comps; i++)12790err += basisu::squaref((scaledLow.m_c[i] / 255.0f) - xl[i]) + basisu::squaref((scaledHigh.m_c[i] / 255.0f) - xh[i]);1279112792if (err < best_err)12793{12794best_err = err;12795best_pbits[0] = p;12796best_pbits[1] = p;12797for (uint32_t j = 0; j < 4; j++)12798{12799bestMinColor.m_c[j] = xMinColor.m_c[j] >> 1;12800bestMaxColor.m_c[j] = xMaxColor.m_c[j] >> 1;12801}12802}12803}12804}1280512806// Determines the best unique pbits to use to encode xl/xh12807static void determine_unique_pbits(12808uint32_t total_comps, uint32_t comp_bits, float xl[4], float xh[4],12809color_quad_u8& bestMinColor, color_quad_u8& bestMaxColor, uint32_t best_pbits[2])12810{12811const uint32_t total_bits = comp_bits + 1;12812const int iscalep = (1 << total_bits) - 1;12813const float scalep = (float)iscalep;1281412815float best_err0 = 1e+9f;12816float best_err1 = 1e+9f;1281712818for (int p = 0; p < 2; p++)12819{12820color_quad_u8 xMinColor, xMaxColor;1282112822for (uint32_t c = 0; c < 4; c++)12823{12824xMinColor.m_c[c] = (uint8_t)(clampi(((int)((xl[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));12825xMaxColor.m_c[c] = (uint8_t)(clampi(((int)((xh[c] * scalep - p) / 2.0f + .5f)) * 2 + p, p, iscalep - 1 + p));12826}1282712828color_quad_u8 scaledLow, scaledHigh;12829for (uint32_t i = 0; i < 4; i++)12830{12831scaledLow.m_c[i] = (xMinColor.m_c[i] << (8 - total_bits));12832scaledLow.m_c[i] |= (scaledLow.m_c[i] >> total_bits);12833assert(scaledLow.m_c[i] <= 255);1283412835scaledHigh.m_c[i] = (xMaxColor.m_c[i] << (8 - total_bits));12836scaledHigh.m_c[i] |= (scaledHigh.m_c[i] >> total_bits);12837assert(scaledHigh.m_c[i] <= 255);12838}1283912840float err0 = 0, err1 = 0;12841for (uint32_t i = 0; i < total_comps; i++)12842{12843err0 += basisu::squaref(scaledLow.m_c[i] - xl[i] * 255.0f);12844err1 += basisu::squaref(scaledHigh.m_c[i] - xh[i] * 255.0f);12845}1284612847if (err0 < best_err0)12848{12849best_err0 = err0;12850best_pbits[0] = p;1285112852bestMinColor.m_c[0] = xMinColor.m_c[0] >> 1;12853bestMinColor.m_c[1] = xMinColor.m_c[1] >> 1;12854bestMinColor.m_c[2] = xMinColor.m_c[2] >> 1;12855bestMinColor.m_c[3] = xMinColor.m_c[3] >> 1;12856}1285712858if (err1 < best_err1)12859{12860best_err1 = err1;12861best_pbits[1] = p;1286212863bestMaxColor.m_c[0] = xMaxColor.m_c[0] >> 1;12864bestMaxColor.m_c[1] = xMaxColor.m_c[1] >> 1;12865bestMaxColor.m_c[2] = xMaxColor.m_c[2] >> 1;12866bestMaxColor.m_c[3] = xMaxColor.m_c[3] >> 1;12867}12868}12869}1287012871bool transcode_uastc_to_astc(const uastc_block& src_blk, void* pDst)12872{12873unpacked_uastc_block unpacked_src_blk;12874if (!unpack_uastc(src_blk, unpacked_src_blk, true, false))12875return false;1287612877bool success = false;12878if (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR)12879{12880pack_astc_solid_block(pDst, unpacked_src_blk.m_solid_color);12881success = true;12882}12883else12884{12885success = pack_astc_block(static_cast<uint32_t*>(pDst), &unpacked_src_blk.m_astc, unpacked_src_blk.m_mode);12886}1288712888return success;12889}1289012891bool transcode_uastc_to_bc7(const unpacked_uastc_block& unpacked_src_blk, bc7_optimization_results& dst_blk)12892{12893memset(&dst_blk, 0, sizeof(dst_blk));1289412895const uint32_t mode = unpacked_src_blk.m_mode;1289612897const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[mode];12898const uint32_t total_comps = g_uastc_mode_comps[mode];1289912900switch (mode)12901{12902case 0:12903case 5:12904case 10:12905case 12:12906case 14:12907case 15:12908case 18:12909{12910// MODE 0: DualPlane: 0, WeightRange: 8 (16), Subsets: 1, EndpointRange: 19 (192) - BC7 MODE6 RGB12911// MODE 5: DualPlane: 0, WeightRange : 5 (8), Subsets : 1, EndpointRange : 20 (256) - BC7 MODE6 RGB12912// MODE 10 DualPlane: 0, WeightRange: 8 (16), Subsets: 1, EndpointRange: 13 (48) - BC7 MODE612913// MODE 12: DualPlane: 0, WeightRange : 5 (8), Subsets : 1, EndpointRange : 19 (192) - BC7 MODE612914// MODE 14: DualPlane: 0, WeightRange : 2 (4), Subsets : 1, EndpointRange : 20 (256) - BC7 MODE612915// MODE 18: DualPlane: 0, WeightRange : 11 (32), Subsets : 1, CEM : 8, EndpointRange : 11 (32) - BC7 MODE612916// MODE 15: DualPlane: 0, WeightRange : 8 (16), Subsets : 1, CEM : 4 (LA Direct), EndpointRange : 20 (256) - BC7 MODE612917dst_blk.m_mode = 6;1291812919float xl[4], xh[4];12920if (total_comps == 2)12921{12922xl[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0]].m_unquant / 255.0f;12923xh[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1]].m_unquant / 255.0f;1292412925xl[1] = xl[0];12926xh[1] = xh[0];1292712928xl[2] = xl[0];12929xh[2] = xh[0];1293012931xl[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2]].m_unquant / 255.0f;12932xh[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3]].m_unquant / 255.0f;12933}12934else12935{12936xl[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0]].m_unquant / 255.0f;12937xl[1] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2]].m_unquant / 255.0f;12938xl[2] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[4]].m_unquant / 255.0f;1293912940xh[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1]].m_unquant / 255.0f;12941xh[1] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3]].m_unquant / 255.0f;12942xh[2] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[5]].m_unquant / 255.0f;1294312944if (total_comps == 4)12945{12946xl[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[6]].m_unquant / 255.0f;12947xh[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[7]].m_unquant / 255.0f;12948}12949else12950{12951xl[3] = 1.0f;12952xh[3] = 1.0f;12953}12954}1295512956uint32_t best_pbits[2];12957color_quad_u8 bestMinColor, bestMaxColor;12958determine_unique_pbits((total_comps == 2) ? 4 : total_comps, 7, xl, xh, bestMinColor, bestMaxColor, best_pbits);1295912960dst_blk.m_low[0] = bestMinColor;12961dst_blk.m_high[0] = bestMaxColor;1296212963if (total_comps == 3)12964{12965dst_blk.m_low[0].m_c[3] = 127;12966dst_blk.m_high[0].m_c[3] = 127;12967}1296812969dst_blk.m_pbits[0][0] = best_pbits[0];12970dst_blk.m_pbits[0][1] = best_pbits[1];1297112972if (mode == 18)12973{12974const uint8_t s_bc7_5_to_4[32] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15 };12975for (uint32_t i = 0; i < 16; i++)12976dst_blk.m_selectors[i] = s_bc7_5_to_4[unpacked_src_blk.m_astc.m_weights[i]];12977}12978else if (mode == 14)12979{12980const uint8_t s_bc7_2_to_4[4] = { 0, 5, 10, 15 };12981for (uint32_t i = 0; i < 16; i++)12982dst_blk.m_selectors[i] = s_bc7_2_to_4[unpacked_src_blk.m_astc.m_weights[i]];12983}12984else if ((mode == 5) || (mode == 12))12985{12986const uint8_t s_bc7_3_to_4[8] = { 0, 2, 4, 6, 9, 11, 13, 15 };12987for (uint32_t i = 0; i < 16; i++)12988dst_blk.m_selectors[i] = s_bc7_3_to_4[unpacked_src_blk.m_astc.m_weights[i]];12989}12990else12991{12992for (uint32_t i = 0; i < 16; i++)12993dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];12994}1299512996break;12997}12998case 1:12999{13000// DualPlane: 0, WeightRange : 2 (4), Subsets : 1, EndpointRange : 20 (256) - BC7 MODE313001// Mode 1 uses endpoint range 20 - no need to use ASTC dequant tables.13002dst_blk.m_mode = 3;1300313004float xl[4], xh[4];13005xl[0] = unpacked_src_blk.m_astc.m_endpoints[0] / 255.0f;13006xl[1] = unpacked_src_blk.m_astc.m_endpoints[2] / 255.0f;13007xl[2] = unpacked_src_blk.m_astc.m_endpoints[4] / 255.0f;13008xl[3] = 1.0f;1300913010xh[0] = unpacked_src_blk.m_astc.m_endpoints[1] / 255.0f;13011xh[1] = unpacked_src_blk.m_astc.m_endpoints[3] / 255.0f;13012xh[2] = unpacked_src_blk.m_astc.m_endpoints[5] / 255.0f;13013xh[3] = 1.0f;1301413015uint32_t best_pbits[2];13016color_quad_u8 bestMinColor, bestMaxColor;13017memset(&bestMinColor, 0, sizeof(bestMinColor));13018memset(&bestMaxColor, 0, sizeof(bestMaxColor));13019determine_unique_pbits(3, 7, xl, xh, bestMinColor, bestMaxColor, best_pbits);1302013021for (uint32_t i = 0; i < 3; i++)13022{13023dst_blk.m_low[0].m_c[i] = bestMinColor.m_c[i];13024dst_blk.m_high[0].m_c[i] = bestMaxColor.m_c[i];13025dst_blk.m_low[1].m_c[i] = bestMinColor.m_c[i];13026dst_blk.m_high[1].m_c[i] = bestMaxColor.m_c[i];13027}13028dst_blk.m_pbits[0][0] = best_pbits[0];13029dst_blk.m_pbits[0][1] = best_pbits[1];13030dst_blk.m_pbits[1][0] = best_pbits[0];13031dst_blk.m_pbits[1][1] = best_pbits[1];1303213033for (uint32_t i = 0; i < 16; i++)13034dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];1303513036break;13037}13038case 2:13039{13040// 2. DualPlane: 0, WeightRange : 5 (8), Subsets : 2, EndpointRange : 8 (16) - BC7 MODE113041dst_blk.m_mode = 1;13042dst_blk.m_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_bc7;1304313044const bool invert_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_invert;1304513046float xl[4], xh[4];13047xl[3] = 1.0f;13048xh[3] = 1.0f;1304913050for (uint32_t subset = 0; subset < 2; subset++)13051{13052for (uint32_t i = 0; i < 3; i++)13053{13054uint32_t v = unpacked_src_blk.m_astc.m_endpoints[i * 2 + subset * 6];13055v = (v << 4) | v;13056xl[i] = v / 255.0f;1305713058v = unpacked_src_blk.m_astc.m_endpoints[i * 2 + subset * 6 + 1];13059v = (v << 4) | v;13060xh[i] = v / 255.0f;13061}1306213063uint32_t best_pbits[2] = { 0, 0 };13064color_quad_u8 bestMinColor, bestMaxColor;13065memset(&bestMinColor, 0, sizeof(bestMinColor));13066memset(&bestMaxColor, 0, sizeof(bestMaxColor));13067determine_shared_pbits(3, 6, xl, xh, bestMinColor, bestMaxColor, best_pbits);1306813069const uint32_t bc7_subset_index = invert_partition ? (1 - subset) : subset;1307013071for (uint32_t i = 0; i < 3; i++)13072{13073dst_blk.m_low[bc7_subset_index].m_c[i] = bestMinColor.m_c[i];13074dst_blk.m_high[bc7_subset_index].m_c[i] = bestMaxColor.m_c[i];13075}1307613077dst_blk.m_pbits[bc7_subset_index][0] = best_pbits[0];13078} // subset1307913080for (uint32_t i = 0; i < 16; i++)13081dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];1308213083break;13084}13085case 3:13086{13087// DualPlane: 0, WeightRange : 2 (4), Subsets : 3, EndpointRange : 7 (12) - BC7 MODE213088dst_blk.m_mode = 2;13089dst_blk.m_partition = g_astc_bc7_common_partitions3[unpacked_src_blk.m_common_pattern].m_bc7;1309013091const uint32_t perm = g_astc_bc7_common_partitions3[unpacked_src_blk.m_common_pattern].m_astc_to_bc7_perm;1309213093for (uint32_t subset = 0; subset < 3; subset++)13094{13095for (uint32_t comp = 0; comp < 3; comp++)13096{13097uint32_t lo = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[comp * 2 + 0 + subset * 6]].m_unquant;13098uint32_t hi = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[comp * 2 + 1 + subset * 6]].m_unquant;1309913100// TODO: I think this can be improved by using tables like Basis Universal does with ETC1S conversion.13101lo = (lo * 31 + 127) / 255;13102hi = (hi * 31 + 127) / 255;1310313104const uint32_t bc7_subset_index = g_astc_to_bc7_partition_index_perm_tables[perm][subset];1310513106dst_blk.m_low[bc7_subset_index].m_c[comp] = (uint8_t)lo;13107dst_blk.m_high[bc7_subset_index].m_c[comp] = (uint8_t)hi;13108}13109}1311013111for (uint32_t i = 0; i < 16; i++)13112dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];1311313114break;13115}13116case 4:13117{13118// 4. DualPlane: 0, WeightRange: 2 (4), Subsets: 2, EndpointRange: 12 (40) - BC7 MODE313119dst_blk.m_mode = 3;13120dst_blk.m_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_bc7;1312113122const bool invert_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_invert;1312313124float xl[4], xh[4];13125xl[3] = 1.0f;13126xh[3] = 1.0f;1312713128for (uint32_t subset = 0; subset < 2; subset++)13129{13130for (uint32_t i = 0; i < 3; i++)13131{13132xl[i] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[i * 2 + subset * 6]].m_unquant / 255.0f;13133xh[i] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[i * 2 + subset * 6 + 1]].m_unquant / 255.0f;13134}1313513136uint32_t best_pbits[2] = { 0, 0 };13137color_quad_u8 bestMinColor, bestMaxColor;13138memset(&bestMinColor, 0, sizeof(bestMinColor));13139memset(&bestMaxColor, 0, sizeof(bestMaxColor));13140determine_unique_pbits(3, 7, xl, xh, bestMinColor, bestMaxColor, best_pbits);1314113142const uint32_t bc7_subset_index = invert_partition ? (1 - subset) : subset;1314313144for (uint32_t i = 0; i < 3; i++)13145{13146dst_blk.m_low[bc7_subset_index].m_c[i] = bestMinColor.m_c[i];13147dst_blk.m_high[bc7_subset_index].m_c[i] = bestMaxColor.m_c[i];13148}13149dst_blk.m_low[bc7_subset_index].m_c[3] = 127;13150dst_blk.m_high[bc7_subset_index].m_c[3] = 127;1315113152dst_blk.m_pbits[bc7_subset_index][0] = best_pbits[0];13153dst_blk.m_pbits[bc7_subset_index][1] = best_pbits[1];1315413155} // subset1315613157for (uint32_t i = 0; i < 16; i++)13158dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];1315913160break;13161}13162case 6:13163case 11:13164case 13:13165case 17:13166{13167// MODE 6: DualPlane: 1, WeightRange : 2 (4), Subsets : 1, EndpointRange : 18 (160) - BC7 MODE5 RGB13168// MODE 11: DualPlane: 1, WeightRange: 2 (4), Subsets: 1, EndpointRange: 13 (48) - BC7 MODE513169// MODE 13: DualPlane: 1, WeightRange: 0 (2), Subsets : 1, EndpointRange : 20 (256) - BC7 MODE513170// MODE 17: DualPlane: 1, WeightRange: 2 (4), Subsets: 1, CEM: 4 (LA Direct), EndpointRange: 20 (256) - BC7 MODE513171dst_blk.m_mode = 5;13172dst_blk.m_rotation = (unpacked_src_blk.m_astc.m_ccs + 1) & 3;1317313174if (total_comps == 2)13175{13176assert(unpacked_src_blk.m_astc.m_ccs == 3);1317713178dst_blk.m_low->m_c[0] = (uint8_t)((g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0]].m_unquant * 127 + 127) / 255);13179dst_blk.m_high->m_c[0] = (uint8_t)((g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1]].m_unquant * 127 + 127) / 255);1318013181dst_blk.m_low->m_c[1] = dst_blk.m_low->m_c[0];13182dst_blk.m_high->m_c[1] = dst_blk.m_high->m_c[0];1318313184dst_blk.m_low->m_c[2] = dst_blk.m_low->m_c[0];13185dst_blk.m_high->m_c[2] = dst_blk.m_high->m_c[0];1318613187dst_blk.m_low->m_c[3] = (uint8_t)(g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2]].m_unquant);13188dst_blk.m_high->m_c[3] = (uint8_t)(g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3]].m_unquant);13189}13190else13191{13192for (uint32_t astc_comp = 0; astc_comp < 4; astc_comp++)13193{13194uint32_t bc7_comp = astc_comp;13195// ASTC and BC7 handle dual plane component rotations differently:13196// ASTC: 2nd plane separately interpolates the CCS channel.13197// BC7: 2nd plane channel is swapped with alpha, 2nd plane controls alpha interpolation, then we swap alpha with the desired channel.13198if (astc_comp == (uint32_t)unpacked_src_blk.m_astc.m_ccs)13199bc7_comp = 3;13200else if (astc_comp == 3)13201bc7_comp = unpacked_src_blk.m_astc.m_ccs;1320213203uint32_t l = 255, h = 255;13204if (astc_comp < total_comps)13205{13206l = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[astc_comp * 2 + 0]].m_unquant;13207h = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[astc_comp * 2 + 1]].m_unquant;13208}1320913210if (bc7_comp < 3)13211{13212l = (l * 127 + 127) / 255;13213h = (h * 127 + 127) / 255;13214}1321513216dst_blk.m_low->m_c[bc7_comp] = (uint8_t)l;13217dst_blk.m_high->m_c[bc7_comp] = (uint8_t)h;13218}13219}1322013221if (mode == 13)13222{13223for (uint32_t i = 0; i < 16; i++)13224{13225dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i * 2] ? 3 : 0;13226dst_blk.m_alpha_selectors[i] = unpacked_src_blk.m_astc.m_weights[i * 2 + 1] ? 3 : 0;13227}13228}13229else13230{13231for (uint32_t i = 0; i < 16; i++)13232{13233dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i * 2];13234dst_blk.m_alpha_selectors[i] = unpacked_src_blk.m_astc.m_weights[i * 2 + 1];13235}13236}1323713238break;13239}13240case 7:13241{13242// DualPlane: 0, WeightRange : 2 (4), Subsets : 2, EndpointRange : 12 (40) - BC7 MODE213243dst_blk.m_mode = 2;13244dst_blk.m_partition = g_bc7_3_astc2_common_partitions[unpacked_src_blk.m_common_pattern].m_bc73;1324513246const uint32_t common_pattern_k = g_bc7_3_astc2_common_partitions[unpacked_src_blk.m_common_pattern].k;1324713248for (uint32_t bc7_part = 0; bc7_part < 3; bc7_part++)13249{13250const uint32_t astc_part = bc7_convert_partition_index_3_to_2(bc7_part, common_pattern_k);1325113252for (uint32_t c = 0; c < 3; c++)13253{13254dst_blk.m_low[bc7_part].m_c[c] = (g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[c * 2 + 0 + astc_part * 6]].m_unquant * 31 + 127) / 255;13255dst_blk.m_high[bc7_part].m_c[c] = (g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[c * 2 + 1 + astc_part * 6]].m_unquant * 31 + 127) / 255;13256}13257}1325813259for (uint32_t i = 0; i < 16; i++)13260dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];1326113262break;13263}13264case UASTC_MODE_INDEX_SOLID_COLOR:13265{13266// Void-Extent: Solid Color RGBA (BC7 MODE5 or MODE6)13267const color32& solid_color = unpacked_src_blk.m_solid_color;1326813269uint32_t best_err0 = g_bc7_mode_6_optimal_endpoints[solid_color.r][0].m_error + g_bc7_mode_6_optimal_endpoints[solid_color.g][0].m_error +13270g_bc7_mode_6_optimal_endpoints[solid_color.b][0].m_error + g_bc7_mode_6_optimal_endpoints[solid_color.a][0].m_error;1327113272uint32_t best_err1 = g_bc7_mode_6_optimal_endpoints[solid_color.r][1].m_error + g_bc7_mode_6_optimal_endpoints[solid_color.g][1].m_error +13273g_bc7_mode_6_optimal_endpoints[solid_color.b][1].m_error + g_bc7_mode_6_optimal_endpoints[solid_color.a][1].m_error;1327413275if (best_err0 > 0 && best_err1 > 0)13276{13277dst_blk.m_mode = 5;1327813279for (uint32_t c = 0; c < 3; c++)13280{13281dst_blk.m_low[0].m_c[c] = g_bc7_mode_5_optimal_endpoints[solid_color.c[c]].m_lo;13282dst_blk.m_high[0].m_c[c] = g_bc7_mode_5_optimal_endpoints[solid_color.c[c]].m_hi;13283}1328413285memset(dst_blk.m_selectors, BC7ENC_MODE_5_OPTIMAL_INDEX, 16);1328613287dst_blk.m_low[0].m_c[3] = solid_color.c[3];13288dst_blk.m_high[0].m_c[3] = solid_color.c[3];1328913290//memset(dst_blk.m_alpha_selectors, 0, 16);13291}13292else13293{13294dst_blk.m_mode = 6;1329513296uint32_t best_p = 0;13297if (best_err1 < best_err0)13298best_p = 1;1329913300for (uint32_t c = 0; c < 4; c++)13301{13302dst_blk.m_low[0].m_c[c] = g_bc7_mode_6_optimal_endpoints[solid_color.c[c]][best_p].m_lo;13303dst_blk.m_high[0].m_c[c] = g_bc7_mode_6_optimal_endpoints[solid_color.c[c]][best_p].m_hi;13304}1330513306dst_blk.m_pbits[0][0] = best_p;13307dst_blk.m_pbits[0][1] = best_p;13308memset(dst_blk.m_selectors, BC7ENC_MODE_6_OPTIMAL_INDEX, 16);13309}1331013311break;13312}13313case 9:13314case 16:13315{13316// 9. DualPlane: 0, WeightRange : 2 (4), Subsets : 2, EndpointRange : 8 (16) - BC7 MODE713317// 16. DualPlane: 0, WeightRange: 2 (4), Subsets: 2, CEM: 4 (LA Direct), EndpointRange: 20 (256) - BC7 MODE71331813319dst_blk.m_mode = 7;13320dst_blk.m_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_bc7;1332113322const bool invert_partition = g_astc_bc7_common_partitions2[unpacked_src_blk.m_common_pattern].m_invert;1332313324for (uint32_t astc_subset = 0; astc_subset < 2; astc_subset++)13325{13326float xl[4], xh[4];1332713328if (total_comps == 2)13329{13330xl[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0 + astc_subset * 4]].m_unquant / 255.0f;13331xh[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1 + astc_subset * 4]].m_unquant / 255.0f;1333213333xl[1] = xl[0];13334xh[1] = xh[0];1333513336xl[2] = xl[0];13337xh[2] = xh[0];1333813339xl[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2 + astc_subset * 4]].m_unquant / 255.0f;13340xh[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3 + astc_subset * 4]].m_unquant / 255.0f;13341}13342else13343{13344xl[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[0 + astc_subset * 8]].m_unquant / 255.0f;13345xl[1] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[2 + astc_subset * 8]].m_unquant / 255.0f;13346xl[2] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[4 + astc_subset * 8]].m_unquant / 255.0f;13347xl[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[6 + astc_subset * 8]].m_unquant / 255.0f;1334813349xh[0] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[1 + astc_subset * 8]].m_unquant / 255.0f;13350xh[1] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[3 + astc_subset * 8]].m_unquant / 255.0f;13351xh[2] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[5 + astc_subset * 8]].m_unquant / 255.0f;13352xh[3] = g_astc_unquant[endpoint_range][unpacked_src_blk.m_astc.m_endpoints[7 + astc_subset * 8]].m_unquant / 255.0f;13353}1335413355uint32_t best_pbits[2] = { 0, 0 };13356color_quad_u8 bestMinColor, bestMaxColor;13357memset(&bestMinColor, 0, sizeof(bestMinColor));13358memset(&bestMaxColor, 0, sizeof(bestMaxColor));13359determine_unique_pbits(4, 5, xl, xh, bestMinColor, bestMaxColor, best_pbits);1336013361const uint32_t bc7_subset_index = invert_partition ? (1 - astc_subset) : astc_subset;1336213363dst_blk.m_low[bc7_subset_index] = bestMinColor;13364dst_blk.m_high[bc7_subset_index] = bestMaxColor;1336513366dst_blk.m_pbits[bc7_subset_index][0] = best_pbits[0];13367dst_blk.m_pbits[bc7_subset_index][1] = best_pbits[1];13368} // astc_subset1336913370for (uint32_t i = 0; i < 16; i++)13371dst_blk.m_selectors[i] = unpacked_src_blk.m_astc.m_weights[i];1337213373break;13374}13375default:13376return false;13377}1337813379return true;13380}1338113382bool transcode_uastc_to_bc7(const uastc_block& src_blk, bc7_optimization_results& dst_blk)13383{13384unpacked_uastc_block unpacked_src_blk;13385if (!unpack_uastc(src_blk, unpacked_src_blk, false, false))13386return false;1338713388return transcode_uastc_to_bc7(unpacked_src_blk, dst_blk);13389}1339013391bool transcode_uastc_to_bc7(const uastc_block& src_blk, void* pDst)13392{13393bc7_optimization_results temp;13394if (!transcode_uastc_to_bc7(src_blk, temp))13395return false;1339613397encode_bc7_block(pDst, &temp);13398return true;13399}1340013401color32 apply_etc1_bias(const color32 &block_color, uint32_t bias, uint32_t limit, uint32_t subblock)13402{13403color32 result;1340413405for (uint32_t c = 0; c < 3; c++)13406{13407static const int s_divs[3] = { 1, 3, 9 };1340813409int delta = 0;1341013411switch (bias)13412{13413case 2: delta = subblock ? 0 : ((c == 0) ? -1 : 0); break;13414case 5: delta = subblock ? 0 : ((c == 1) ? -1 : 0); break;13415case 6: delta = subblock ? 0 : ((c == 2) ? -1 : 0); break;1341613417case 7: delta = subblock ? 0 : ((c == 0) ? 1 : 0); break;13418case 11: delta = subblock ? 0 : ((c == 1) ? 1 : 0); break;13419case 15: delta = subblock ? 0 : ((c == 2) ? 1 : 0); break;1342013421case 18: delta = subblock ? ((c == 0) ? -1 : 0) : 0; break;13422case 19: delta = subblock ? ((c == 1) ? -1 : 0) : 0; break;13423case 20: delta = subblock ? ((c == 2) ? -1 : 0) : 0; break;1342413425case 21: delta = subblock ? ((c == 0) ? 1 : 0) : 0; break;13426case 24: delta = subblock ? ((c == 1) ? 1 : 0) : 0; break;13427case 8: delta = subblock ? ((c == 2) ? 1 : 0) : 0; break;1342813429case 10: delta = -2; break;1343013431case 27: delta = subblock ? 0 : -1; break;13432case 28: delta = subblock ? -1 : 1; break;13433case 29: delta = subblock ? 1 : 0; break;13434case 30: delta = subblock ? -1 : 0; break;13435case 31: delta = subblock ? 0 : 1; break;1343613437default:13438delta = ((bias / s_divs[c]) % 3) - 1;13439break;13440}1344113442int v = block_color[c];13443if (v == 0)13444{13445if (delta == -2)13446v += 3;13447else13448v += delta + 1;13449}13450else if (v == (int)limit)13451{13452v += (delta - 1);13453}13454else13455{13456v += delta;13457if ((v < 0) || (v > (int)limit))13458v = (v - delta) - delta;13459}1346013461assert(v >= 0);13462assert(v <= (int)limit);1346313464result[c] = (uint8_t)v;13465}1346613467return result;13468}1346913470static void etc1_determine_selectors(decoder_etc_block& dst_blk, const color32* pSource_pixels, uint32_t first_subblock, uint32_t last_subblock)13471{13472static const uint8_t s_tran[4] = { 1, 0, 2, 3 };1347313474uint16_t l_bitmask = 0;13475uint16_t h_bitmask = 0;1347613477for (uint32_t subblock = first_subblock; subblock < last_subblock; subblock++)13478{13479color32 block_colors[4];13480dst_blk.get_block_colors(block_colors, subblock);1348113482uint32_t block_y[4];13483for (uint32_t i = 0; i < 4; i++)13484block_y[i] = block_colors[i][0] * 54 + block_colors[i][1] * 183 + block_colors[i][2] * 19;1348513486const uint32_t block_y01 = block_y[0] + block_y[1];13487const uint32_t block_y12 = block_y[1] + block_y[2];13488const uint32_t block_y23 = block_y[2] + block_y[3];1348913490// X0 X0 X0 X0 X1 X1 X1 X1 X2 X2 X2 X2 X3 X3 X3 X313491// Y0 Y1 Y2 Y3 Y0 Y1 Y2 Y3 Y0 Y1 Y2 Y3 Y0 Y1 Y2 Y31349213493if (dst_blk.get_flip_bit())13494{13495uint32_t ofs = subblock * 2;1349613497for (uint32_t y = 0; y < 2; y++)13498{13499for (uint32_t x = 0; x < 4; x++)13500{13501const color32& c = pSource_pixels[x + (subblock * 2 + y) * 4];13502const uint32_t l = c[0] * 108 + c[1] * 366 + c[2] * 38;1350313504uint32_t t = s_tran[(l < block_y01) + (l < block_y12) + (l < block_y23)];1350513506assert(ofs < 16);13507l_bitmask |= ((t & 1) << ofs);13508h_bitmask |= ((t >> 1) << ofs);13509ofs += 4;13510}1351113512ofs = (int)ofs + 1 - 4 * 4;13513}13514}13515else13516{13517uint32_t ofs = (subblock * 2) * 4;13518for (uint32_t x = 0; x < 2; x++)13519{13520for (uint32_t y = 0; y < 4; y++)13521{13522const color32& c = pSource_pixels[subblock * 2 + x + y * 4];13523const uint32_t l = c[0] * 108 + c[1] * 366 + c[2] * 38;1352413525uint32_t t = s_tran[(l < block_y01) + (l < block_y12) + (l < block_y23)];1352613527assert(ofs < 16);13528l_bitmask |= ((t & 1) << ofs);13529h_bitmask |= ((t >> 1) << ofs);13530++ofs;13531}13532}13533}13534}1353513536dst_blk.m_bytes[7] = (uint8_t)(l_bitmask);13537dst_blk.m_bytes[6] = (uint8_t)(l_bitmask >> 8);13538dst_blk.m_bytes[5] = (uint8_t)(h_bitmask);13539dst_blk.m_bytes[4] = (uint8_t)(h_bitmask >> 8);13540}1354113542static const uint8_t s_etc1_solid_selectors[4][4] = { { 255, 255, 255, 255 }, { 255, 255, 0, 0 }, { 0, 0, 0, 0 }, {0, 0, 255, 255 } };1354313544struct etc_coord213545{13546uint8_t m_x, m_y;13547};1354813549// [flip][subblock][pixel_index]13550const etc_coord2 g_etc1_pixel_coords[2][2][8] =13551{13552{13553{13554{ 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 },13555{ 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }13556},13557{13558{ 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 },13559{ 3, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }13560}13561},13562{13563{13564{ 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },13565{ 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }13566},13567{13568{ 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },13569{ 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 }13570},13571}13572};1357313574void transcode_uastc_to_etc1(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst)13575{13576decoder_etc_block& dst_blk = *static_cast<decoder_etc_block*>(pDst);1357713578if (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR)13579{13580dst_blk.m_bytes[3] = (uint8_t)((unpacked_src_blk.m_etc1_diff << 1) | (unpacked_src_blk.m_etc1_inten0 << 5) | (unpacked_src_blk.m_etc1_inten0 << 2));1358113582if (unpacked_src_blk.m_etc1_diff)13583{13584dst_blk.m_bytes[0] = (uint8_t)(unpacked_src_blk.m_etc1_r << 3);13585dst_blk.m_bytes[1] = (uint8_t)(unpacked_src_blk.m_etc1_g << 3);13586dst_blk.m_bytes[2] = (uint8_t)(unpacked_src_blk.m_etc1_b << 3);13587}13588else13589{13590dst_blk.m_bytes[0] = (uint8_t)(unpacked_src_blk.m_etc1_r | (unpacked_src_blk.m_etc1_r << 4));13591dst_blk.m_bytes[1] = (uint8_t)(unpacked_src_blk.m_etc1_g | (unpacked_src_blk.m_etc1_g << 4));13592dst_blk.m_bytes[2] = (uint8_t)(unpacked_src_blk.m_etc1_b | (unpacked_src_blk.m_etc1_b << 4));13593}1359413595memcpy(dst_blk.m_bytes + 4, &s_etc1_solid_selectors[unpacked_src_blk.m_etc1_selector][0], 4);1359613597return;13598}1359913600const bool flip = unpacked_src_blk.m_etc1_flip != 0;13601const bool diff = unpacked_src_blk.m_etc1_diff != 0;1360213603dst_blk.m_bytes[3] = (uint8_t)((int)flip | (diff << 1) | (unpacked_src_blk.m_etc1_inten0 << 5) | (unpacked_src_blk.m_etc1_inten1 << 2));1360413605const uint32_t limit = diff ? 31 : 15;1360613607color32 block_colors[2];1360813609for (uint32_t subset = 0; subset < 2; subset++)13610{13611uint32_t avg_color[3];13612memset(avg_color, 0, sizeof(avg_color));1361313614for (uint32_t j = 0; j < 8; j++)13615{13616const etc_coord2& c = g_etc1_pixel_coords[flip][subset][j];1361713618avg_color[0] += block_pixels[c.m_y][c.m_x].r;13619avg_color[1] += block_pixels[c.m_y][c.m_x].g;13620avg_color[2] += block_pixels[c.m_y][c.m_x].b;13621} // j1362213623block_colors[subset][0] = (uint8_t)((avg_color[0] * limit + 1020) / (8 * 255));13624block_colors[subset][1] = (uint8_t)((avg_color[1] * limit + 1020) / (8 * 255));13625block_colors[subset][2] = (uint8_t)((avg_color[2] * limit + 1020) / (8 * 255));13626block_colors[subset][3] = 0;1362713628if (g_uastc_mode_has_etc1_bias[unpacked_src_blk.m_mode])13629{13630block_colors[subset] = apply_etc1_bias(block_colors[subset], unpacked_src_blk.m_etc1_bias, limit, subset);13631}1363213633} // subset1363413635if (diff)13636{13637int dr = block_colors[1].r - block_colors[0].r;13638int dg = block_colors[1].g - block_colors[0].g;13639int db = block_colors[1].b - block_colors[0].b;1364013641dr = basisu::clamp<int>(dr, cETC1ColorDeltaMin, cETC1ColorDeltaMax);13642dg = basisu::clamp<int>(dg, cETC1ColorDeltaMin, cETC1ColorDeltaMax);13643db = basisu::clamp<int>(db, cETC1ColorDeltaMin, cETC1ColorDeltaMax);1364413645if (dr < 0) dr += 8;13646if (dg < 0) dg += 8;13647if (db < 0) db += 8;1364813649dst_blk.m_bytes[0] = (uint8_t)((block_colors[0].r << 3) | dr);13650dst_blk.m_bytes[1] = (uint8_t)((block_colors[0].g << 3) | dg);13651dst_blk.m_bytes[2] = (uint8_t)((block_colors[0].b << 3) | db);13652}13653else13654{13655dst_blk.m_bytes[0] = (uint8_t)(block_colors[1].r | (block_colors[0].r << 4));13656dst_blk.m_bytes[1] = (uint8_t)(block_colors[1].g | (block_colors[0].g << 4));13657dst_blk.m_bytes[2] = (uint8_t)(block_colors[1].b | (block_colors[0].b << 4));13658}1365913660etc1_determine_selectors(dst_blk, &block_pixels[0][0], 0, 2);13661}1366213663bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst)13664{13665unpacked_uastc_block unpacked_src_blk;13666if (!unpack_uastc(src_blk, unpacked_src_blk, false))13667return false;1366813669color32 block_pixels[4][4];13670if (unpacked_src_blk.m_mode != UASTC_MODE_INDEX_SOLID_COLOR)13671{13672const bool unpack_srgb = false;13673if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))13674return false;13675}1367613677transcode_uastc_to_etc1(unpacked_src_blk, block_pixels, pDst);1367813679return true;13680}1368113682static inline int gray_distance2(const uint8_t c, int y)13683{13684int gray_dist = (int)c - y;13685return gray_dist * gray_dist;13686}1368713688static bool pack_etc1_y_estimate_flipped(const uint8_t* pSrc_pixels,13689int& upper_avg, int& lower_avg, int& left_avg, int& right_avg)13690{13691int sums[2][2];1369213693#define GET_XY(x, y) pSrc_pixels[(x) + ((y) * 4)]1369413695sums[0][0] = GET_XY(0, 0) + GET_XY(0, 1) + GET_XY(1, 0) + GET_XY(1, 1);13696sums[1][0] = GET_XY(2, 0) + GET_XY(2, 1) + GET_XY(3, 0) + GET_XY(3, 1);13697sums[0][1] = GET_XY(0, 2) + GET_XY(0, 3) + GET_XY(1, 2) + GET_XY(1, 3);13698sums[1][1] = GET_XY(2, 2) + GET_XY(2, 3) + GET_XY(3, 2) + GET_XY(3, 3);1369913700upper_avg = (sums[0][0] + sums[1][0] + 4) / 8;13701lower_avg = (sums[0][1] + sums[1][1] + 4) / 8;13702left_avg = (sums[0][0] + sums[0][1] + 4) / 8;13703right_avg = (sums[1][0] + sums[1][1] + 4) / 8;1370413705#undef GET_XY13706#define GET_XY(x, y, a) gray_distance2(pSrc_pixels[(x) + ((y) * 4)], a)1370713708int upper_gray_dist = 0, lower_gray_dist = 0, left_gray_dist = 0, right_gray_dist = 0;13709for (uint32_t i = 0; i < 4; i++)13710{13711for (uint32_t j = 0; j < 2; j++)13712{13713upper_gray_dist += GET_XY(i, j, upper_avg);13714lower_gray_dist += GET_XY(i, 2 + j, lower_avg);13715left_gray_dist += GET_XY(j, i, left_avg);13716right_gray_dist += GET_XY(2 + j, i, right_avg);13717}13718}1371913720#undef GET_XY1372113722int upper_lower_sum = upper_gray_dist + lower_gray_dist;13723int left_right_sum = left_gray_dist + right_gray_dist;1372413725return upper_lower_sum < left_right_sum;13726}1372713728// Base Sel Table13729// XXXXX XX XXX13730static const uint16_t g_etc1_y_solid_block_configs[256] =13731{137320,781,64,161,260,192,33,131,96,320,65,162,261,193,34,291,97,224,66,163,262,194,35,549,98,4,67,653,164,195,523,36,99,5,578,68,165,353,196,37,135,100,324,69,166,354,197,38,295,101,228,70,167,13733355,198,39,553,102,8,71,608,168,199,527,40,103,9,582,72,169,357,200,41,139,104,328,73,170,358,201,42,299,105,232,74,171,359,202,43,557,106,12,75,612,172,203,531,44,107,13,586,76,173,361,13734204,45,143,108,332,77,174,362,205,46,303,109,236,78,175,363,206,47,561,110,16,79,616,176,207,535,48,111,17,590,80,177,365,208,49,147,112,336,81,178,366,209,50,307,113,240,82,179,367,210,1373551,565,114,20,83,620,180,211,539,52,115,21,594,84,181,369,212,53,151,116,340,85,182,370,213,54,311,117,244,86,183,371,214,55,569,118,24,87,624,184,215,543,56,119,25,598,88,185,373,216,57,13736155,120,344,89,186,374,217,58,315,121,248,90,187,375,218,59,573,122,28,91,628,188,219,754,60,123,29,602,92,189,377,220,61,159,124,348,93,190,378,221,62,319,125,252,94,191,379,222,63,882,12613737};1373813739// individual13740// table base sel0 sel1 sel2 sel313741static const uint16_t g_etc1_y_solid_block_4i_configs[256] =13742{137430xA000,0xA800,0x540B,0xAA01,0xAA01,0xFE00,0xFF00,0xFF00,0x8,0x5515,0x5509,0x5509,0xAA03,0x5508,0x5508,0x9508,0xA508,0xA908,0xAA08,0x5513,0xAA09,0xAA09,0xAA05,0xFF08,0xFF08,0x10,0x551D,0x5511,0x5511,137440xAA0B,0x5510,0x5510,0x9510,0xA510,0xA910,0xAA10,0x551B,0xAA11,0xAA11,0xAA0D,0xFF10,0xFF10,0x18,0x5525,0x5519,0x5519,0xAA13,0x5518,0x5518,0x9518,0xA518,0xA918,0xAA18,0x5523,0xAA19,0xAA19,0xAA15,137450xFF18,0xFF18,0x20,0x552D,0x5521,0x5521,0xAA1B,0x5520,0x5520,0x9520,0xA520,0xA920,0xAA20,0x552B,0xAA21,0xAA21,0xAA1D,0xFF20,0xFF20,0x28,0x5535,0x5529,0x5529,0xAA23,0x5528,0x5528,0x9528,0xA528,0xA928,137460xAA28,0x5533,0xAA29,0xAA29,0xAA25,0xFF28,0xFF28,0x30,0x553D,0x5531,0x5531,0xAA2B,0x5530,0x5530,0x9530,0xA530,0xA930,0xAA30,0x553B,0xAA31,0xAA31,0xAA2D,0xFF30,0xFF30,0x38,0x5545,0x5539,0x5539,0xAA33,137470x5538,0x5538,0x9538,0xA538,0xA938,0xAA38,0x5543,0xAA39,0xAA39,0xAA35,0xFF38,0xFF38,0x40,0x554D,0x5541,0x5541,0xAA3B,0x5540,0x5540,0x9540,0xA540,0xA940,0xAA40,0x554B,0xAA41,0xAA41,0xAA3D,0xFF40,0xFF40,137480x48,0x5555,0x5549,0x5549,0xAA43,0x5548,0x5548,0x9548,0xA548,0xA948,0xAA48,0x5553,0xAA49,0xAA49,0xAA45,0xFF48,0xFF48,0x50,0x555D,0x5551,0x5551,0xAA4B,0x5550,0x5550,0x9550,0xA550,0xA950,0xAA50,0x555B,137490xAA51,0xAA51,0xAA4D,0xFF50,0xFF50,0x58,0x5565,0x5559,0x5559,0xAA53,0x5558,0x5558,0x9558,0xA558,0xA958,0xAA58,0x5563,0xAA59,0xAA59,0xAA55,0xFF58,0xFF58,0x60,0x556D,0x5561,0x5561,0xAA5B,0x5560,0x5560,137500x9560,0xA560,0xA960,0xAA60,0x556B,0xAA61,0xAA61,0xAA5D,0xFF60,0xFF60,0x68,0x5575,0x5569,0x5569,0xAA63,0x5568,0x5568,0x9568,0xA568,0xA968,0xAA68,0x5573,0xAA69,0xAA69,0xAA65,0xFF68,0xFF68,0x70,0x557D,137510x5571,0x5571,0xAA6B,0x5570,0x5570,0x9570,0xA570,0xA970,0xAA70,0x557B,0xAA71,0xAA71,0xAA6D,0xFF70,0xFF70,0x78,0x78,0x5579,0x5579,0xAA73,0x5578,0x9578,0x2578,0xE6E,0x27813752};1375313754static const uint16_t g_etc1_y_solid_block_2i_configs[256] =13755{137560x416,0x800,0xA00,0x50B,0xA01,0xA01,0xF00,0xF00,0xF00,0x8,0x515,0x509,0x509,0xA03,0x508,0x508,0xF01,0xF01,0xA08,0xA08,0x513,0xA09,0xA09,0xA05,0xF08,0xF08,0x10,0x51D,0x511,0x511,0xA0B,0x510,0x510,0xF09,137570xF09,0xA10,0xA10,0x51B,0xA11,0xA11,0xA0D,0xF10,0xF10,0x18,0x525,0x519,0x519,0xA13,0x518,0x518,0xF11,0xF11,0xA18,0xA18,0x523,0xA19,0xA19,0xA15,0xF18,0xF18,0x20,0x52D,0x521,0x521,0xA1B,0x520,0x520,0xF19,137580xF19,0xA20,0xA20,0x52B,0xA21,0xA21,0xA1D,0xF20,0xF20,0x28,0x535,0x529,0x529,0xA23,0x528,0x528,0xF21,0xF21,0xA28,0xA28,0x533,0xA29,0xA29,0xA25,0xF28,0xF28,0x30,0x53D,0x531,0x531,0xA2B,0x530,0x530,0xF29,137590xF29,0xA30,0xA30,0x53B,0xA31,0xA31,0xA2D,0xF30,0xF30,0x38,0x545,0x539,0x539,0xA33,0x538,0x538,0xF31,0xF31,0xA38,0xA38,0x543,0xA39,0xA39,0xA35,0xF38,0xF38,0x40,0x54D,0x541,0x541,0xA3B,0x540,0x540,0xF39,137600xF39,0xA40,0xA40,0x54B,0xA41,0xA41,0xA3D,0xF40,0xF40,0x48,0x555,0x549,0x549,0xA43,0x548,0x548,0xF41,0xF41,0xA48,0xA48,0x553,0xA49,0xA49,0xA45,0xF48,0xF48,0x50,0x55D,0x551,0x551,0xA4B,0x550,0x550,0xF49,137610xF49,0xA50,0xA50,0x55B,0xA51,0xA51,0xA4D,0xF50,0xF50,0x58,0x565,0x559,0x559,0xA53,0x558,0x558,0xF51,0xF51,0xA58,0xA58,0x563,0xA59,0xA59,0xA55,0xF58,0xF58,0x60,0x56D,0x561,0x561,0xA5B,0x560,0x560,0xF59,137620xF59,0xA60,0xA60,0x56B,0xA61,0xA61,0xA5D,0xF60,0xF60,0x68,0x575,0x569,0x569,0xA63,0x568,0x568,0xF61,0xF61,0xA68,0xA68,0x573,0xA69,0xA69,0xA65,0xF68,0xF68,0x70,0x57D,0x571,0x571,0xA6B,0x570,0x570,0xF69,137630xF69,0xA70,0xA70,0x57B,0xA71,0xA71,0xA6D,0xF70,0xF70,0x78,0x78,0x579,0x579,0xA73,0x578,0x578,0xE6E,0x27813764};1376513766static const uint16_t g_etc1_y_solid_block_1i_configs[256] =13767{137680x0,0x116,0x200,0x200,0x10B,0x201,0x201,0x300,0x300,0x8,0x115,0x109,0x109,0x203,0x108,0x108,0x114,0x301,0x204,0x208,0x208,0x113,0x209,0x209,0x205,0x308,0x10,0x11D,0x111,0x111,0x20B,0x110,0x110,0x11C,0x309,137690x20C,0x210,0x210,0x11B,0x211,0x211,0x20D,0x310,0x18,0x125,0x119,0x119,0x213,0x118,0x118,0x124,0x311,0x214,0x218,0x218,0x123,0x219,0x219,0x215,0x318,0x20,0x12D,0x121,0x121,0x21B,0x120,0x120,0x12C,0x319,0x21C,137700x220,0x220,0x12B,0x221,0x221,0x21D,0x320,0x28,0x135,0x129,0x129,0x223,0x128,0x128,0x134,0x321,0x224,0x228,0x228,0x133,0x229,0x229,0x225,0x328,0x30,0x13D,0x131,0x131,0x22B,0x130,0x130,0x13C,0x329,0x22C,0x230,137710x230,0x13B,0x231,0x231,0x22D,0x330,0x38,0x145,0x139,0x139,0x233,0x138,0x138,0x144,0x331,0x234,0x238,0x238,0x143,0x239,0x239,0x235,0x338,0x40,0x14D,0x141,0x141,0x23B,0x140,0x140,0x14C,0x339,0x23C,0x240,0x240,137720x14B,0x241,0x241,0x23D,0x340,0x48,0x155,0x149,0x149,0x243,0x148,0x148,0x154,0x341,0x244,0x248,0x248,0x153,0x249,0x249,0x245,0x348,0x50,0x15D,0x151,0x151,0x24B,0x150,0x150,0x15C,0x349,0x24C,0x250,0x250,0x15B,137730x251,0x251,0x24D,0x350,0x58,0x165,0x159,0x159,0x253,0x158,0x158,0x164,0x351,0x254,0x258,0x258,0x163,0x259,0x259,0x255,0x358,0x60,0x16D,0x161,0x161,0x25B,0x160,0x160,0x16C,0x359,0x25C,0x260,0x260,0x16B,0x261,137740x261,0x25D,0x360,0x68,0x175,0x169,0x169,0x263,0x168,0x168,0x174,0x361,0x264,0x268,0x268,0x173,0x269,0x269,0x265,0x368,0x70,0x17D,0x171,0x171,0x26B,0x170,0x170,0x17C,0x369,0x26C,0x270,0x270,0x17B,0x271,0x271,137750x26D,0x370,0x78,0x78,0x179,0x179,0x273,0x178,0x178,0x26E,0x27813776};1377713778// We don't have any useful hints to accelerate single channel ETC1, so we need to real-time encode from scratch.13779bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst, uint32_t channel)13780{13781unpacked_uastc_block unpacked_src_blk;13782if (!unpack_uastc(src_blk, unpacked_src_blk, false))13783return false;1378413785#if 013786for (uint32_t individ = 0; individ < 2; individ++)13787{13788uint32_t overall_error = 0;1378913790for (uint32_t c = 0; c < 256; c++)13791{13792uint32_t best_err = UINT32_MAX;13793uint32_t best_individ = 0;13794uint32_t best_base = 0;13795uint32_t best_sels[4] = { 0,0,0,0 };13796uint32_t best_table = 0;1379713798const uint32_t limit = individ ? 16 : 32;1379913800for (uint32_t table = 0; table < 8; table++)13801{13802for (uint32_t base = 0; base < limit; base++)13803{13804uint32_t total_e = 0;13805uint32_t sels[4] = { 0,0,0,0 };1380613807const uint32_t N = 4;13808for (uint32_t i = 0; i < basisu::minimum<uint32_t>(N, (256 - c)); i++)13809{13810uint32_t best_sel_e = UINT32_MAX;13811uint32_t best_sel = 0;1381213813for (uint32_t sel = 0; sel < 4; sel++)13814{13815int val = individ ? ((base << 4) | base) : ((base << 3) | (base >> 2));13816val = clamp255(val + g_etc1_inten_tables[table][sel]);1381713818int e = iabs(val - clamp255(c + i));13819if (e < best_sel_e)13820{13821best_sel_e = e;13822best_sel = sel;13823}1382413825} // sel1382613827sels[i] = best_sel;13828total_e += best_sel_e * best_sel_e;1382913830} // i1383113832if (total_e < best_err)13833{13834best_err = total_e;13835best_individ = individ;13836best_base = base;13837memcpy(best_sels, sels, sizeof(best_sels));13838best_table = table;13839}1384013841} // base13842} // table1384313844//printf("%u: %u,%u,%u,%u,%u,%u,%u,%u\n", c, best_err, best_individ, best_table, best_base, best_sels[0], best_sels[1], best_sels[2], best_sels[3]);1384513846uint32_t encoded = best_table | (best_base << 3) |13847(best_sels[0] << 8) |13848(best_sels[1] << 10) |13849(best_sels[2] << 12) |13850(best_sels[3] << 14);1385113852printf("0x%X,", encoded);1385313854overall_error += best_err;13855} // c1385613857printf("\n");13858printf("Overall error: %u\n", overall_error);1385913860} // individ1386113862exit(0);13863#endif1386413865#if 013866for (uint32_t individ = 0; individ < 2; individ++)13867{13868uint32_t overall_error = 0;1386913870for (uint32_t c = 0; c < 256; c++)13871{13872uint32_t best_err = UINT32_MAX;13873uint32_t best_individ = 0;13874uint32_t best_base = 0;13875uint32_t best_sels[4] = { 0,0,0,0 };13876uint32_t best_table = 0;1387713878const uint32_t limit = individ ? 16 : 32;1387913880for (uint32_t table = 0; table < 8; table++)13881{13882for (uint32_t base = 0; base < limit; base++)13883{13884uint32_t total_e = 0;13885uint32_t sels[4] = { 0,0,0,0 };1388613887const uint32_t N = 1;13888for (uint32_t i = 0; i < basisu::minimum<uint32_t>(N, (256 - c)); i++)13889{13890uint32_t best_sel_e = UINT32_MAX;13891uint32_t best_sel = 0;1389213893for (uint32_t sel = 0; sel < 4; sel++)13894{13895int val = individ ? ((base << 4) | base) : ((base << 3) | (base >> 2));13896val = clamp255(val + g_etc1_inten_tables[table][sel]);1389713898int e = iabs(val - clamp255(c + i));13899if (e < best_sel_e)13900{13901best_sel_e = e;13902best_sel = sel;13903}1390413905} // sel1390613907sels[i] = best_sel;13908total_e += best_sel_e * best_sel_e;1390913910} // i1391113912if (total_e < best_err)13913{13914best_err = total_e;13915best_individ = individ;13916best_base = base;13917memcpy(best_sels, sels, sizeof(best_sels));13918best_table = table;13919}1392013921} // base13922} // table1392313924//printf("%u: %u,%u,%u,%u,%u,%u,%u,%u\n", c, best_err, best_individ, best_table, best_base, best_sels[0], best_sels[1], best_sels[2], best_sels[3]);1392513926uint32_t encoded = best_table | (best_base << 3) |13927(best_sels[0] << 8) |13928(best_sels[1] << 10) |13929(best_sels[2] << 12) |13930(best_sels[3] << 14);1393113932printf("0x%X,", encoded);1393313934overall_error += best_err;13935} // c1393613937printf("\n");13938printf("Overall error: %u\n", overall_error);1393913940} // individ1394113942exit(0);13943#endif1394413945decoder_etc_block& dst_blk = *static_cast<decoder_etc_block*>(pDst);1394613947if (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR)13948{13949const uint32_t y = unpacked_src_blk.m_solid_color[channel];13950const uint32_t encoded_config = g_etc1_y_solid_block_configs[y];1395113952const uint32_t base = encoded_config & 31;13953const uint32_t sel = (encoded_config >> 5) & 3;13954const uint32_t table = encoded_config >> 7;1395513956dst_blk.m_bytes[3] = (uint8_t)(2 | (table << 5) | (table << 2));1395713958dst_blk.m_bytes[0] = (uint8_t)(base << 3);13959dst_blk.m_bytes[1] = (uint8_t)(base << 3);13960dst_blk.m_bytes[2] = (uint8_t)(base << 3);1396113962memcpy(dst_blk.m_bytes + 4, &s_etc1_solid_selectors[sel][0], 4);13963return true;13964}1396513966color32 block_pixels[4][4];13967const bool unpack_srgb = false;13968if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))13969return false;1397013971uint8_t block_y[4][4];13972for (uint32_t i = 0; i < 16; i++)13973((uint8_t*)block_y)[i] = ((color32*)block_pixels)[i][channel];1397413975int upper_avg, lower_avg, left_avg, right_avg;13976bool flip = pack_etc1_y_estimate_flipped(&block_y[0][0], upper_avg, lower_avg, left_avg, right_avg);1397713978// non-flipped: | |13979// vs.13980// flipped: --13981// --1398213983uint32_t low[2] = { 255, 255 }, high[2] = { 0, 0 };1398413985if (flip)13986{13987for (uint32_t y = 0; y < 2; y++)13988{13989for (uint32_t x = 0; x < 4; x++)13990{13991const uint32_t v = block_y[y][x];13992low[0] = basisu::minimum(low[0], v);13993high[0] = basisu::maximum(high[0], v);13994}13995}13996for (uint32_t y = 2; y < 4; y++)13997{13998for (uint32_t x = 0; x < 4; x++)13999{14000const uint32_t v = block_y[y][x];14001low[1] = basisu::minimum(low[1], v);14002high[1] = basisu::maximum(high[1], v);14003}14004}14005}14006else14007{14008for (uint32_t y = 0; y < 4; y++)14009{14010for (uint32_t x = 0; x < 2; x++)14011{14012const uint32_t v = block_y[y][x];14013low[0] = basisu::minimum(low[0], v);14014high[0] = basisu::maximum(high[0], v);14015}14016}14017for (uint32_t y = 0; y < 4; y++)14018{14019for (uint32_t x = 2; x < 4; x++)14020{14021const uint32_t v = block_y[y][x];14022low[1] = basisu::minimum(low[1], v);14023high[1] = basisu::maximum(high[1], v);14024}14025}14026}1402714028const uint32_t range[2] = { high[0] - low[0], high[1] - low[1] };1402914030dst_blk.m_bytes[3] = (uint8_t)((int)flip);1403114032if ((range[0] <= 3) && (range[1] <= 3))14033{14034// This is primarily for better gradients.14035dst_blk.m_bytes[0] = 0;14036dst_blk.m_bytes[1] = 0;14037dst_blk.m_bytes[2] = 0;1403814039uint16_t l_bitmask = 0, h_bitmask = 0;1404014041for (uint32_t subblock = 0; subblock < 2; subblock++)14042{14043const uint32_t encoded = (range[subblock] == 0) ? g_etc1_y_solid_block_1i_configs[low[subblock]] : ((range[subblock] < 2) ? g_etc1_y_solid_block_2i_configs[low[subblock]] : g_etc1_y_solid_block_4i_configs[low[subblock]]);1404414045const uint32_t table = encoded & 7;14046const uint32_t base = (encoded >> 3) & 31;14047assert(base <= 15);14048const uint32_t sels[4] = { (encoded >> 8) & 3, (encoded >> 10) & 3, (encoded >> 12) & 3, (encoded >> 14) & 3 };1404914050dst_blk.m_bytes[3] |= (uint8_t)(table << (subblock ? 2 : 5));1405114052const uint32_t sv = base << (subblock ? 0 : 4);14053dst_blk.m_bytes[0] |= (uint8_t)(sv);14054dst_blk.m_bytes[1] |= (uint8_t)(sv);14055dst_blk.m_bytes[2] |= (uint8_t)(sv);1405614057if (flip)14058{14059uint32_t ofs = subblock * 2;14060for (uint32_t y = 0; y < 2; y++)14061{14062for (uint32_t x = 0; x < 4; x++)14063{14064uint32_t t = block_y[y + subblock * 2][x];14065assert(t >= low[subblock] && t <= high[subblock]);14066t -= low[subblock];14067assert(t <= 3);1406814069t = g_selector_index_to_etc1[sels[t]];1407014071assert(ofs < 16);14072l_bitmask |= ((t & 1) << ofs);14073h_bitmask |= ((t >> 1) << ofs);14074ofs += 4;14075}1407614077ofs = (int)ofs + 1 - 4 * 4;14078}14079}14080else14081{14082uint32_t ofs = (subblock * 2) * 4;14083for (uint32_t x = 0; x < 2; x++)14084{14085for (uint32_t y = 0; y < 4; y++)14086{14087uint32_t t = block_y[y][x + subblock * 2];14088assert(t >= low[subblock] && t <= high[subblock]);14089t -= low[subblock];14090assert(t <= 3);1409114092t = g_selector_index_to_etc1[sels[t]];1409314094assert(ofs < 16);14095l_bitmask |= ((t & 1) << ofs);14096h_bitmask |= ((t >> 1) << ofs);14097++ofs;14098}14099}14100}14101} // subblock1410214103dst_blk.m_bytes[7] = (uint8_t)(l_bitmask);14104dst_blk.m_bytes[6] = (uint8_t)(l_bitmask >> 8);14105dst_blk.m_bytes[5] = (uint8_t)(h_bitmask);14106dst_blk.m_bytes[4] = (uint8_t)(h_bitmask >> 8);1410714108return true;14109}1411014111uint32_t y0 = ((flip ? upper_avg : left_avg) * 31 + 127) / 255;14112uint32_t y1 = ((flip ? lower_avg : right_avg) * 31 + 127) / 255;1411314114bool diff = true;1411514116int dy = y1 - y0;1411714118if ((dy < cETC1ColorDeltaMin) || (dy > cETC1ColorDeltaMax))14119{14120diff = false;1412114122y0 = ((flip ? upper_avg : left_avg) * 15 + 127) / 255;14123y1 = ((flip ? lower_avg : right_avg) * 15 + 127) / 255;1412414125dst_blk.m_bytes[0] = (uint8_t)(y1 | (y0 << 4));14126dst_blk.m_bytes[1] = (uint8_t)(y1 | (y0 << 4));14127dst_blk.m_bytes[2] = (uint8_t)(y1 | (y0 << 4));14128}14129else14130{14131dy = basisu::clamp<int>(dy, cETC1ColorDeltaMin, cETC1ColorDeltaMax);1413214133y1 = y0 + dy;1413414135if (dy < 0) dy += 8;1413614137dst_blk.m_bytes[0] = (uint8_t)((y0 << 3) | dy);14138dst_blk.m_bytes[1] = (uint8_t)((y0 << 3) | dy);14139dst_blk.m_bytes[2] = (uint8_t)((y0 << 3) | dy);1414014141dst_blk.m_bytes[3] |= 2;14142}1414314144const uint32_t base_y[2] = { diff ? ((y0 << 3) | (y0 >> 2)) : ((y0 << 4) | y0), diff ? ((y1 << 3) | (y1 >> 2)) : ((y1 << 4) | y1) };1414514146uint32_t enc_range[2];14147for (uint32_t subset = 0; subset < 2; subset++)14148{14149const int pos = basisu::iabs((int)high[subset] - (int)base_y[subset]);14150const int neg = basisu::iabs((int)base_y[subset] - (int)low[subset]);1415114152enc_range[subset] = basisu::maximum(pos, neg);14153}1415414155uint16_t l_bitmask = 0, h_bitmask = 0;14156for (uint32_t subblock = 0; subblock < 2; subblock++)14157{14158if ((!diff) && (range[subblock] <= 3))14159{14160const uint32_t encoded = (range[subblock] == 0) ? g_etc1_y_solid_block_1i_configs[low[subblock]] : ((range[subblock] < 2) ? g_etc1_y_solid_block_2i_configs[low[subblock]] : g_etc1_y_solid_block_4i_configs[low[subblock]]);1416114162const uint32_t table = encoded & 7;14163const uint32_t base = (encoded >> 3) & 31;14164assert(base <= 15);14165const uint32_t sels[4] = { (encoded >> 8) & 3, (encoded >> 10) & 3, (encoded >> 12) & 3, (encoded >> 14) & 3 };1416614167dst_blk.m_bytes[3] |= (uint8_t)(table << (subblock ? 2 : 5));1416814169const uint32_t mask = ~(0xF << (subblock ? 0 : 4));1417014171dst_blk.m_bytes[0] &= mask;14172dst_blk.m_bytes[1] &= mask;14173dst_blk.m_bytes[2] &= mask;1417414175const uint32_t sv = base << (subblock ? 0 : 4);14176dst_blk.m_bytes[0] |= (uint8_t)(sv);14177dst_blk.m_bytes[1] |= (uint8_t)(sv);14178dst_blk.m_bytes[2] |= (uint8_t)(sv);1417914180if (flip)14181{14182uint32_t ofs = subblock * 2;14183for (uint32_t y = 0; y < 2; y++)14184{14185for (uint32_t x = 0; x < 4; x++)14186{14187uint32_t t = block_y[y + subblock * 2][x];14188assert(t >= low[subblock] && t <= high[subblock]);14189t -= low[subblock];14190assert(t <= 3);1419114192t = g_selector_index_to_etc1[sels[t]];1419314194assert(ofs < 16);14195l_bitmask |= ((t & 1) << ofs);14196h_bitmask |= ((t >> 1) << ofs);14197ofs += 4;14198}1419914200ofs = (int)ofs + 1 - 4 * 4;14201}14202}14203else14204{14205uint32_t ofs = (subblock * 2) * 4;14206for (uint32_t x = 0; x < 2; x++)14207{14208for (uint32_t y = 0; y < 4; y++)14209{14210uint32_t t = block_y[y][x + subblock * 2];14211assert(t >= low[subblock] && t <= high[subblock]);14212t -= low[subblock];14213assert(t <= 3);1421414215t = g_selector_index_to_etc1[sels[t]];1421614217assert(ofs < 16);14218l_bitmask |= ((t & 1) << ofs);14219h_bitmask |= ((t >> 1) << ofs);14220++ofs;14221}14222}14223}1422414225continue;14226} // if1422714228uint32_t best_err = UINT32_MAX;14229uint8_t best_sels[8];14230uint32_t best_inten = 0;1423114232const int base = base_y[subblock];1423314234const int low_limit = -base;14235const int high_limit = 255 - base;1423614237assert(low_limit <= 0 && high_limit >= 0);1423814239uint32_t inten_table_mask = 0xFF;14240const uint32_t er = enc_range[subblock];14241// Each one of these tables is expensive to evaluate, so let's only examine the ones we know may be useful.14242if (er <= 51)14243{14244inten_table_mask = 0xF;1424514246if (er > 22)14247inten_table_mask &= ~(1 << 0);1424814249if ((er < 4) || (er > 39))14250inten_table_mask &= ~(1 << 1);1425114252if (er < 9)14253inten_table_mask &= ~(1 << 2);1425414255if (er < 12)14256inten_table_mask &= ~(1 << 3);14257}14258else14259{14260inten_table_mask &= ~((1 << 0) | (1 << 1));1426114262if (er > 60)14263inten_table_mask &= ~(1 << 2);1426414265if (er > 89)14266inten_table_mask &= ~(1 << 3);1426714268if (er > 120)14269inten_table_mask &= ~(1 << 4);1427014271if (er > 136)14272inten_table_mask &= ~(1 << 5);1427314274if (er > 174)14275inten_table_mask &= ~(1 << 6);14276}1427714278for (uint32_t inten = 0; inten < 8; inten++)14279{14280if ((inten_table_mask & (1 << inten)) == 0)14281continue;1428214283const int t0 = basisu::maximum(low_limit, g_etc1_inten_tables[inten][0]);14284const int t1 = basisu::maximum(low_limit, g_etc1_inten_tables[inten][1]);14285const int t2 = basisu::minimum(high_limit, g_etc1_inten_tables[inten][2]);14286const int t3 = basisu::minimum(high_limit, g_etc1_inten_tables[inten][3]);14287assert((t0 <= t1) && (t1 <= t2) && (t2 <= t3));1428814289const int tv[4] = { t2, t3, t1, t0 };1429014291const int thresh01 = t0 + t1;14292const int thresh12 = t1 + t2;14293const int thresh23 = t2 + t3;1429414295assert(thresh01 <= thresh12 && thresh12 <= thresh23);1429614297static const uint8_t s_table[4] = { 1, 0, 2, 3 };1429814299uint32_t total_err = 0;14300uint8_t sels[8];1430114302if (flip)14303{14304if (((int)high[subblock] - base) * 2 < thresh01)14305{14306memset(sels, 3, 8);1430714308for (uint32_t y = 0; y < 2; y++)14309{14310for (uint32_t x = 0; x < 4; x++)14311{14312const int delta = (int)block_y[y + subblock * 2][x] - base;1431314314const uint32_t c = 3;1431514316uint32_t e = basisu::iabs(tv[c] - delta);14317total_err += e * e;14318}14319if (total_err >= best_err)14320break;14321}14322}14323else if (((int)low[subblock] - base) * 2 >= thresh23)14324{14325memset(sels, 1, 8);1432614327for (uint32_t y = 0; y < 2; y++)14328{14329for (uint32_t x = 0; x < 4; x++)14330{14331const int delta = (int)block_y[y + subblock * 2][x] - base;1433214333const uint32_t c = 1;1433414335uint32_t e = basisu::iabs(tv[c] - delta);14336total_err += e * e;14337}14338if (total_err >= best_err)14339break;14340}14341}14342else14343{14344for (uint32_t y = 0; y < 2; y++)14345{14346for (uint32_t x = 0; x < 4; x++)14347{14348const int delta = (int)block_y[y + subblock * 2][x] - base;14349const int delta2 = delta * 2;1435014351uint32_t c = s_table[(delta2 < thresh01) + (delta2 < thresh12) + (delta2 < thresh23)];14352sels[y * 4 + x] = (uint8_t)c;1435314354uint32_t e = basisu::iabs(tv[c] - delta);14355total_err += e * e;14356}14357if (total_err >= best_err)14358break;14359}14360}14361}14362else14363{14364if (((int)high[subblock] - base) * 2 < thresh01)14365{14366memset(sels, 3, 8);1436714368for (uint32_t y = 0; y < 4; y++)14369{14370for (uint32_t x = 0; x < 2; x++)14371{14372const int delta = (int)block_y[y][x + subblock * 2] - base;1437314374const uint32_t c = 3;1437514376uint32_t e = basisu::iabs(tv[c] - delta);14377total_err += e * e;14378}14379if (total_err >= best_err)14380break;14381}14382}14383else if (((int)low[subblock] - base) * 2 >= thresh23)14384{14385memset(sels, 1, 8);1438614387for (uint32_t y = 0; y < 4; y++)14388{14389for (uint32_t x = 0; x < 2; x++)14390{14391const int delta = (int)block_y[y][x + subblock * 2] - base;1439214393const uint32_t c = 1;1439414395uint32_t e = basisu::iabs(tv[c] - delta);14396total_err += e * e;14397}14398if (total_err >= best_err)14399break;14400}14401}14402else14403{14404for (uint32_t y = 0; y < 4; y++)14405{14406for (uint32_t x = 0; x < 2; x++)14407{14408const int delta = (int)block_y[y][x + subblock * 2] - base;14409const int delta2 = delta * 2;1441014411uint32_t c = s_table[(delta2 < thresh01) + (delta2 < thresh12) + (delta2 < thresh23)];14412sels[y * 2 + x] = (uint8_t)c;1441314414uint32_t e = basisu::iabs(tv[c] - delta);14415total_err += e * e;14416}14417if (total_err >= best_err)14418break;14419}14420}14421}1442214423if (total_err < best_err)14424{14425best_err = total_err;14426best_inten = inten;14427memcpy(best_sels, sels, 8);14428}1442914430} // inten1443114432//g_inten_hist[best_inten][enc_range[subblock]]++;1443314434dst_blk.m_bytes[3] |= (uint8_t)(best_inten << (subblock ? 2 : 5));1443514436if (flip)14437{14438uint32_t ofs = subblock * 2;14439for (uint32_t y = 0; y < 2; y++)14440{14441for (uint32_t x = 0; x < 4; x++)14442{14443uint32_t t = best_sels[y * 4 + x];1444414445assert(ofs < 16);14446l_bitmask |= ((t & 1) << ofs);14447h_bitmask |= ((t >> 1) << ofs);14448ofs += 4;14449}1445014451ofs = (int)ofs + 1 - 4 * 4;14452}14453}14454else14455{14456uint32_t ofs = (subblock * 2) * 4;14457for (uint32_t x = 0; x < 2; x++)14458{14459for (uint32_t y = 0; y < 4; y++)14460{14461uint32_t t = best_sels[y * 2 + x];1446214463assert(ofs < 16);14464l_bitmask |= ((t & 1) << ofs);14465h_bitmask |= ((t >> 1) << ofs);14466++ofs;14467}14468}14469}1447014471} // subblock1447214473dst_blk.m_bytes[7] = (uint8_t)(l_bitmask);14474dst_blk.m_bytes[6] = (uint8_t)(l_bitmask >> 8);14475dst_blk.m_bytes[5] = (uint8_t)(h_bitmask);14476dst_blk.m_bytes[4] = (uint8_t)(h_bitmask >> 8);1447714478return true;14479}1448014481const uint32_t ETC2_EAC_MIN_VALUE_SELECTOR = 3, ETC2_EAC_MAX_VALUE_SELECTOR = 7;1448214483void transcode_uastc_to_etc2_eac_a8(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst)14484{14485eac_block& dst = *static_cast<eac_block*>(pDst);14486const color32* pSrc_pixels = &block_pixels[0][0];1448714488if ((!g_uastc_mode_has_alpha[unpacked_src_blk.m_mode]) || (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR))14489{14490const uint32_t a = (unpacked_src_blk.m_mode == UASTC_MODE_INDEX_SOLID_COLOR) ? unpacked_src_blk.m_solid_color[3] : 255;1449114492dst.m_base = a;14493dst.m_table = 13;14494dst.m_multiplier = 1;1449514496memcpy(dst.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));1449714498return;14499}1450014501uint32_t min_a = 255, max_a = 0;14502for (uint32_t i = 0; i < 16; i++)14503{14504min_a = basisu::minimum<uint32_t>(min_a, pSrc_pixels[i].a);14505max_a = basisu::maximum<uint32_t>(max_a, pSrc_pixels[i].a);14506}1450714508if (min_a == max_a)14509{14510dst.m_base = min_a;14511dst.m_table = 13;14512dst.m_multiplier = 1;1451314514memcpy(dst.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));14515return;14516}1451714518const uint32_t table = unpacked_src_blk.m_etc2_hints & 0xF;14519const int multiplier = unpacked_src_blk.m_etc2_hints >> 4;1452014521assert(multiplier >= 1);1452214523dst.m_multiplier = multiplier;14524dst.m_table = table;1452514526const float range = (float)(g_eac_modifier_table[dst.m_table][ETC2_EAC_MAX_VALUE_SELECTOR] - g_eac_modifier_table[dst.m_table][ETC2_EAC_MIN_VALUE_SELECTOR]);14527const int center = (int)roundf(basisu::lerp((float)min_a, (float)max_a, (float)(0 - g_eac_modifier_table[dst.m_table][ETC2_EAC_MIN_VALUE_SELECTOR]) / range));1452814529dst.m_base = center;1453014531const int8_t* pTable = &g_eac_modifier_table[dst.m_table][0];1453214533uint32_t vals[8];14534for (uint32_t j = 0; j < 8; j++)14535vals[j] = clamp255(center + (pTable[j] * multiplier));1453614537uint64_t sels = 0;14538for (uint32_t i = 0; i < 16; i++)14539{14540const uint32_t a = block_pixels[i & 3][i >> 2].a;1454114542const uint32_t err0 = (basisu::iabs(vals[0] - a) << 3) | 0;14543const uint32_t err1 = (basisu::iabs(vals[1] - a) << 3) | 1;14544const uint32_t err2 = (basisu::iabs(vals[2] - a) << 3) | 2;14545const uint32_t err3 = (basisu::iabs(vals[3] - a) << 3) | 3;14546const uint32_t err4 = (basisu::iabs(vals[4] - a) << 3) | 4;14547const uint32_t err5 = (basisu::iabs(vals[5] - a) << 3) | 5;14548const uint32_t err6 = (basisu::iabs(vals[6] - a) << 3) | 6;14549const uint32_t err7 = (basisu::iabs(vals[7] - a) << 3) | 7;1455014551const uint32_t min_err = basisu::minimum(basisu::minimum(basisu::minimum(basisu::minimum(basisu::minimum(basisu::minimum(err0, err1, err2), err3), err4), err5), err6), err7);1455214553const uint64_t best_index = min_err & 7;14554sels |= (best_index << (45 - i * 3));14555}1455614557dst.set_selector_bits(sels);14558}1455914560bool transcode_uastc_to_etc2_rgba(const uastc_block& src_blk, void* pDst)14561{14562eac_block& dst_etc2_eac_a8_blk = *static_cast<eac_block*>(pDst);14563decoder_etc_block& dst_etc1_blk = static_cast<decoder_etc_block*>(pDst)[1];1456414565unpacked_uastc_block unpacked_src_blk;14566if (!unpack_uastc(src_blk, unpacked_src_blk, false))14567return false;1456814569color32 block_pixels[4][4];14570if (unpacked_src_blk.m_mode != UASTC_MODE_INDEX_SOLID_COLOR)14571{14572const bool unpack_srgb = false;14573if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))14574return false;14575}1457614577transcode_uastc_to_etc2_eac_a8(unpacked_src_blk, block_pixels, &dst_etc2_eac_a8_blk);1457814579transcode_uastc_to_etc1(unpacked_src_blk, block_pixels, &dst_etc1_blk);1458014581return true;14582}1458314584static const uint8_t s_uastc5_to_bc1[32] = { 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1 };14585static const uint8_t s_uastc4_to_bc1[16] = { 0, 0, 0, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 1, 1, 1 };14586static const uint8_t s_uastc3_to_bc1[8] = { 0, 0, 2, 2, 3, 3, 1, 1 };14587static const uint8_t s_uastc2_to_bc1[4] = { 0, 2, 3, 1 };14588static const uint8_t s_uastc1_to_bc1[2] = { 0, 1 };14589const uint8_t* s_uastc_to_bc1_weights[6] = { nullptr, s_uastc1_to_bc1, s_uastc2_to_bc1, s_uastc3_to_bc1, s_uastc4_to_bc1, s_uastc5_to_bc1 };1459014591void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride)14592{14593uint32_t min0_v, max0_v, min1_v, max1_v,min2_v, max2_v, min3_v, max3_v;1459414595{14596min0_v = max0_v = pPixels[0 * stride];14597min1_v = max1_v = pPixels[1 * stride];14598min2_v = max2_v = pPixels[2 * stride];14599min3_v = max3_v = pPixels[3 * stride];14600}1460114602{14603uint32_t v0 = pPixels[4 * stride]; min0_v = basisu::minimum(min0_v, v0); max0_v = basisu::maximum(max0_v, v0);14604uint32_t v1 = pPixels[5 * stride]; min1_v = basisu::minimum(min1_v, v1); max1_v = basisu::maximum(max1_v, v1);14605uint32_t v2 = pPixels[6 * stride]; min2_v = basisu::minimum(min2_v, v2); max2_v = basisu::maximum(max2_v, v2);14606uint32_t v3 = pPixels[7 * stride]; min3_v = basisu::minimum(min3_v, v3); max3_v = basisu::maximum(max3_v, v3);14607}1460814609{14610uint32_t v0 = pPixels[8 * stride]; min0_v = basisu::minimum(min0_v, v0); max0_v = basisu::maximum(max0_v, v0);14611uint32_t v1 = pPixels[9 * stride]; min1_v = basisu::minimum(min1_v, v1); max1_v = basisu::maximum(max1_v, v1);14612uint32_t v2 = pPixels[10 * stride]; min2_v = basisu::minimum(min2_v, v2); max2_v = basisu::maximum(max2_v, v2);14613uint32_t v3 = pPixels[11 * stride]; min3_v = basisu::minimum(min3_v, v3); max3_v = basisu::maximum(max3_v, v3);14614}1461514616{14617uint32_t v0 = pPixels[12 * stride]; min0_v = basisu::minimum(min0_v, v0); max0_v = basisu::maximum(max0_v, v0);14618uint32_t v1 = pPixels[13 * stride]; min1_v = basisu::minimum(min1_v, v1); max1_v = basisu::maximum(max1_v, v1);14619uint32_t v2 = pPixels[14 * stride]; min2_v = basisu::minimum(min2_v, v2); max2_v = basisu::maximum(max2_v, v2);14620uint32_t v3 = pPixels[15 * stride]; min3_v = basisu::minimum(min3_v, v3); max3_v = basisu::maximum(max3_v, v3);14621}1462214623const uint32_t min_v = basisu::minimum(min0_v, min1_v, min2_v, min3_v);14624const uint32_t max_v = basisu::maximum(max0_v, max1_v, max2_v, max3_v);1462514626uint8_t* pDst_bytes = static_cast<uint8_t*>(pDst);14627pDst_bytes[0] = (uint8_t)max_v;14628pDst_bytes[1] = (uint8_t)min_v;1462914630if (max_v == min_v)14631{14632memset(pDst_bytes + 2, 0, 6);14633return;14634}1463514636const uint32_t delta = max_v - min_v;1463714638// min_v is now 0. Compute thresholds between values by scaling max_v. It's x14 because we're adding two x7 scale factors.14639const int t0 = delta * 13;14640const int t1 = delta * 11;14641const int t2 = delta * 9;14642const int t3 = delta * 7;14643const int t4 = delta * 5;14644const int t5 = delta * 3;14645const int t6 = delta * 1;1464614647// BC4 floors in its divisions, which we compensate for with the 4 bias.14648// This function is optimal for all possible inputs (i.e. it outputs the same results as checking all 8 values and choosing the closest one).14649const int bias = 4 - min_v * 14;1465014651static const uint32_t s_tran0[8] = { 1U , 7U , 6U , 5U , 4U , 3U , 2U , 0U };14652static const uint32_t s_tran1[8] = { 1U << 3U, 7U << 3U, 6U << 3U, 5U << 3U, 4U << 3U, 3U << 3U, 2U << 3U, 0U << 3U };14653static const uint32_t s_tran2[8] = { 1U << 6U, 7U << 6U, 6U << 6U, 5U << 6U, 4U << 6U, 3U << 6U, 2U << 6U, 0U << 6U };14654static const uint32_t s_tran3[8] = { 1U << 9U, 7U << 9U, 6U << 9U, 5U << 9U, 4U << 9U, 3U << 9U, 2U << 9U, 0U << 9U };1465514656uint64_t a0, a1, a2, a3;14657{14658const int v0 = pPixels[0 * stride] * 14 + bias;14659const int v1 = pPixels[1 * stride] * 14 + bias;14660const int v2 = pPixels[2 * stride] * 14 + bias;14661const int v3 = pPixels[3 * stride] * 14 + bias;14662a0 = s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)];14663a1 = s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)];14664a2 = s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)];14665a3 = s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)];14666}1466714668{14669const int v0 = pPixels[4 * stride] * 14 + bias;14670const int v1 = pPixels[5 * stride] * 14 + bias;14671const int v2 = pPixels[6 * stride] * 14 + bias;14672const int v3 = pPixels[7 * stride] * 14 + bias;14673a0 |= (s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)] << 12U);14674a1 |= (s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)] << 12U);14675a2 |= (s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)] << 12U);14676a3 |= (s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)] << 12U);14677}1467814679{14680const int v0 = pPixels[8 * stride] * 14 + bias;14681const int v1 = pPixels[9 * stride] * 14 + bias;14682const int v2 = pPixels[10 * stride] * 14 + bias;14683const int v3 = pPixels[11 * stride] * 14 + bias;14684a0 |= (((uint64_t)s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)]) << 24U);14685a1 |= (((uint64_t)s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)]) << 24U);14686a2 |= (((uint64_t)s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)]) << 24U);14687a3 |= (((uint64_t)s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)]) << 24U);14688}1468914690{14691const int v0 = pPixels[12 * stride] * 14 + bias;14692const int v1 = pPixels[13 * stride] * 14 + bias;14693const int v2 = pPixels[14 * stride] * 14 + bias;14694const int v3 = pPixels[15 * stride] * 14 + bias;14695a0 |= (((uint64_t)s_tran0[(v0 >= t0) + (v0 >= t1) + (v0 >= t2) + (v0 >= t3) + (v0 >= t4) + (v0 >= t5) + (v0 >= t6)]) << 36U);14696a1 |= (((uint64_t)s_tran1[(v1 >= t0) + (v1 >= t1) + (v1 >= t2) + (v1 >= t3) + (v1 >= t4) + (v1 >= t5) + (v1 >= t6)]) << 36U);14697a2 |= (((uint64_t)s_tran2[(v2 >= t0) + (v2 >= t1) + (v2 >= t2) + (v2 >= t3) + (v2 >= t4) + (v2 >= t5) + (v2 >= t6)]) << 36U);14698a3 |= (((uint64_t)s_tran3[(v3 >= t0) + (v3 >= t1) + (v3 >= t2) + (v3 >= t3) + (v3 >= t4) + (v3 >= t5) + (v3 >= t6)]) << 36U);14699}1470014701const uint64_t f = a0 | a1 | a2 | a3;1470214703pDst_bytes[2] = (uint8_t)f;14704pDst_bytes[3] = (uint8_t)(f >> 8U);14705pDst_bytes[4] = (uint8_t)(f >> 16U);14706pDst_bytes[5] = (uint8_t)(f >> 24U);14707pDst_bytes[6] = (uint8_t)(f >> 32U);14708pDst_bytes[7] = (uint8_t)(f >> 40U);14709}1471014711static void bc1_find_sels(const color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16])14712{14713uint32_t block_r[4], block_g[4], block_b[4];1471414715block_r[0] = (lr << 3) | (lr >> 2); block_g[0] = (lg << 2) | (lg >> 4); block_b[0] = (lb << 3) | (lb >> 2);14716block_r[3] = (hr << 3) | (hr >> 2); block_g[3] = (hg << 2) | (hg >> 4); block_b[3] = (hb << 3) | (hb >> 2);14717block_r[1] = (block_r[0] * 2 + block_r[3]) / 3; block_g[1] = (block_g[0] * 2 + block_g[3]) / 3; block_b[1] = (block_b[0] * 2 + block_b[3]) / 3;14718block_r[2] = (block_r[3] * 2 + block_r[0]) / 3; block_g[2] = (block_g[3] * 2 + block_g[0]) / 3; block_b[2] = (block_b[3] * 2 + block_b[0]) / 3;1471914720int ar = block_r[3] - block_r[0], ag = block_g[3] - block_g[0], ab = block_b[3] - block_b[0];1472114722int dots[4];14723for (uint32_t i = 0; i < 4; i++)14724dots[i] = (int)block_r[i] * ar + (int)block_g[i] * ag + (int)block_b[i] * ab;1472514726int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3];1472714728ar *= 2; ag *= 2; ab *= 2;1472914730for (uint32_t i = 0; i < 16; i++)14731{14732const int d = pSrc_pixels[i].r * ar + pSrc_pixels[i].g * ag + pSrc_pixels[i].b * ab;14733static const uint8_t s_sels[4] = { 3, 2, 1, 0 };1473414735// Rounding matters here!14736// d <= t0: <=, not <, to the later LS step "sees" a wider range of selectors. It matters for quality.14737sels[i] = s_sels[(d <= t0) + (d < t1) + (d < t2)];14738}14739}1474014741static inline void bc1_find_sels_2(const color32* pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb, uint8_t sels[16])14742{14743uint32_t block_r[4], block_g[4], block_b[4];1474414745block_r[0] = (lr << 3) | (lr >> 2); block_g[0] = (lg << 2) | (lg >> 4); block_b[0] = (lb << 3) | (lb >> 2);14746block_r[3] = (hr << 3) | (hr >> 2); block_g[3] = (hg << 2) | (hg >> 4); block_b[3] = (hb << 3) | (hb >> 2);14747block_r[1] = (block_r[0] * 2 + block_r[3]) / 3; block_g[1] = (block_g[0] * 2 + block_g[3]) / 3; block_b[1] = (block_b[0] * 2 + block_b[3]) / 3;14748block_r[2] = (block_r[3] * 2 + block_r[0]) / 3; block_g[2] = (block_g[3] * 2 + block_g[0]) / 3; block_b[2] = (block_b[3] * 2 + block_b[0]) / 3;1474914750int ar = block_r[3] - block_r[0], ag = block_g[3] - block_g[0], ab = block_b[3] - block_b[0];1475114752int dots[4];14753for (uint32_t i = 0; i < 4; i++)14754dots[i] = (int)block_r[i] * ar + (int)block_g[i] * ag + (int)block_b[i] * ab;1475514756int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3];1475714758ar *= 2; ag *= 2; ab *= 2;1475914760static const uint8_t s_sels[4] = { 3, 2, 1, 0 };1476114762for (uint32_t i = 0; i < 16; i += 4)14763{14764const int d0 = pSrc_pixels[i+0].r * ar + pSrc_pixels[i+0].g * ag + pSrc_pixels[i+0].b * ab;14765const int d1 = pSrc_pixels[i+1].r * ar + pSrc_pixels[i+1].g * ag + pSrc_pixels[i+1].b * ab;14766const int d2 = pSrc_pixels[i+2].r * ar + pSrc_pixels[i+2].g * ag + pSrc_pixels[i+2].b * ab;14767const int d3 = pSrc_pixels[i+3].r * ar + pSrc_pixels[i+3].g * ag + pSrc_pixels[i+3].b * ab;1476814769sels[i+0] = s_sels[(d0 <= t0) + (d0 < t1) + (d0 < t2)];14770sels[i+1] = s_sels[(d1 <= t0) + (d1 < t1) + (d1 < t2)];14771sels[i+2] = s_sels[(d2 <= t0) + (d2 < t1) + (d2 < t2)];14772sels[i+3] = s_sels[(d3 <= t0) + (d3 < t1) + (d3 < t2)];14773}14774}1477514776struct vec3F { float c[3]; };1477714778static bool compute_least_squares_endpoints_rgb(const color32* pColors, const uint8_t* pSelectors, vec3F* pXl, vec3F* pXh)14779{14780// Derived from bc7enc16's LS function.14781// Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf14782// I did this in matrix form first, expanded out all the ops, then optimized it a bit.14783uint32_t uq00_r = 0, uq10_r = 0, ut_r = 0, uq00_g = 0, uq10_g = 0, ut_g = 0, uq00_b = 0, uq10_b = 0, ut_b = 0;1478414785// This table is: 9 * (w * w), 9 * ((1.0f - w) * w), 9 * ((1.0f - w) * (1.0f - w))14786// where w is [0,1/3,2/3,1]. 9 is the perfect multiplier.14787static const uint32_t s_weight_vals[4] = { 0x000009, 0x010204, 0x040201, 0x090000 };1478814789uint32_t weight_accum = 0;14790for (uint32_t i = 0; i < 16; i++)14791{14792const uint32_t r = pColors[i].c[0], g = pColors[i].c[1], b = pColors[i].c[2];14793const uint32_t sel = pSelectors[i];14794ut_r += r;14795ut_g += g;14796ut_b += b;14797weight_accum += s_weight_vals[sel];14798uq00_r += sel * r;14799uq00_g += sel * g;14800uq00_b += sel * b;14801}1480214803float q00_r = (float)uq00_r, q10_r = (float)uq10_r, t_r = (float)ut_r;14804float q00_g = (float)uq00_g, q10_g = (float)uq10_g, t_g = (float)ut_g;14805float q00_b = (float)uq00_b, q10_b = (float)uq10_b, t_b = (float)ut_b;1480614807q10_r = t_r * 3.0f - q00_r;14808q10_g = t_g * 3.0f - q00_g;14809q10_b = t_b * 3.0f - q00_b;1481014811float z00 = (float)((weight_accum >> 16) & 0xFF);14812float z10 = (float)((weight_accum >> 8) & 0xFF);14813float z11 = (float)(weight_accum & 0xFF);14814float z01 = z10;1481514816float det = z00 * z11 - z01 * z10;14817if (fabs(det) < 1e-8f)14818return false;1481914820det = 3.0f / det;1482114822float iz00, iz01, iz10, iz11;14823iz00 = z11 * det;14824iz01 = -z01 * det;14825iz10 = -z10 * det;14826iz11 = z00 * det;1482714828pXl->c[0] = iz00 * q00_r + iz01 * q10_r; pXh->c[0] = iz10 * q00_r + iz11 * q10_r;14829pXl->c[1] = iz00 * q00_g + iz01 * q10_g; pXh->c[1] = iz10 * q00_g + iz11 * q10_g;14830pXl->c[2] = iz00 * q00_b + iz01 * q10_b; pXh->c[2] = iz10 * q00_b + iz11 * q10_b;1483114832// Check and fix channel singularities - might not be needed, but is in UASTC's encoder.14833for (uint32_t c = 0; c < 3; c++)14834{14835if ((pXl->c[c] < 0.0f) || (pXh->c[c] > 255.0f))14836{14837uint32_t lo_v = UINT32_MAX, hi_v = 0;14838for (uint32_t i = 0; i < 16; i++)14839{14840lo_v = basisu::minimumu(lo_v, pColors[i].c[c]);14841hi_v = basisu::maximumu(hi_v, pColors[i].c[c]);14842}1484314844if (lo_v == hi_v)14845{14846pXl->c[c] = (float)lo_v;14847pXh->c[c] = (float)hi_v;14848}14849}14850}1485114852return true;14853}1485414855void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb)14856{14857dxt1_block* pDst_block = static_cast<dxt1_block*>(pDst);1485814859uint32_t mask = 0xAA;14860uint32_t max16 = (g_bc1_match5_equals_1[fr].m_hi << 11) | (g_bc1_match6_equals_1[fg].m_hi << 5) | g_bc1_match5_equals_1[fb].m_hi;14861uint32_t min16 = (g_bc1_match5_equals_1[fr].m_lo << 11) | (g_bc1_match6_equals_1[fg].m_lo << 5) | g_bc1_match5_equals_1[fb].m_lo;1486214863if (min16 == max16)14864{14865// Always forbid 3 color blocks14866// This is to guarantee that BC3 blocks never use punchthrough alpha (3 color) mode, which isn't supported on some (all?) GPU's.14867mask = 0;1486814869// Make l > h14870if (min16 > 0)14871min16--;14872else14873{14874// l = h = 014875assert(min16 == max16 && max16 == 0);1487614877max16 = 1;14878min16 = 0;14879mask = 0x55;14880}1488114882assert(max16 > min16);14883}1488414885if (max16 < min16)14886{14887std::swap(max16, min16);14888mask ^= 0x55;14889}1489014891pDst_block->set_low_color(static_cast<uint16_t>(max16));14892pDst_block->set_high_color(static_cast<uint16_t>(min16));14893pDst_block->m_selectors[0] = static_cast<uint8_t>(mask);14894pDst_block->m_selectors[1] = static_cast<uint8_t>(mask);14895pDst_block->m_selectors[2] = static_cast<uint8_t>(mask);14896pDst_block->m_selectors[3] = static_cast<uint8_t>(mask);14897}1489814899static inline uint8_t to_5(uint32_t v) { v = v * 31 + 128; return (uint8_t)((v + (v >> 8)) >> 8); }14900static inline uint8_t to_6(uint32_t v) { v = v * 63 + 128; return (uint8_t)((v + (v >> 8)) >> 8); }1490114902// Good references: squish library, stb_dxt.14903void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags)14904{14905const color32* pSrc_pixels = (const color32*)pPixels;14906dxt1_block* pDst_block = static_cast<dxt1_block*>(pDst);1490714908int avg_r = -1, avg_g = 0, avg_b = 0;14909int lr = 0, lg = 0, lb = 0, hr = 0, hg = 0, hb = 0;14910uint8_t sels[16];1491114912const bool use_sels = (flags & cEncodeBC1UseSelectors) != 0;14913if (use_sels)14914{14915// Caller is jamming in their own selectors for us to try.14916const uint32_t s = pDst_block->m_selectors[0] | (pDst_block->m_selectors[1] << 8) | (pDst_block->m_selectors[2] << 16) | (pDst_block->m_selectors[3] << 24);1491714918static const uint8_t s_sel_tran[4] = { 0, 3, 1, 2 };1491914920for (uint32_t i = 0; i < 16; i++)14921sels[i] = s_sel_tran[(s >> (i * 2)) & 3];14922}14923else14924{14925const uint32_t fr = pSrc_pixels[0].r, fg = pSrc_pixels[0].g, fb = pSrc_pixels[0].b;1492614927uint32_t j;14928for (j = 1; j < 16; j++)14929if ((pSrc_pixels[j].r != fr) || (pSrc_pixels[j].g != fg) || (pSrc_pixels[j].b != fb))14930break;1493114932if (j == 16)14933{14934encode_bc1_solid_block(pDst, fr, fg, fb);14935return;14936}1493714938// Select 2 colors along the principle axis. (There must be a faster/simpler way.)14939int total_r = fr, total_g = fg, total_b = fb;14940int max_r = fr, max_g = fg, max_b = fb;14941int min_r = fr, min_g = fg, min_b = fb;14942for (uint32_t i = 1; i < 16; i++)14943{14944const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;14945max_r = basisu::maximum(max_r, r); max_g = basisu::maximum(max_g, g); max_b = basisu::maximum(max_b, b);14946min_r = basisu::minimum(min_r, r); min_g = basisu::minimum(min_g, g); min_b = basisu::minimum(min_b, b);14947total_r += r; total_g += g; total_b += b;14948}1494914950avg_r = (total_r + 8) >> 4;14951avg_g = (total_g + 8) >> 4;14952avg_b = (total_b + 8) >> 4;1495314954int icov[6] = { 0, 0, 0, 0, 0, 0 };14955for (uint32_t i = 0; i < 16; i++)14956{14957int r = (int)pSrc_pixels[i].r - avg_r;14958int g = (int)pSrc_pixels[i].g - avg_g;14959int b = (int)pSrc_pixels[i].b - avg_b;14960icov[0] += r * r;14961icov[1] += r * g;14962icov[2] += r * b;14963icov[3] += g * g;14964icov[4] += g * b;14965icov[5] += b * b;14966}1496714968float cov[6];14969for (uint32_t i = 0; i < 6; i++)14970cov[i] = static_cast<float>(icov[i])* (1.0f / 255.0f);1497114972#if 014973// Seems silly to use full PCA to choose 2 colors. The diff in avg. PSNR between using PCA vs. not is small (~.025 difference).14974// TODO: Try 2 or 3 different normalized diagonal vectors, choose the one that results in the largest dot delta14975int saxis_r = max_r - min_r;14976int saxis_g = max_g - min_g;14977int saxis_b = max_b - min_b;14978#else14979float xr = (float)(max_r - min_r);14980float xg = (float)(max_g - min_g);14981float xb = (float)(max_b - min_b);14982//float xr = (float)(max_r - avg_r); // max-avg is nearly the same, and doesn't require computing min's14983//float xg = (float)(max_g - avg_g);14984//float xb = (float)(max_b - avg_b);14985for (uint32_t power_iter = 0; power_iter < 4; power_iter++)14986{14987float r = xr * cov[0] + xg * cov[1] + xb * cov[2];14988float g = xr * cov[1] + xg * cov[3] + xb * cov[4];14989float b = xr * cov[2] + xg * cov[4] + xb * cov[5];14990xr = r; xg = g; xb = b;14991}1499214993float k = basisu::maximum(fabsf(xr), fabsf(xg), fabsf(xb));14994int saxis_r = 306, saxis_g = 601, saxis_b = 117;14995if (k >= 2)14996{14997float m = 1024.0f / k;14998saxis_r = (int)(xr * m);14999saxis_g = (int)(xg * m);15000saxis_b = (int)(xb * m);15001}15002#endif1500315004int low_dot = INT_MAX, high_dot = INT_MIN, low_c = 0, high_c = 0;15005for (uint32_t i = 0; i < 16; i++)15006{15007int dot = pSrc_pixels[i].r * saxis_r + pSrc_pixels[i].g * saxis_g + pSrc_pixels[i].b * saxis_b;15008if (dot < low_dot)15009{15010low_dot = dot;15011low_c = i;15012}15013if (dot > high_dot)15014{15015high_dot = dot;15016high_c = i;15017}15018}1501915020lr = to_5(pSrc_pixels[low_c].r);15021lg = to_6(pSrc_pixels[low_c].g);15022lb = to_5(pSrc_pixels[low_c].b);1502315024hr = to_5(pSrc_pixels[high_c].r);15025hg = to_6(pSrc_pixels[high_c].g);15026hb = to_5(pSrc_pixels[high_c].b);1502715028bc1_find_sels(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels);15029} // if (use_sels)1503015031const uint32_t total_ls_passes = (flags & cEncodeBC1HigherQuality) ? 3 : (flags & cEncodeBC1HighQuality ? 2 : 1);15032for (uint32_t ls_pass = 0; ls_pass < total_ls_passes; ls_pass++)15033{15034// This is where the real magic happens. We have an array of candidate selectors, so let's use least squares to compute the optimal low/high endpoint colors.15035vec3F xl, xh;15036if (!compute_least_squares_endpoints_rgb(pSrc_pixels, sels, &xl, &xh))15037{15038if (avg_r < 0)15039{15040int total_r = 0, total_g = 0, total_b = 0;15041for (uint32_t i = 0; i < 16; i++)15042{15043total_r += pSrc_pixels[i].r;15044total_g += pSrc_pixels[i].g;15045total_b += pSrc_pixels[i].b;15046}1504715048avg_r = (total_r + 8) >> 4;15049avg_g = (total_g + 8) >> 4;15050avg_b = (total_b + 8) >> 4;15051}1505215053// All selectors equal - treat it as a solid block which should always be equal or better.15054lr = g_bc1_match5_equals_1[avg_r].m_hi;15055lg = g_bc1_match6_equals_1[avg_g].m_hi;15056lb = g_bc1_match5_equals_1[avg_b].m_hi;1505715058hr = g_bc1_match5_equals_1[avg_r].m_lo;15059hg = g_bc1_match6_equals_1[avg_g].m_lo;15060hb = g_bc1_match5_equals_1[avg_b].m_lo;1506115062// In high/higher quality mode, let it try again in case the optimal tables have caused the sels to diverge.15063}15064else15065{15066lr = basisu::clamp((int)((xl.c[0]) * (31.0f / 255.0f) + .5f), 0, 31);15067lg = basisu::clamp((int)((xl.c[1]) * (63.0f / 255.0f) + .5f), 0, 63);15068lb = basisu::clamp((int)((xl.c[2]) * (31.0f / 255.0f) + .5f), 0, 31);1506915070hr = basisu::clamp((int)((xh.c[0]) * (31.0f / 255.0f) + .5f), 0, 31);15071hg = basisu::clamp((int)((xh.c[1]) * (63.0f / 255.0f) + .5f), 0, 63);15072hb = basisu::clamp((int)((xh.c[2]) * (31.0f / 255.0f) + .5f), 0, 31);15073}1507415075bc1_find_sels(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels);15076}1507715078uint32_t lc16 = dxt1_block::pack_unscaled_color(lr, lg, lb);15079uint32_t hc16 = dxt1_block::pack_unscaled_color(hr, hg, hb);1508015081// Always forbid 3 color blocks15082if (lc16 == hc16)15083{15084uint8_t mask = 0;1508515086// Make l > h15087if (hc16 > 0)15088hc16--;15089else15090{15091// lc16 = hc16 = 015092assert(lc16 == hc16 && hc16 == 0);1509315094hc16 = 0;15095lc16 = 1;15096mask = 0x55; // select hc1615097}1509815099assert(lc16 > hc16);15100pDst_block->set_low_color(static_cast<uint16_t>(lc16));15101pDst_block->set_high_color(static_cast<uint16_t>(hc16));1510215103pDst_block->m_selectors[0] = mask;15104pDst_block->m_selectors[1] = mask;15105pDst_block->m_selectors[2] = mask;15106pDst_block->m_selectors[3] = mask;15107}15108else15109{15110uint8_t invert_mask = 0;15111if (lc16 < hc16)15112{15113std::swap(lc16, hc16);15114invert_mask = 0x55;15115}1511615117assert(lc16 > hc16);15118pDst_block->set_low_color((uint16_t)lc16);15119pDst_block->set_high_color((uint16_t)hc16);1512015121uint32_t packed_sels = 0;15122static const uint8_t s_sel_trans[4] = { 0, 2, 3, 1 };15123for (uint32_t i = 0; i < 16; i++)15124packed_sels |= ((uint32_t)s_sel_trans[sels[i]] << (i * 2));1512515126pDst_block->m_selectors[0] = (uint8_t)packed_sels ^ invert_mask;15127pDst_block->m_selectors[1] = (uint8_t)(packed_sels >> 8) ^ invert_mask;15128pDst_block->m_selectors[2] = (uint8_t)(packed_sels >> 16) ^ invert_mask;15129pDst_block->m_selectors[3] = (uint8_t)(packed_sels >> 24) ^ invert_mask;15130}15131}1513215133void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags)15134{15135const color32* pSrc_pixels = (const color32*)pPixels;15136dxt1_block* pDst_block = static_cast<dxt1_block*>(pDst);1513715138int avg_r = -1, avg_g = 0, avg_b = 0;15139int lr = 0, lg = 0, lb = 0, hr = 0, hg = 0, hb = 0;15140uint8_t sels[16];1514115142const bool use_sels = (flags & cEncodeBC1UseSelectors) != 0;15143if (use_sels)15144{15145// Caller is jamming in their own selectors for us to try.15146const uint32_t s = pDst_block->m_selectors[0] | (pDst_block->m_selectors[1] << 8) | (pDst_block->m_selectors[2] << 16) | (pDst_block->m_selectors[3] << 24);1514715148static const uint8_t s_sel_tran[4] = { 0, 3, 1, 2 };1514915150for (uint32_t i = 0; i < 16; i++)15151sels[i] = s_sel_tran[(s >> (i * 2)) & 3];15152}15153else15154{15155const uint32_t fr = pSrc_pixels[0].r, fg = pSrc_pixels[0].g, fb = pSrc_pixels[0].b;1515615157uint32_t j;15158for (j = 1; j < 16; j++)15159if ((pSrc_pixels[j].r != fr) || (pSrc_pixels[j].g != fg) || (pSrc_pixels[j].b != fb))15160break;1516115162if (j == 16)15163{15164encode_bc1_solid_block(pDst, fr, fg, fb);15165return;15166}1516715168// Select 2 colors along the principle axis. (There must be a faster/simpler way.)15169int total_r = fr, total_g = fg, total_b = fb;15170int max_r = fr, max_g = fg, max_b = fb;15171int min_r = fr, min_g = fg, min_b = fb;15172uint32_t grayscale_flag = (fr == fg) && (fr == fb);15173for (uint32_t i = 1; i < 16; i++)15174{15175const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;15176grayscale_flag &= ((r == g) && (r == b));15177max_r = basisu::maximum(max_r, r); max_g = basisu::maximum(max_g, g); max_b = basisu::maximum(max_b, b);15178min_r = basisu::minimum(min_r, r); min_g = basisu::minimum(min_g, g); min_b = basisu::minimum(min_b, b);15179total_r += r; total_g += g; total_b += b;15180}1518115182if (grayscale_flag)15183{15184// Grayscale blocks are a common enough case to specialize.15185if ((max_r - min_r) < 2)15186{15187lr = lb = hr = hb = to_5(fr);15188lg = hg = to_6(fr);15189}15190else15191{15192lr = lb = to_5(min_r);15193lg = to_6(min_r);1519415195hr = hb = to_5(max_r);15196hg = to_6(max_r);15197}15198}15199else15200{15201avg_r = (total_r + 8) >> 4;15202avg_g = (total_g + 8) >> 4;15203avg_b = (total_b + 8) >> 4;1520415205// Find the shortest vector from a AABB corner to the block's average color.15206// This is to help avoid outliers.1520715208uint32_t dist[3][2];15209dist[0][0] = basisu::square(min_r - avg_r) << 3; dist[0][1] = basisu::square(max_r - avg_r) << 3;15210dist[1][0] = basisu::square(min_g - avg_g) << 3; dist[1][1] = basisu::square(max_g - avg_g) << 3;15211dist[2][0] = basisu::square(min_b - avg_b) << 3; dist[2][1] = basisu::square(max_b - avg_b) << 3;1521215213uint32_t min_d0 = (dist[0][0] + dist[1][0] + dist[2][0]);15214uint32_t d4 = (dist[0][0] + dist[1][0] + dist[2][1]) | 4;15215min_d0 = basisu::minimum(min_d0, d4);1521615217uint32_t min_d1 = (dist[0][1] + dist[1][0] + dist[2][0]) | 1;15218uint32_t d5 = (dist[0][1] + dist[1][0] + dist[2][1]) | 5;15219min_d1 = basisu::minimum(min_d1, d5);1522015221uint32_t d2 = (dist[0][0] + dist[1][1] + dist[2][0]) | 2;15222min_d0 = basisu::minimum(min_d0, d2);1522315224uint32_t d3 = (dist[0][1] + dist[1][1] + dist[2][0]) | 3;15225min_d1 = basisu::minimum(min_d1, d3);1522615227uint32_t d6 = (dist[0][0] + dist[1][1] + dist[2][1]) | 6;15228min_d0 = basisu::minimum(min_d0, d6);1522915230uint32_t d7 = (dist[0][1] + dist[1][1] + dist[2][1]) | 7;15231min_d1 = basisu::minimum(min_d1, d7);1523215233uint32_t min_d = basisu::minimum(min_d0, min_d1);15234uint32_t best_i = min_d & 7;1523515236int delta_r = (best_i & 1) ? (max_r - avg_r) : (avg_r - min_r);15237int delta_g = (best_i & 2) ? (max_g - avg_g) : (avg_g - min_g);15238int delta_b = (best_i & 4) ? (max_b - avg_b) : (avg_b - min_b);1523915240// Note: if delta_r/g/b==0, we actually want to choose a single color, so the block average color optimization kicks in.15241uint32_t low_c = 0, high_c = 0;15242if ((delta_r | delta_g | delta_b) != 0)15243{15244// Now we have a smaller AABB going from the block's average color to a cornerpoint of the larger AABB.15245// Project all pixels colors along the 4 vectors going from a smaller AABB cornerpoint to the opposite cornerpoint, find largest projection.15246// One of these vectors will be a decent approximation of the block's PCA.15247const int saxis0_r = delta_r, saxis0_g = delta_g, saxis0_b = delta_b;1524815249int low_dot0 = INT_MAX, high_dot0 = INT_MIN;15250int low_dot1 = INT_MAX, high_dot1 = INT_MIN;15251int low_dot2 = INT_MAX, high_dot2 = INT_MIN;15252int low_dot3 = INT_MAX, high_dot3 = INT_MIN;1525315254//int low_c0, low_c1, low_c2, low_c3;15255//int high_c0, high_c1, high_c2, high_c3;1525615257for (uint32_t i = 0; i < 16; i++)15258{15259const int dotx = pSrc_pixels[i].r * saxis0_r;15260const int doty = pSrc_pixels[i].g * saxis0_g;15261const int dotz = pSrc_pixels[i].b * saxis0_b;1526215263const int dot0 = ((dotz + dotx + doty) << 4) + i;15264const int dot1 = ((dotz - dotx - doty) << 4) + i;15265const int dot2 = ((dotz - dotx + doty) << 4) + i;15266const int dot3 = ((dotz + dotx - doty) << 4) + i;1526715268if (dot0 < low_dot0)15269{15270low_dot0 = dot0;15271//low_c0 = i;15272}15273if ((dot0 ^ 15) > high_dot0)15274{15275high_dot0 = dot0 ^ 15;15276//high_c0 = i;15277}1527815279if (dot1 < low_dot1)15280{15281low_dot1 = dot1;15282//low_c1 = i;15283}15284if ((dot1 ^ 15) > high_dot1)15285{15286high_dot1 = dot1 ^ 15;15287//high_c1 = i;15288}1528915290if (dot2 < low_dot2)15291{15292low_dot2 = dot2;15293//low_c2 = i;15294}15295if ((dot2 ^ 15) > high_dot2)15296{15297high_dot2 = dot2 ^ 15;15298//high_c2 = i;15299}1530015301if (dot3 < low_dot3)15302{15303low_dot3 = dot3;15304//low_c3 = i;15305}15306if ((dot3 ^ 15) > high_dot3)15307{15308high_dot3 = dot3 ^ 15;15309//high_c3 = i;15310}15311}1531215313low_c = low_dot0 & 15;15314high_c = ~high_dot0 & 15;15315uint32_t r = (high_dot0 & ~15) - (low_dot0 & ~15);1531615317uint32_t tr = (high_dot1 & ~15) - (low_dot1 & ~15);15318if (tr > r) {15319low_c = low_dot1 & 15;15320high_c = ~high_dot1 & 15;15321r = tr;15322}1532315324tr = (high_dot2 & ~15) - (low_dot2 & ~15);15325if (tr > r) {15326low_c = low_dot2 & 15;15327high_c = ~high_dot2 & 15;15328r = tr;15329}1533015331tr = (high_dot3 & ~15) - (low_dot3 & ~15);15332if (tr > r) {15333low_c = low_dot3 & 15;15334high_c = ~high_dot3 & 15;15335}15336}1533715338lr = to_5(pSrc_pixels[low_c].r);15339lg = to_6(pSrc_pixels[low_c].g);15340lb = to_5(pSrc_pixels[low_c].b);1534115342hr = to_5(pSrc_pixels[high_c].r);15343hg = to_6(pSrc_pixels[high_c].g);15344hb = to_5(pSrc_pixels[high_c].b);15345}1534615347bc1_find_sels_2(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels);15348} // if (use_sels)1534915350const uint32_t total_ls_passes = (flags & cEncodeBC1HigherQuality) ? 3 : (flags & cEncodeBC1HighQuality ? 2 : 1);15351for (uint32_t ls_pass = 0; ls_pass < total_ls_passes; ls_pass++)15352{15353int prev_lr = lr, prev_lg = lg, prev_lb = lb, prev_hr = hr, prev_hg = hg, prev_hb = hb;1535415355// This is where the real magic happens. We have an array of candidate selectors, so let's use least squares to compute the optimal low/high endpoint colors.15356vec3F xl, xh;15357if (!compute_least_squares_endpoints_rgb(pSrc_pixels, sels, &xl, &xh))15358{15359if (avg_r < 0)15360{15361int total_r = 0, total_g = 0, total_b = 0;15362for (uint32_t i = 0; i < 16; i++)15363{15364total_r += pSrc_pixels[i].r;15365total_g += pSrc_pixels[i].g;15366total_b += pSrc_pixels[i].b;15367}1536815369avg_r = (total_r + 8) >> 4;15370avg_g = (total_g + 8) >> 4;15371avg_b = (total_b + 8) >> 4;15372}1537315374// All selectors equal - treat it as a solid block which should always be equal or better.15375lr = g_bc1_match5_equals_1[avg_r].m_hi;15376lg = g_bc1_match6_equals_1[avg_g].m_hi;15377lb = g_bc1_match5_equals_1[avg_b].m_hi;1537815379hr = g_bc1_match5_equals_1[avg_r].m_lo;15380hg = g_bc1_match6_equals_1[avg_g].m_lo;15381hb = g_bc1_match5_equals_1[avg_b].m_lo;1538215383// In high/higher quality mode, let it try again in case the optimal tables have caused the sels to diverge.15384}15385else15386{15387lr = basisu::clamp((int)((xl.c[0]) * (31.0f / 255.0f) + .5f), 0, 31);15388lg = basisu::clamp((int)((xl.c[1]) * (63.0f / 255.0f) + .5f), 0, 63);15389lb = basisu::clamp((int)((xl.c[2]) * (31.0f / 255.0f) + .5f), 0, 31);1539015391hr = basisu::clamp((int)((xh.c[0]) * (31.0f / 255.0f) + .5f), 0, 31);15392hg = basisu::clamp((int)((xh.c[1]) * (63.0f / 255.0f) + .5f), 0, 63);15393hb = basisu::clamp((int)((xh.c[2]) * (31.0f / 255.0f) + .5f), 0, 31);15394}1539515396if ((prev_lr == lr) && (prev_lg == lg) && (prev_lb == lb) && (prev_hr == hr) && (prev_hg == hg) && (prev_hb == hb))15397break;1539815399bc1_find_sels_2(pSrc_pixels, lr, lg, lb, hr, hg, hb, sels);15400}1540115402uint32_t lc16 = dxt1_block::pack_unscaled_color(lr, lg, lb);15403uint32_t hc16 = dxt1_block::pack_unscaled_color(hr, hg, hb);1540415405// Always forbid 3 color blocks15406if (lc16 == hc16)15407{15408uint8_t mask = 0;1540915410// Make l > h15411if (hc16 > 0)15412hc16--;15413else15414{15415// lc16 = hc16 = 015416assert(lc16 == hc16 && hc16 == 0);1541715418hc16 = 0;15419lc16 = 1;15420mask = 0x55; // select hc1615421}1542215423assert(lc16 > hc16);15424pDst_block->set_low_color(static_cast<uint16_t>(lc16));15425pDst_block->set_high_color(static_cast<uint16_t>(hc16));1542615427pDst_block->m_selectors[0] = mask;15428pDst_block->m_selectors[1] = mask;15429pDst_block->m_selectors[2] = mask;15430pDst_block->m_selectors[3] = mask;15431}15432else15433{15434uint8_t invert_mask = 0;15435if (lc16 < hc16)15436{15437std::swap(lc16, hc16);15438invert_mask = 0x55;15439}1544015441assert(lc16 > hc16);15442pDst_block->set_low_color((uint16_t)lc16);15443pDst_block->set_high_color((uint16_t)hc16);1544415445uint32_t packed_sels = 0;15446static const uint8_t s_sel_trans[4] = { 0, 2, 3, 1 };15447for (uint32_t i = 0; i < 16; i++)15448packed_sels |= ((uint32_t)s_sel_trans[sels[i]] << (i * 2));1544915450pDst_block->m_selectors[0] = (uint8_t)packed_sels ^ invert_mask;15451pDst_block->m_selectors[1] = (uint8_t)(packed_sels >> 8) ^ invert_mask;15452pDst_block->m_selectors[2] = (uint8_t)(packed_sels >> 16) ^ invert_mask;15453pDst_block->m_selectors[3] = (uint8_t)(packed_sels >> 24) ^ invert_mask;15454}15455}1545615457// Scale the UASTC first subset endpoints and first plane's weight indices directly to BC1's - fastest.15458void transcode_uastc_to_bc1_hint0(const unpacked_uastc_block& unpacked_src_blk, void* pDst)15459{15460const uint32_t mode = unpacked_src_blk.m_mode;15461const astc_block_desc& astc_blk = unpacked_src_blk.m_astc;1546215463dxt1_block& b = *static_cast<dxt1_block*>(pDst);1546415465const uint32_t endpoint_range = g_uastc_mode_endpoint_ranges[mode];1546615467const uint32_t total_comps = g_uastc_mode_comps[mode];1546815469if (total_comps == 2)15470{15471const uint32_t l = g_astc_unquant[endpoint_range][astc_blk.m_endpoints[0]].m_unquant;15472const uint32_t h = g_astc_unquant[endpoint_range][astc_blk.m_endpoints[1]].m_unquant;1547315474b.set_low_color(dxt1_block::pack_color(color32(l, l, l, 255), true, 127));15475b.set_high_color(dxt1_block::pack_color(color32(h, h, h, 255), true, 127));15476}15477else15478{15479b.set_low_color(dxt1_block::pack_color(15480color32(g_astc_unquant[endpoint_range][astc_blk.m_endpoints[0]].m_unquant,15481g_astc_unquant[endpoint_range][astc_blk.m_endpoints[2]].m_unquant,15482g_astc_unquant[endpoint_range][astc_blk.m_endpoints[4]].m_unquant,15483255), true, 127)15484);1548515486b.set_high_color(dxt1_block::pack_color(15487color32(g_astc_unquant[endpoint_range][astc_blk.m_endpoints[1]].m_unquant,15488g_astc_unquant[endpoint_range][astc_blk.m_endpoints[3]].m_unquant,15489g_astc_unquant[endpoint_range][astc_blk.m_endpoints[5]].m_unquant,15490255), true, 127)15491);15492}1549315494if (b.get_low_color() == b.get_high_color())15495{15496// Always forbid 3 color blocks15497uint16_t lc16 = (uint16_t)b.get_low_color();15498uint16_t hc16 = (uint16_t)b.get_high_color();1549915500uint8_t mask = 0;1550115502// Make l > h15503if (hc16 > 0)15504hc16--;15505else15506{15507// lc16 = hc16 = 015508assert(lc16 == hc16 && hc16 == 0);1550915510hc16 = 0;15511lc16 = 1;15512mask = 0x55; // select hc1615513}1551415515assert(lc16 > hc16);15516b.set_low_color(static_cast<uint16_t>(lc16));15517b.set_high_color(static_cast<uint16_t>(hc16));1551815519b.m_selectors[0] = mask;15520b.m_selectors[1] = mask;15521b.m_selectors[2] = mask;15522b.m_selectors[3] = mask;15523}15524else15525{15526bool invert = false;15527if (b.get_low_color() < b.get_high_color())15528{15529std::swap(b.m_low_color[0], b.m_high_color[0]);15530std::swap(b.m_low_color[1], b.m_high_color[1]);15531invert = true;15532}1553315534const uint8_t* pTran = s_uastc_to_bc1_weights[g_uastc_mode_weight_bits[mode]];1553515536const uint32_t plane_shift = g_uastc_mode_planes[mode] - 1;1553715538uint32_t sels = 0;15539for (int i = 15; i >= 0; --i)15540{15541uint32_t s = pTran[astc_blk.m_weights[i << plane_shift]];1554215543if (invert)15544s ^= 1;1554515546sels = (sels << 2) | s;15547}15548b.m_selectors[0] = sels & 0xFF;15549b.m_selectors[1] = (sels >> 8) & 0xFF;15550b.m_selectors[2] = (sels >> 16) & 0xFF;15551b.m_selectors[3] = (sels >> 24) & 0xFF;15552}15553}1555415555// Scale the UASTC first plane's weight indices to BC1, use 1 or 2 least squares passes to compute endpoints - no PCA needed.15556void transcode_uastc_to_bc1_hint1(const unpacked_uastc_block& unpacked_src_blk, const color32 block_pixels[4][4], void* pDst, bool high_quality)15557{15558const uint32_t mode = unpacked_src_blk.m_mode;1555915560const astc_block_desc& astc_blk = unpacked_src_blk.m_astc;1556115562dxt1_block& b = *static_cast<dxt1_block*>(pDst);1556315564b.set_low_color(1);15565b.set_high_color(0);1556615567const uint8_t* pTran = s_uastc_to_bc1_weights[g_uastc_mode_weight_bits[mode]];1556815569const uint32_t plane_shift = g_uastc_mode_planes[mode] - 1;1557015571uint32_t sels = 0;15572for (int i = 15; i >= 0; --i)15573{15574sels <<= 2;15575sels |= pTran[astc_blk.m_weights[i << plane_shift]];15576}1557715578b.m_selectors[0] = sels & 0xFF;15579b.m_selectors[1] = (sels >> 8) & 0xFF;15580b.m_selectors[2] = (sels >> 16) & 0xFF;15581b.m_selectors[3] = (sels >> 24) & 0xFF;1558215583encode_bc1(&b, (const uint8_t*)&block_pixels[0][0].c[0], (high_quality ? cEncodeBC1HighQuality : 0) | cEncodeBC1UseSelectors);15584}1558515586bool transcode_uastc_to_bc1(const uastc_block& src_blk, void* pDst, bool high_quality)15587{15588unpacked_uastc_block unpacked_src_blk;15589if (!unpack_uastc(src_blk, unpacked_src_blk, false))15590return false;1559115592const uint32_t mode = unpacked_src_blk.m_mode;1559315594if (mode == UASTC_MODE_INDEX_SOLID_COLOR)15595{15596encode_bc1_solid_block(pDst, unpacked_src_blk.m_solid_color.r, unpacked_src_blk.m_solid_color.g, unpacked_src_blk.m_solid_color.b);15597return true;15598}1559915600if ((!high_quality) && (unpacked_src_blk.m_bc1_hint0))15601transcode_uastc_to_bc1_hint0(unpacked_src_blk, pDst);15602else15603{15604color32 block_pixels[4][4];15605const bool unpack_srgb = false;15606if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))15607return false;1560815609if (unpacked_src_blk.m_bc1_hint1)15610transcode_uastc_to_bc1_hint1(unpacked_src_blk, block_pixels, pDst, high_quality);15611else15612encode_bc1(pDst, &block_pixels[0][0].r, high_quality ? cEncodeBC1HighQuality : 0);15613}1561415615return true;15616}1561715618static void write_bc4_solid_block(uint8_t* pDst, uint32_t a)15619{15620pDst[0] = (uint8_t)a;15621pDst[1] = (uint8_t)a;15622memset(pDst + 2, 0, 6);15623}1562415625bool transcode_uastc_to_bc3(const uastc_block& src_blk, void* pDst, bool high_quality)15626{15627unpacked_uastc_block unpacked_src_blk;15628if (!unpack_uastc(src_blk, unpacked_src_blk, false))15629return false;1563015631const uint32_t mode = unpacked_src_blk.m_mode;1563215633void* pBC4_block = pDst;15634dxt1_block* pBC1_block = &static_cast<dxt1_block*>(pDst)[1];1563515636if (mode == UASTC_MODE_INDEX_SOLID_COLOR)15637{15638write_bc4_solid_block(static_cast<uint8_t*>(pBC4_block), unpacked_src_blk.m_solid_color.a);15639encode_bc1_solid_block(pBC1_block, unpacked_src_blk.m_solid_color.r, unpacked_src_blk.m_solid_color.g, unpacked_src_blk.m_solid_color.b);15640return true;15641}1564215643color32 block_pixels[4][4];15644const bool unpack_srgb = false;15645if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))15646return false;1564715648basist::encode_bc4(pBC4_block, &block_pixels[0][0].a, sizeof(color32));1564915650if ((!high_quality) && (unpacked_src_blk.m_bc1_hint0))15651transcode_uastc_to_bc1_hint0(unpacked_src_blk, pBC1_block);15652else15653{15654if (unpacked_src_blk.m_bc1_hint1)15655transcode_uastc_to_bc1_hint1(unpacked_src_blk, block_pixels, pBC1_block, high_quality);15656else15657encode_bc1(pBC1_block, &block_pixels[0][0].r, high_quality ? cEncodeBC1HighQuality : 0);15658}1565915660return true;15661}1566215663bool transcode_uastc_to_bc4(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0)15664{15665BASISU_NOTE_UNUSED(high_quality);1566615667unpacked_uastc_block unpacked_src_blk;15668if (!unpack_uastc(src_blk, unpacked_src_blk, false))15669return false;1567015671const uint32_t mode = unpacked_src_blk.m_mode;1567215673void* pBC4_block = pDst;1567415675if (mode == UASTC_MODE_INDEX_SOLID_COLOR)15676{15677write_bc4_solid_block(static_cast<uint8_t*>(pBC4_block), unpacked_src_blk.m_solid_color.c[chan0]);15678return true;15679}1568015681color32 block_pixels[4][4];15682const bool unpack_srgb = false;15683if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))15684return false;1568515686basist::encode_bc4(pBC4_block, &block_pixels[0][0].c[chan0], sizeof(color32));1568715688return true;15689}1569015691bool transcode_uastc_to_bc5(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1)15692{15693BASISU_NOTE_UNUSED(high_quality);1569415695unpacked_uastc_block unpacked_src_blk;15696if (!unpack_uastc(src_blk, unpacked_src_blk, false))15697return false;1569815699const uint32_t mode = unpacked_src_blk.m_mode;1570015701void* pBC4_block0 = pDst;15702void* pBC4_block1 = (uint8_t*)pDst + 8;1570315704if (mode == UASTC_MODE_INDEX_SOLID_COLOR)15705{15706write_bc4_solid_block(static_cast<uint8_t*>(pBC4_block0), unpacked_src_blk.m_solid_color.c[chan0]);15707write_bc4_solid_block(static_cast<uint8_t*>(pBC4_block1), unpacked_src_blk.m_solid_color.c[chan1]);15708return true;15709}1571015711color32 block_pixels[4][4];15712const bool unpack_srgb = false;15713if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))15714return false;1571515716basist::encode_bc4(pBC4_block0, &block_pixels[0][0].c[chan0], sizeof(color32));15717basist::encode_bc4(pBC4_block1, &block_pixels[0][0].c[chan1], sizeof(color32));1571815719return true;15720}1572115722static const uint8_t s_etc2_eac_bit_ofs[16] = { 45, 33, 21, 9, 42, 30, 18, 6, 39, 27, 15, 3, 36, 24, 12, 0 };1572315724static void pack_eac_solid_block(eac_block& blk, uint32_t a)15725{15726blk.m_base = static_cast<uint8_t>(a);15727blk.m_table = 13;15728blk.m_multiplier = 0;1572915730memcpy(blk.m_selectors, g_etc2_eac_a8_sel4, sizeof(g_etc2_eac_a8_sel4));1573115732return;15733}1573415735// Only checks 4 tables.15736static void pack_eac(eac_block& blk, const uint8_t* pPixels, uint32_t stride)15737{15738uint32_t min_alpha = 255, max_alpha = 0;15739for (uint32_t i = 0; i < 16; i++)15740{15741const uint32_t a = pPixels[i * stride];15742if (a < min_alpha) min_alpha = a;15743if (a > max_alpha) max_alpha = a;15744}1574515746if (min_alpha == max_alpha)15747{15748pack_eac_solid_block(blk, min_alpha);15749return;15750}1575115752const uint32_t alpha_range = max_alpha - min_alpha;1575315754const uint32_t SINGLE_TABLE_THRESH = 5;15755if (alpha_range <= SINGLE_TABLE_THRESH)15756{15757// If alpha_range <= 5 table 13 is lossless15758int base = clamp255((int)max_alpha - 2);1575915760blk.m_base = base;15761blk.m_multiplier = 1;15762blk.m_table = 13;1576315764base -= 3;1576515766uint64_t packed_sels = 0;15767for (uint32_t i = 0; i < 16; i++)15768{15769const int a = pPixels[i * stride];1577015771static const uint8_t s_sels[6] = { 2, 1, 0, 4, 5, 6 };1577215773int sel = a - base;15774assert(sel >= 0 && sel <= 5);1577515776packed_sels |= (static_cast<uint64_t>(s_sels[sel]) << s_etc2_eac_bit_ofs[i]);15777}1577815779blk.set_selector_bits(packed_sels);1578015781return;15782}1578315784const uint32_t T0 = 2, T1 = 8, T2 = 11, T3 = 13;15785static const uint8_t s_tables[4] = { T0, T1, T2, T3 };1578615787int base[4], mul[4];15788uint32_t mul_or = 0;15789for (uint32_t i = 0; i < 4; i++)15790{15791const uint32_t table = s_tables[i];1579215793const float range = (float)(g_eac_modifier_table[table][ETC2_EAC_MAX_VALUE_SELECTOR] - g_eac_modifier_table[table][ETC2_EAC_MIN_VALUE_SELECTOR]);1579415795base[i] = clamp255((int)roundf(basisu::lerp((float)min_alpha, (float)max_alpha, (float)(0 - g_eac_modifier_table[table][ETC2_EAC_MIN_VALUE_SELECTOR]) / range)));15796mul[i] = clampi((int)roundf(alpha_range / range), 1, 15);15797mul_or |= mul[i];15798}1579915800uint32_t total_err[4] = { 0, 0, 0, 0 };15801uint8_t sels[4][16];1580215803for (uint32_t i = 0; i < 16; i++)15804{15805const int a = pPixels[i * stride];1580615807uint32_t l0 = UINT32_MAX, l1 = UINT32_MAX, l2 = UINT32_MAX, l3 = UINT32_MAX;1580815809if ((a < 7) || (a > (255 - 7)))15810{15811for (uint32_t s = 0; s < 8; s++)15812{15813const int v0 = clamp255(mul[0] * g_eac_modifier_table[T0][s] + base[0]);15814const int v1 = clamp255(mul[1] * g_eac_modifier_table[T1][s] + base[1]);15815const int v2 = clamp255(mul[2] * g_eac_modifier_table[T2][s] + base[2]);15816const int v3 = clamp255(mul[3] * g_eac_modifier_table[T3][s] + base[3]);1581715818l0 = basisu::minimum(l0, (basisu::iabs(v0 - a) << 3) | s);15819l1 = basisu::minimum(l1, (basisu::iabs(v1 - a) << 3) | s);15820l2 = basisu::minimum(l2, (basisu::iabs(v2 - a) << 3) | s);15821l3 = basisu::minimum(l3, (basisu::iabs(v3 - a) << 3) | s);15822}15823}15824else if (mul_or == 1)15825{15826const int a0 = base[0] - a, a1 = base[1] - a, a2 = base[2] - a, a3 = base[3] - a;1582715828for (uint32_t s = 0; s < 8; s++)15829{15830const int v0 = g_eac_modifier_table[T0][s] + a0;15831const int v1 = g_eac_modifier_table[T1][s] + a1;15832const int v2 = g_eac_modifier_table[T2][s] + a2;15833const int v3 = g_eac_modifier_table[T3][s] + a3;1583415835l0 = basisu::minimum(l0, (basisu::iabs(v0) << 3) | s);15836l1 = basisu::minimum(l1, (basisu::iabs(v1) << 3) | s);15837l2 = basisu::minimum(l2, (basisu::iabs(v2) << 3) | s);15838l3 = basisu::minimum(l3, (basisu::iabs(v3) << 3) | s);15839}15840}15841else15842{15843const int a0 = base[0] - a, a1 = base[1] - a, a2 = base[2] - a, a3 = base[3] - a;1584415845for (uint32_t s = 0; s < 8; s++)15846{15847const int v0 = mul[0] * g_eac_modifier_table[T0][s] + a0;15848const int v1 = mul[1] * g_eac_modifier_table[T1][s] + a1;15849const int v2 = mul[2] * g_eac_modifier_table[T2][s] + a2;15850const int v3 = mul[3] * g_eac_modifier_table[T3][s] + a3;1585115852l0 = basisu::minimum(l0, (basisu::iabs(v0) << 3) | s);15853l1 = basisu::minimum(l1, (basisu::iabs(v1) << 3) | s);15854l2 = basisu::minimum(l2, (basisu::iabs(v2) << 3) | s);15855l3 = basisu::minimum(l3, (basisu::iabs(v3) << 3) | s);15856}15857}1585815859sels[0][i] = l0 & 7;15860sels[1][i] = l1 & 7;15861sels[2][i] = l2 & 7;15862sels[3][i] = l3 & 7;1586315864total_err[0] += basisu::square<uint32_t>(l0 >> 3);15865total_err[1] += basisu::square<uint32_t>(l1 >> 3);15866total_err[2] += basisu::square<uint32_t>(l2 >> 3);15867total_err[3] += basisu::square<uint32_t>(l3 >> 3);15868}1586915870uint32_t min_err = total_err[0], min_index = 0;15871for (uint32_t i = 1; i < 4; i++)15872{15873if (total_err[i] < min_err)15874{15875min_err = total_err[i];15876min_index = i;15877}15878}1587915880blk.m_base = base[min_index];15881blk.m_multiplier = mul[min_index];15882blk.m_table = s_tables[min_index];1588315884uint64_t packed_sels = 0;15885const uint8_t* pSels = &sels[min_index][0];15886for (uint32_t i = 0; i < 16; i++)15887packed_sels |= (static_cast<uint64_t>(pSels[i]) << s_etc2_eac_bit_ofs[i]);1588815889blk.set_selector_bits(packed_sels);15890}1589115892// Checks all 16 tables. Around ~2 dB better vs. pack_eac(), ~1.2 dB less than near-optimal.15893static void pack_eac_high_quality(eac_block& blk, const uint8_t* pPixels, uint32_t stride)15894{15895uint32_t min_alpha = 255, max_alpha = 0;15896for (uint32_t i = 0; i < 16; i++)15897{15898const uint32_t a = pPixels[i * stride];15899if (a < min_alpha) min_alpha = a;15900if (a > max_alpha) max_alpha = a;15901}1590215903if (min_alpha == max_alpha)15904{15905pack_eac_solid_block(blk, min_alpha);15906return;15907}1590815909const uint32_t alpha_range = max_alpha - min_alpha;1591015911const uint32_t SINGLE_TABLE_THRESH = 5;15912if (alpha_range <= SINGLE_TABLE_THRESH)15913{15914// If alpha_range <= 5 table 13 is lossless15915int base = clamp255((int)max_alpha - 2);1591615917blk.m_base = base;15918blk.m_multiplier = 1;15919blk.m_table = 13;1592015921base -= 3;1592215923uint64_t packed_sels = 0;15924for (uint32_t i = 0; i < 16; i++)15925{15926const int a = pPixels[i * stride];1592715928static const uint8_t s_sels[6] = { 2, 1, 0, 4, 5, 6 };1592915930int sel = a - base;15931assert(sel >= 0 && sel <= 5);1593215933packed_sels |= (static_cast<uint64_t>(s_sels[sel]) << s_etc2_eac_bit_ofs[i]);15934}1593515936blk.set_selector_bits(packed_sels);1593715938return;15939}1594015941int base[16], mul[16];15942for (uint32_t table = 0; table < 16; table++)15943{15944const float range = (float)(g_eac_modifier_table[table][ETC2_EAC_MAX_VALUE_SELECTOR] - g_eac_modifier_table[table][ETC2_EAC_MIN_VALUE_SELECTOR]);1594515946base[table] = clamp255((int)roundf(basisu::lerp((float)min_alpha, (float)max_alpha, (float)(0 - g_eac_modifier_table[table][ETC2_EAC_MIN_VALUE_SELECTOR]) / range)));15947mul[table] = clampi((int)roundf(alpha_range / range), 1, 15);15948}1594915950uint32_t total_err[16];15951memset(total_err, 0, sizeof(total_err));1595215953uint8_t sels[16][16];1595415955for (uint32_t table = 0; table < 16; table++)15956{15957const int8_t* pTable = &g_eac_modifier_table[table][0];15958const int m = mul[table], b = base[table];1595915960uint32_t prev_l = 0, prev_a = UINT32_MAX;1596115962for (uint32_t i = 0; i < 16; i++)15963{15964const int a = pPixels[i * stride];1596515966if ((uint32_t)a == prev_a)15967{15968sels[table][i] = prev_l & 7;15969total_err[table] += basisu::square<uint32_t>(prev_l >> 3);15970}15971else15972{15973uint32_t l = basisu::iabs(clamp255(m * pTable[0] + b) - a) << 3;15974l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[1] + b) - a) << 3) | 1);15975l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[2] + b) - a) << 3) | 2);15976l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[3] + b) - a) << 3) | 3);15977l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[4] + b) - a) << 3) | 4);15978l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[5] + b) - a) << 3) | 5);15979l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[6] + b) - a) << 3) | 6);15980l = basisu::minimum(l, (basisu::iabs(clamp255(m * pTable[7] + b) - a) << 3) | 7);1598115982sels[table][i] = l & 7;15983total_err[table] += basisu::square<uint32_t>(l >> 3);1598415985prev_l = l;15986prev_a = a;15987}15988}15989}1599015991uint32_t min_err = total_err[0], min_index = 0;15992for (uint32_t i = 1; i < 16; i++)15993{15994if (total_err[i] < min_err)15995{15996min_err = total_err[i];15997min_index = i;15998}15999}1600016001blk.m_base = base[min_index];16002blk.m_multiplier = mul[min_index];16003blk.m_table = min_index;1600416005uint64_t packed_sels = 0;16006const uint8_t* pSels = &sels[min_index][0];16007for (uint32_t i = 0; i < 16; i++)16008packed_sels |= (static_cast<uint64_t>(pSels[i]) << s_etc2_eac_bit_ofs[i]);1600916010blk.set_selector_bits(packed_sels);16011}1601216013bool transcode_uastc_to_etc2_eac_r11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0)16014{16015unpacked_uastc_block unpacked_src_blk;16016if (!unpack_uastc(src_blk, unpacked_src_blk, false))16017return false;1601816019const uint32_t mode = unpacked_src_blk.m_mode;1602016021if (mode == UASTC_MODE_INDEX_SOLID_COLOR)16022{16023pack_eac_solid_block(*static_cast<eac_block*>(pDst), unpacked_src_blk.m_solid_color.c[chan0]);16024return true;16025}1602616027color32 block_pixels[4][4];16028const bool unpack_srgb = false;16029if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))16030return false;1603116032if (chan0 == 3)16033transcode_uastc_to_etc2_eac_a8(unpacked_src_blk, block_pixels, pDst);16034else16035(high_quality ? pack_eac_high_quality : pack_eac)(*static_cast<eac_block*>(pDst), &block_pixels[0][0].c[chan0], sizeof(color32));1603616037return true;16038}1603916040bool transcode_uastc_to_etc2_eac_rg11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1)16041{16042unpacked_uastc_block unpacked_src_blk;16043if (!unpack_uastc(src_blk, unpacked_src_blk, false))16044return false;1604516046const uint32_t mode = unpacked_src_blk.m_mode;1604716048if (mode == UASTC_MODE_INDEX_SOLID_COLOR)16049{16050pack_eac_solid_block(static_cast<eac_block*>(pDst)[0], unpacked_src_blk.m_solid_color.c[chan0]);16051pack_eac_solid_block(static_cast<eac_block*>(pDst)[1], unpacked_src_blk.m_solid_color.c[chan1]);16052return true;16053}1605416055color32 block_pixels[4][4];16056const bool unpack_srgb = false;16057if (!unpack_uastc(unpacked_src_blk, &block_pixels[0][0], unpack_srgb))16058return false;1605916060if (chan0 == 3)16061transcode_uastc_to_etc2_eac_a8(unpacked_src_blk, block_pixels, &static_cast<eac_block*>(pDst)[0]);16062else16063(high_quality ? pack_eac_high_quality : pack_eac)(static_cast<eac_block*>(pDst)[0], &block_pixels[0][0].c[chan0], sizeof(color32));1606416065if (chan1 == 3)16066transcode_uastc_to_etc2_eac_a8(unpacked_src_blk, block_pixels, &static_cast<eac_block*>(pDst)[1]);16067else16068(high_quality ? pack_eac_high_quality : pack_eac)(static_cast<eac_block*>(pDst)[1], &block_pixels[0][0].c[chan1], sizeof(color32));16069return true;16070}1607116072// PVRTC116073static void fixup_pvrtc1_4_modulation_rgb(16074const uastc_block* pSrc_blocks,16075const uint32_t* pPVRTC_endpoints,16076void* pDst_blocks,16077uint32_t num_blocks_x, uint32_t num_blocks_y, bool from_alpha)16078{16079const uint32_t x_mask = num_blocks_x - 1;16080const uint32_t y_mask = num_blocks_y - 1;16081const uint32_t x_bits = basisu::total_bits(x_mask);16082const uint32_t y_bits = basisu::total_bits(y_mask);16083const uint32_t min_bits = basisu::minimum(x_bits, y_bits);16084//const uint32_t max_bits = basisu::maximum(x_bits, y_bits);16085const uint32_t swizzle_mask = (1 << (min_bits * 2)) - 1;1608616087uint32_t block_index = 0;1608816089// really 3x316090int e0[4][4], e1[4][4];1609116092for (int y = 0; y < static_cast<int>(num_blocks_y); y++)16093{16094const uint32_t* pE_rows[3];1609516096for (int ey = 0; ey < 3; ey++)16097{16098int by = y + ey - 1;1609916100const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x];1610116102pE_rows[ey] = pE;1610316104for (int ex = 0; ex < 3; ex++)16105{16106int bx = 0 + ex - 1;1610716108const uint32_t e = pE[bx & x_mask];1610916110e0[ex][ey] = (get_opaque_endpoint_l0(e) * 255) / 31;16111e1[ex][ey] = (get_opaque_endpoint_l1(e) * 255) / 31;16112}16113}1611416115const uint32_t y_swizzle = (g_pvrtc_swizzle_table[y >> 8] << 16) | g_pvrtc_swizzle_table[y & 0xFF];1611616117for (int x = 0; x < static_cast<int>(num_blocks_x); x++, block_index++)16118{16119const uastc_block& src_block = pSrc_blocks[block_index];1612016121color32 block_pixels[4][4];16122unpack_uastc(src_block, &block_pixels[0][0], false);16123if (from_alpha)16124{16125// Just set RGB to alpha to avoid adding complexity below.16126for (uint32_t i = 0; i < 16; i++)16127{16128const uint8_t a = ((color32*)block_pixels)[i].a;16129((color32*)block_pixels)[i].set(a, a, a, 255);16130}16131}1613216133const uint32_t x_swizzle = (g_pvrtc_swizzle_table[x >> 8] << 17) | (g_pvrtc_swizzle_table[x & 0xFF] << 1);1613416135uint32_t swizzled = x_swizzle | y_swizzle;16136if (num_blocks_x != num_blocks_y)16137{16138swizzled &= swizzle_mask;1613916140if (num_blocks_x > num_blocks_y)16141swizzled |= ((x >> min_bits) << (min_bits * 2));16142else16143swizzled |= ((y >> min_bits) << (min_bits * 2));16144}1614516146pvrtc4_block* pDst_block = static_cast<pvrtc4_block*>(pDst_blocks) + swizzled;16147pDst_block->m_endpoints = pPVRTC_endpoints[block_index];1614816149{16150const uint32_t ex = 2;16151int bx = x + ex - 1;16152bx &= x_mask;1615316154#define DO_ROW(ey) \16155{ \16156const uint32_t e = pE_rows[ey][bx]; \16157e0[ex][ey] = (get_opaque_endpoint_l0(e) * 255) / 31; \16158e1[ex][ey] = (get_opaque_endpoint_l1(e) * 255) / 31; \16159}1616016161DO_ROW(0);16162DO_ROW(1);16163DO_ROW(2);16164#undef DO_ROW16165}1616616167uint32_t mod = 0;1616816169#define DO_PIX(lx, ly, w0, w1, w2, w3) \16170{ \16171int ca_l = a0 * w0 + a1 * w1 + a2 * w2 + a3 * w3; \16172int cb_l = b0 * w0 + b1 * w1 + b2 * w2 + b3 * w3; \16173int cl = (block_pixels[ly][lx].r + block_pixels[ly][lx].g + block_pixels[ly][lx].b) * 16; \16174int dl = cb_l - ca_l; \16175int vl = cl - ca_l; \16176int p = vl * 16; \16177if (ca_l > cb_l) { p = -p; dl = -dl; } \16178uint32_t m = 0; \16179if (p > 3 * dl) m = (uint32_t)(1 << ((ly) * 8 + (lx) * 2)); \16180if (p > 8 * dl) m = (uint32_t)(2 << ((ly) * 8 + (lx) * 2)); \16181if (p > 13 * dl) m = (uint32_t)(3 << ((ly) * 8 + (lx) * 2)); \16182mod |= m; \16183}1618416185{16186const uint32_t ex = 0, ey = 0;16187const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];16188const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];16189DO_PIX(0, 0, 4, 4, 4, 4);16190DO_PIX(1, 0, 2, 6, 2, 6);16191DO_PIX(0, 1, 2, 2, 6, 6);16192DO_PIX(1, 1, 1, 3, 3, 9);16193}1619416195{16196const uint32_t ex = 1, ey = 0;16197const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];16198const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];16199DO_PIX(2, 0, 8, 0, 8, 0);16200DO_PIX(3, 0, 6, 2, 6, 2);16201DO_PIX(2, 1, 4, 0, 12, 0);16202DO_PIX(3, 1, 3, 1, 9, 3);16203}1620416205{16206const uint32_t ex = 0, ey = 1;16207const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];16208const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];16209DO_PIX(0, 2, 8, 8, 0, 0);16210DO_PIX(1, 2, 4, 12, 0, 0);16211DO_PIX(0, 3, 6, 6, 2, 2);16212DO_PIX(1, 3, 3, 9, 1, 3);16213}1621416215{16216const uint32_t ex = 1, ey = 1;16217const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];16218const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];16219DO_PIX(2, 2, 16, 0, 0, 0);16220DO_PIX(3, 2, 12, 4, 0, 0);16221DO_PIX(2, 3, 12, 0, 4, 0);16222DO_PIX(3, 3, 9, 3, 3, 1);16223}16224#undef DO_PIX1622516226pDst_block->m_modulation = mod;1622716228e0[0][0] = e0[1][0]; e0[1][0] = e0[2][0];16229e0[0][1] = e0[1][1]; e0[1][1] = e0[2][1];16230e0[0][2] = e0[1][2]; e0[1][2] = e0[2][2];1623116232e1[0][0] = e1[1][0]; e1[1][0] = e1[2][0];16233e1[0][1] = e1[1][1]; e1[1][1] = e1[2][1];16234e1[0][2] = e1[1][2]; e1[1][2] = e1[2][2];1623516236} // x16237} // y16238}1623916240static void fixup_pvrtc1_4_modulation_rgba(16241const uastc_block* pSrc_blocks,16242const uint32_t* pPVRTC_endpoints,16243void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y)16244{16245const uint32_t x_mask = num_blocks_x - 1;16246const uint32_t y_mask = num_blocks_y - 1;16247const uint32_t x_bits = basisu::total_bits(x_mask);16248const uint32_t y_bits = basisu::total_bits(y_mask);16249const uint32_t min_bits = basisu::minimum(x_bits, y_bits);16250//const uint32_t max_bits = basisu::maximum(x_bits, y_bits);16251const uint32_t swizzle_mask = (1 << (min_bits * 2)) - 1;1625216253uint32_t block_index = 0;1625416255// really 3x316256int e0[4][4], e1[4][4];1625716258for (int y = 0; y < static_cast<int>(num_blocks_y); y++)16259{16260const uint32_t* pE_rows[3];1626116262for (int ey = 0; ey < 3; ey++)16263{16264int by = y + ey - 1;1626516266const uint32_t* pE = &pPVRTC_endpoints[(by & y_mask) * num_blocks_x];1626716268pE_rows[ey] = pE;1626916270for (int ex = 0; ex < 3; ex++)16271{16272int bx = 0 + ex - 1;1627316274const uint32_t e = pE[bx & x_mask];1627516276e0[ex][ey] = get_endpoint_l8(e, 0);16277e1[ex][ey] = get_endpoint_l8(e, 1);16278}16279}1628016281const uint32_t y_swizzle = (g_pvrtc_swizzle_table[y >> 8] << 16) | g_pvrtc_swizzle_table[y & 0xFF];1628216283for (int x = 0; x < static_cast<int>(num_blocks_x); x++, block_index++)16284{16285const uastc_block& src_block = pSrc_blocks[block_index];1628616287color32 block_pixels[4][4];16288unpack_uastc(src_block, &block_pixels[0][0], false);1628916290const uint32_t x_swizzle = (g_pvrtc_swizzle_table[x >> 8] << 17) | (g_pvrtc_swizzle_table[x & 0xFF] << 1);1629116292uint32_t swizzled = x_swizzle | y_swizzle;16293if (num_blocks_x != num_blocks_y)16294{16295swizzled &= swizzle_mask;1629616297if (num_blocks_x > num_blocks_y)16298swizzled |= ((x >> min_bits) << (min_bits * 2));16299else16300swizzled |= ((y >> min_bits) << (min_bits * 2));16301}1630216303pvrtc4_block* pDst_block = static_cast<pvrtc4_block*>(pDst_blocks) + swizzled;16304pDst_block->m_endpoints = pPVRTC_endpoints[block_index];1630516306{16307const uint32_t ex = 2;16308int bx = x + ex - 1;16309bx &= x_mask;1631016311#define DO_ROW(ey) \16312{ \16313const uint32_t e = pE_rows[ey][bx]; \16314e0[ex][ey] = get_endpoint_l8(e, 0); \16315e1[ex][ey] = get_endpoint_l8(e, 1); \16316}1631716318DO_ROW(0);16319DO_ROW(1);16320DO_ROW(2);16321#undef DO_ROW16322}1632316324uint32_t mod = 0;1632516326#define DO_PIX(lx, ly, w0, w1, w2, w3) \16327{ \16328int ca_l = a0 * w0 + a1 * w1 + a2 * w2 + a3 * w3; \16329int cb_l = b0 * w0 + b1 * w1 + b2 * w2 + b3 * w3; \16330int cl = 16 * (block_pixels[ly][lx].r + block_pixels[ly][lx].g + block_pixels[ly][lx].b + block_pixels[ly][lx].a); \16331int dl = cb_l - ca_l; \16332int vl = cl - ca_l; \16333int p = vl * 16; \16334if (ca_l > cb_l) { p = -p; dl = -dl; } \16335uint32_t m = 0; \16336if (p > 3 * dl) m = (uint32_t)(1 << ((ly) * 8 + (lx) * 2)); \16337if (p > 8 * dl) m = (uint32_t)(2 << ((ly) * 8 + (lx) * 2)); \16338if (p > 13 * dl) m = (uint32_t)(3 << ((ly) * 8 + (lx) * 2)); \16339mod |= m; \16340}1634116342{16343const uint32_t ex = 0, ey = 0;16344const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];16345const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];16346DO_PIX(0, 0, 4, 4, 4, 4);16347DO_PIX(1, 0, 2, 6, 2, 6);16348DO_PIX(0, 1, 2, 2, 6, 6);16349DO_PIX(1, 1, 1, 3, 3, 9);16350}1635116352{16353const uint32_t ex = 1, ey = 0;16354const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];16355const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];16356DO_PIX(2, 0, 8, 0, 8, 0);16357DO_PIX(3, 0, 6, 2, 6, 2);16358DO_PIX(2, 1, 4, 0, 12, 0);16359DO_PIX(3, 1, 3, 1, 9, 3);16360}1636116362{16363const uint32_t ex = 0, ey = 1;16364const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];16365const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];16366DO_PIX(0, 2, 8, 8, 0, 0);16367DO_PIX(1, 2, 4, 12, 0, 0);16368DO_PIX(0, 3, 6, 6, 2, 2);16369DO_PIX(1, 3, 3, 9, 1, 3);16370}1637116372{16373const uint32_t ex = 1, ey = 1;16374const int a0 = e0[ex][ey], a1 = e0[ex + 1][ey], a2 = e0[ex][ey + 1], a3 = e0[ex + 1][ey + 1];16375const int b0 = e1[ex][ey], b1 = e1[ex + 1][ey], b2 = e1[ex][ey + 1], b3 = e1[ex + 1][ey + 1];16376DO_PIX(2, 2, 16, 0, 0, 0);16377DO_PIX(3, 2, 12, 4, 0, 0);16378DO_PIX(2, 3, 12, 0, 4, 0);16379DO_PIX(3, 3, 9, 3, 3, 1);16380}16381#undef DO_PIX1638216383pDst_block->m_modulation = mod;1638416385e0[0][0] = e0[1][0]; e0[1][0] = e0[2][0];16386e0[0][1] = e0[1][1]; e0[1][1] = e0[2][1];16387e0[0][2] = e0[1][2]; e0[1][2] = e0[2][2];1638816389e1[0][0] = e1[1][0]; e1[1][0] = e1[2][0];16390e1[0][1] = e1[1][1]; e1[1][1] = e1[2][1];16391e1[0][2] = e1[1][2]; e1[1][2] = e1[2][2];1639216393} // x16394} // y16395}1639616397bool transcode_uastc_to_pvrtc1_4_rgb(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality, bool from_alpha)16398{16399BASISU_NOTE_UNUSED(high_quality);1640016401if ((!num_blocks_x) || (!num_blocks_y))16402return false;1640316404const uint32_t width = num_blocks_x * 4;16405const uint32_t height = num_blocks_y * 4;16406if (!basisu::is_pow2(width) || !basisu::is_pow2(height))16407return false;1640816409basisu::vector<uint32_t> temp_endpoints(num_blocks_x * num_blocks_y);1641016411for (uint32_t y = 0; y < num_blocks_y; y++)16412{16413for (uint32_t x = 0; x < num_blocks_x; x++)16414{16415color32 block_pixels[16];16416if (!unpack_uastc(pSrc_blocks[x + y * num_blocks_x], block_pixels, false))16417return false;1641816419// Get block's RGB bounding box16420color32 low_color(255, 255, 255, 255), high_color(0, 0, 0, 0);1642116422if (from_alpha)16423{16424uint32_t low_a = 255, high_a = 0;16425for (uint32_t i = 0; i < 16; i++)16426{16427low_a = basisu::minimum<uint32_t>(low_a, block_pixels[i].a);16428high_a = basisu::maximum<uint32_t>(high_a, block_pixels[i].a);16429}16430low_color.set(low_a, low_a, low_a, 255);16431high_color.set(high_a, high_a, high_a, 255);16432}16433else16434{16435for (uint32_t i = 0; i < 16; i++)16436{16437low_color = color32::comp_min(low_color, block_pixels[i]);16438high_color = color32::comp_max(high_color, block_pixels[i]);16439}16440}1644116442// Set PVRTC1 endpoints to floor/ceil of bounding box's coordinates.16443pvrtc4_block temp;16444temp.set_opaque_endpoint_floor(0, low_color);16445temp.set_opaque_endpoint_ceil(1, high_color);1644616447temp_endpoints[x + y * num_blocks_x] = temp.m_endpoints;16448}16449}1645016451fixup_pvrtc1_4_modulation_rgb(pSrc_blocks, &temp_endpoints[0], pDst_blocks, num_blocks_x, num_blocks_y, from_alpha);1645216453return true;16454}1645516456bool transcode_uastc_to_pvrtc1_4_rgba(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality)16457{16458BASISU_NOTE_UNUSED(high_quality);1645916460if ((!num_blocks_x) || (!num_blocks_y))16461return false;1646216463const uint32_t width = num_blocks_x * 4;16464const uint32_t height = num_blocks_y * 4;16465if (!basisu::is_pow2(width) || !basisu::is_pow2(height))16466return false;1646716468basisu::vector<uint32_t> temp_endpoints(num_blocks_x * num_blocks_y);1646916470for (uint32_t y = 0; y < num_blocks_y; y++)16471{16472for (uint32_t x = 0; x < num_blocks_x; x++)16473{16474color32 block_pixels[16];16475if (!unpack_uastc(pSrc_blocks[x + y * num_blocks_x], block_pixels, false))16476return false;1647716478// Get block's RGBA bounding box16479color32 low_color(255, 255, 255, 255), high_color(0, 0, 0, 0);1648016481for (uint32_t i = 0; i < 16; i++)16482{16483low_color = color32::comp_min(low_color, block_pixels[i]);16484high_color = color32::comp_max(high_color, block_pixels[i]);16485}1648616487// Set PVRTC1 endpoints to floor/ceil of bounding box's coordinates.16488pvrtc4_block temp;16489temp.set_endpoint_floor(0, low_color);16490temp.set_endpoint_ceil(1, high_color);1649116492temp_endpoints[x + y * num_blocks_x] = temp.m_endpoints;16493}16494}1649516496fixup_pvrtc1_4_modulation_rgba(pSrc_blocks, &temp_endpoints[0], pDst_blocks, num_blocks_x, num_blocks_y);1649716498return true;16499}1650016501void uastc_init()16502{16503for (uint32_t range = 0; range < BC7ENC_TOTAL_ASTC_RANGES; range++)16504{16505if (!astc_is_valid_endpoint_range(range))16506continue;1650716508const uint32_t levels = astc_get_levels(range);1650916510uint32_t vals[256];16511for (uint32_t i = 0; i < levels; i++)16512vals[i] = (unquant_astc_endpoint_val(i, range) << 8) | i;1651316514std::sort(vals, vals + levels);1651516516for (uint32_t i = 0; i < levels; i++)16517{16518const uint32_t order = vals[i] & 0xFF;16519const uint32_t unq = vals[i] >> 8;1652016521g_astc_unquant[range][order].m_unquant = (uint8_t)unq;16522g_astc_unquant[range][order].m_index = (uint8_t)i;1652316524} // i16525}1652616527// TODO: Precompute?16528// BC7 777.116529for (int c = 0; c < 256; c++)16530{16531for (uint32_t lp = 0; lp < 2; lp++)16532{16533endpoint_err best;16534best.m_error = (uint16_t)UINT16_MAX;1653516536for (uint32_t l = 0; l < 128; l++)16537{16538const uint32_t low = (l << 1) | lp;1653916540for (uint32_t h = 0; h < 128; h++)16541{16542const uint32_t high = (h << 1) | lp;1654316544const int k = (low * (64 - g_bc7_weights4[BC7ENC_MODE_6_OPTIMAL_INDEX]) + high * g_bc7_weights4[BC7ENC_MODE_6_OPTIMAL_INDEX] + 32) >> 6;1654516546const int err = (k - c) * (k - c);16547if (err < best.m_error)16548{16549best.m_error = (uint16_t)err;16550best.m_lo = (uint8_t)l;16551best.m_hi = (uint8_t)h;16552}16553} // h16554} // l1655516556g_bc7_mode_6_optimal_endpoints[c][lp] = best;16557} // lp1655816559} // c1656016561// BC7 77716562for (int c = 0; c < 256; c++)16563{16564endpoint_err best;16565best.m_error = (uint16_t)UINT16_MAX;1656616567for (uint32_t l = 0; l < 128; l++)16568{16569const uint32_t low = (l << 1) | (l >> 6);1657016571for (uint32_t h = 0; h < 128; h++)16572{16573const uint32_t high = (h << 1) | (h >> 6);1657416575const int k = (low * (64 - g_bc7_weights2[BC7ENC_MODE_5_OPTIMAL_INDEX]) + high * g_bc7_weights2[BC7ENC_MODE_5_OPTIMAL_INDEX] + 32) >> 6;1657616577const int err = (k - c) * (k - c);16578if (err < best.m_error)16579{16580best.m_error = (uint16_t)err;16581best.m_lo = (uint8_t)l;16582best.m_hi = (uint8_t)h;16583}16584} // h16585} // l1658616587g_bc7_mode_5_optimal_endpoints[c] = best;1658816589} // c16590}1659116592#endif // #if BASISD_SUPPORT_UASTC1659316594// ------------------------------------------------------------------------------------------------------16595// KTX216596// ------------------------------------------------------------------------------------------------------1659716598#if BASISD_SUPPORT_KTX216599const uint8_t g_ktx2_file_identifier[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };1660016601ktx2_transcoder::ktx2_transcoder() :16602m_etc1s_transcoder()16603{16604clear();16605}1660616607void ktx2_transcoder::clear()16608{16609m_pData = nullptr;16610m_data_size = 0;1661116612memset(&m_header, 0, sizeof(m_header));16613m_levels.clear();16614m_dfd.clear();16615m_key_values.clear();16616memset(&m_etc1s_header, 0, sizeof(m_etc1s_header));16617m_etc1s_image_descs.clear();1661816619m_format = basist::basis_tex_format::cETC1S;1662016621m_dfd_color_model = 0;16622m_dfd_color_prims = KTX2_DF_PRIMARIES_UNSPECIFIED;16623m_dfd_transfer_func = 0;16624m_dfd_flags = 0;16625m_dfd_samples = 0;16626m_dfd_chan0 = KTX2_DF_CHANNEL_UASTC_RGB;16627m_dfd_chan1 = KTX2_DF_CHANNEL_UASTC_RGB;1662816629m_etc1s_transcoder.clear();1663016631m_def_transcoder_state.clear();1663216633m_has_alpha = false;16634m_is_video = false;16635}1663616637bool ktx2_transcoder::init(const void* pData, uint32_t data_size)16638{16639clear();1664016641if (!pData)16642{16643BASISU_DEVEL_ERROR("ktx2_transcoder::init: pData is nullptr\n");16644assert(0);16645return false;16646}1664716648if (data_size <= sizeof(ktx2_header))16649{16650BASISU_DEVEL_ERROR("ktx2_transcoder::init: File is impossibly too small to be a valid KTX2 file\n");16651return false;16652}1665316654if (memcmp(pData, g_ktx2_file_identifier, sizeof(g_ktx2_file_identifier)) != 0)16655{16656BASISU_DEVEL_ERROR("ktx2_transcoder::init: KTX2 file identifier is not present\n");16657return false;16658}1665916660m_pData = static_cast<const uint8_t *>(pData);16661m_data_size = data_size;1666216663memcpy(&m_header, pData, sizeof(m_header));1666416665// We only support UASTC and ETC1S16666if (m_header.m_vk_format != KTX2_VK_FORMAT_UNDEFINED)16667{16668BASISU_DEVEL_ERROR("ktx2_transcoder::init: KTX2 file must be in ETC1S or UASTC format\n");16669return false;16670}1667116672// 3.3: "When format is VK_FORMAT_UNDEFINED, typeSize must equal 1."16673if (m_header.m_type_size != 1)16674{16675BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid type_size\n");16676return false;16677}1667816679// We only currently support 2D textures (plain, cubemapped, or texture array), which is by far the most common use case.16680// The BasisU library does not support 1D or 3D textures at all.16681if ((m_header.m_pixel_width < 1) || (m_header.m_pixel_height < 1) || (m_header.m_pixel_depth > 0))16682{16683BASISU_DEVEL_ERROR("ktx2_transcoder::init: Only 2D or cubemap textures are supported\n");16684return false;16685}1668616687// Face count must be 1 or 616688if ((m_header.m_face_count != 1) && (m_header.m_face_count != 6))16689{16690BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid face count, file is corrupted or invalid\n");16691return false;16692}1669316694if (m_header.m_face_count > 1)16695{16696// 3.4: Make sure cubemaps are square.16697if (m_header.m_pixel_width != m_header.m_pixel_height)16698{16699BASISU_DEVEL_ERROR("ktx2_transcoder::init: Cubemap is not square\n");16700return false;16701}16702}1670316704// 3.7 levelCount: "levelCount=0 is allowed, except for block-compressed formats"16705if (m_header.m_level_count < 1)16706{16707BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level count\n");16708return false;16709}1671016711// Sanity check the level count.16712if (m_header.m_level_count > KTX2_MAX_SUPPORTED_LEVEL_COUNT)16713{16714BASISU_DEVEL_ERROR("ktx2_transcoder::init: Too many levels or file is corrupted or invalid\n");16715return false;16716}1671716718if (m_header.m_supercompression_scheme > KTX2_SS_ZSTANDARD)16719{16720BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid/unsupported supercompression or file is corrupted or invalid\n");16721return false;16722}1672316724if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ)16725{16726if (m_header.m_sgd_byte_length <= sizeof(ktx2_etc1s_global_data_header))16727{16728BASISU_DEVEL_ERROR("ktx2_transcoder::init: Supercompression global data is too small\n");16729return false;16730}1673116732if (m_header.m_sgd_byte_offset < sizeof(ktx2_header))16733{16734BASISU_DEVEL_ERROR("ktx2_transcoder::init: Supercompression global data offset is too low\n");16735return false;16736}1673716738if (m_header.m_sgd_byte_offset + m_header.m_sgd_byte_length > m_data_size)16739{16740BASISU_DEVEL_ERROR("ktx2_transcoder::init: Supercompression global data offset and/or length is too high\n");16741return false;16742}16743}1674416745if (!m_levels.try_resize(m_header.m_level_count))16746{16747BASISU_DEVEL_ERROR("ktx2_transcoder::init: Out of memory\n");16748return false;16749}1675016751const uint32_t level_index_size_in_bytes = basisu::maximum(1U, (uint32_t)m_header.m_level_count) * sizeof(ktx2_level_index);1675216753if ((sizeof(ktx2_header) + level_index_size_in_bytes) > m_data_size)16754{16755BASISU_DEVEL_ERROR("ktx2_transcoder::init: File is too small (can't read level index array)\n");16756return false;16757}1675816759memcpy(&m_levels[0], m_pData + sizeof(ktx2_header), level_index_size_in_bytes);1676016761// Sanity check the level offsets and byte sizes16762for (uint32_t i = 0; i < m_levels.size(); i++)16763{16764if (m_levels[i].m_byte_offset < sizeof(ktx2_header))16765{16766BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset (too low)\n");16767return false;16768}1676916770if (!m_levels[i].m_byte_length)16771{16772BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level byte length\n");16773}1677416775if ((m_levels[i].m_byte_offset + m_levels[i].m_byte_length) > m_data_size)16776{16777BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset and/or length\n");16778return false;16779}1678016781const uint64_t MAX_SANE_LEVEL_UNCOMP_SIZE = 2048ULL * 1024ULL * 1024ULL;1678216783if (m_levels[i].m_uncompressed_byte_length >= MAX_SANE_LEVEL_UNCOMP_SIZE)16784{16785BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid level offset (too large)\n");16786return false;16787}1678816789if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ)16790{16791if (m_levels[i].m_uncompressed_byte_length)16792{16793BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid uncompressed length (0)\n");16794return false;16795}16796}16797else if (m_header.m_supercompression_scheme >= KTX2_SS_ZSTANDARD)16798{16799if (!m_levels[i].m_uncompressed_byte_length)16800{16801BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid uncompressed length (1)\n");16802return false;16803}16804}16805}1680616807const uint32_t DFD_MINIMUM_SIZE = 44, DFD_MAXIMUM_SIZE = 60;16808if ((m_header.m_dfd_byte_length != DFD_MINIMUM_SIZE) && (m_header.m_dfd_byte_length != DFD_MAXIMUM_SIZE))16809{16810BASISU_DEVEL_ERROR("ktx2_transcoder::init: Unsupported DFD size\n");16811return false;16812}1681316814if (((m_header.m_dfd_byte_offset + m_header.m_dfd_byte_length) > m_data_size) || (m_header.m_dfd_byte_offset < sizeof(ktx2_header)))16815{16816BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid DFD offset and/or length\n");16817return false;16818}1681916820const uint8_t* pDFD = m_pData + m_header.m_dfd_byte_offset;1682116822if (!m_dfd.try_resize(m_header.m_dfd_byte_length))16823{16824BASISU_DEVEL_ERROR("ktx2_transcoder::init: Out of memory\n");16825return false;16826}1682716828memcpy(m_dfd.data(), pDFD, m_header.m_dfd_byte_length);1682916830// This is all hard coded for only ETC1S and UASTC.16831uint32_t dfd_total_size = basisu::read_le_dword(pDFD);1683216833// 3.10.3: Sanity check16834if (dfd_total_size != m_header.m_dfd_byte_length)16835{16836BASISU_DEVEL_ERROR("ktx2_transcoder::init: DFD size validation failed (1)\n");16837return false;16838}1683916840// 3.10.3: More sanity checking16841if (m_header.m_kvd_byte_length)16842{16843if (dfd_total_size != m_header.m_kvd_byte_offset - m_header.m_dfd_byte_offset)16844{16845BASISU_DEVEL_ERROR("ktx2_transcoder::init: DFD size validation failed (2)\n");16846return false;16847}16848}1684916850const uint32_t dfd_bits = basisu::read_le_dword(pDFD + 3 * sizeof(uint32_t));16851const uint32_t sample_channel0 = basisu::read_le_dword(pDFD + 7 * sizeof(uint32_t));1685216853m_dfd_color_model = dfd_bits & 255;16854m_dfd_color_prims = (ktx2_df_color_primaries)((dfd_bits >> 8) & 255);16855m_dfd_transfer_func = (dfd_bits >> 16) & 255;16856m_dfd_flags = (dfd_bits >> 24) & 255;1685716858// See 3.10.1.Restrictions16859if ((m_dfd_transfer_func != KTX2_KHR_DF_TRANSFER_LINEAR) && (m_dfd_transfer_func != KTX2_KHR_DF_TRANSFER_SRGB))16860{16861BASISU_DEVEL_ERROR("ktx2_transcoder::init: Invalid DFD transfer function\n");16862return false;16863}1686416865if (m_dfd_color_model == KTX2_KDF_DF_MODEL_ETC1S)16866{16867m_format = basist::basis_tex_format::cETC1S;1686816869// 3.10.2: "Whether the image has 1 or 2 slices can be determined from the DFD's sample count."16870// If m_has_alpha is true it may be 2-channel RRRG or 4-channel RGBA, but we let the caller deal with that.16871m_has_alpha = (m_header.m_dfd_byte_length == 60);1687216873m_dfd_samples = m_has_alpha ? 2 : 1;16874m_dfd_chan0 = (ktx2_df_channel_id)((sample_channel0 >> 24) & 15);1687516876if (m_has_alpha)16877{16878const uint32_t sample_channel1 = basisu::read_le_dword(pDFD + 11 * sizeof(uint32_t));16879m_dfd_chan1 = (ktx2_df_channel_id)((sample_channel1 >> 24) & 15);16880}16881}16882else if (m_dfd_color_model == KTX2_KDF_DF_MODEL_UASTC)16883{16884m_format = basist::basis_tex_format::cUASTC4x4;1688516886m_dfd_samples = 1;16887m_dfd_chan0 = (ktx2_df_channel_id)((sample_channel0 >> 24) & 15);1688816889// We're assuming "DATA" means RGBA so it has alpha.16890m_has_alpha = (m_dfd_chan0 == KTX2_DF_CHANNEL_UASTC_RGBA) || (m_dfd_chan0 == KTX2_DF_CHANNEL_UASTC_RRRG);16891}16892else16893{16894// Unsupported DFD color model.16895BASISU_DEVEL_ERROR("ktx2_transcoder::init: Unsupported DFD color model\n");16896return false;16897}1689816899if (!read_key_values())16900{16901BASISU_DEVEL_ERROR("ktx2_transcoder::init: read_key_values() failed\n");16902return false;16903}1690416905// Check for a KTXanimData key16906for (uint32_t i = 0; i < m_key_values.size(); i++)16907{16908if (strcmp(reinterpret_cast<const char*>(m_key_values[i].m_key.data()), "KTXanimData") == 0)16909{16910m_is_video = true;16911break;16912}16913}1691416915return true;16916}1691716918uint32_t ktx2_transcoder::get_etc1s_image_descs_image_flags(uint32_t level_index, uint32_t layer_index, uint32_t face_index) const16919{16920const uint32_t etc1s_image_index =16921(level_index * basisu::maximum<uint32_t>(m_header.m_layer_count, 1) * m_header.m_face_count) +16922layer_index * m_header.m_face_count +16923face_index;1692416925if (etc1s_image_index >= get_etc1s_image_descs().size())16926{16927assert(0);16928return 0;16929}1693016931return get_etc1s_image_descs()[etc1s_image_index].m_image_flags;16932}1693316934const basisu::uint8_vec* ktx2_transcoder::find_key(const std::string& key_name) const16935{16936for (uint32_t i = 0; i < m_key_values.size(); i++)16937if (strcmp((const char *)m_key_values[i].m_key.data(), key_name.c_str()) == 0)16938return &m_key_values[i].m_value;1693916940return nullptr;16941}1694216943bool ktx2_transcoder::start_transcoding()16944{16945if (!m_pData)16946{16947BASISU_DEVEL_ERROR("ktx2_transcoder::start_transcoding: Must call init() first\n");16948return false;16949}1695016951if (m_header.m_supercompression_scheme == KTX2_SS_BASISLZ)16952{16953// Check if we've already decompressed the ETC1S global data. If so don't unpack it again.16954if (!m_etc1s_transcoder.get_endpoints().empty())16955return true;1695616957if (!decompress_etc1s_global_data())16958{16959BASISU_DEVEL_ERROR("ktx2_transcoder::start_transcoding: decompress_etc1s_global_data() failed\n");16960return false;16961}1696216963if (!m_is_video)16964{16965// See if there are any P-frames. If so it must be a video, even if there wasn't a KTXanimData key.16966// Video cannot be a cubemap, and it must be a texture array.16967if ((m_header.m_face_count == 1) && (m_header.m_layer_count > 1))16968{16969for (uint32_t i = 0; i < m_etc1s_image_descs.size(); i++)16970{16971if (m_etc1s_image_descs[i].m_image_flags & KTX2_IMAGE_IS_P_FRAME)16972{16973m_is_video = true;16974break;16975}16976}16977}16978}16979}16980else if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD)16981{16982#if !BASISD_SUPPORT_KTX2_ZSTD16983BASISU_DEVEL_ERROR("ktx2_transcoder::start_transcoding: File uses zstd supercompression, but zstd support was not enabled at compilation time (BASISD_SUPPORT_KTX2_ZSTD == 0)\n");16984return false;16985#endif16986}1698716988return true;16989}1699016991bool ktx2_transcoder::get_image_level_info(ktx2_image_level_info& level_info, uint32_t level_index, uint32_t layer_index, uint32_t face_index) const16992{16993if (level_index >= m_levels.size())16994{16995BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: level_index >= m_levels.size()\n");16996return false;16997}1699816999if (m_header.m_face_count > 1)17000{17001if (face_index >= 6)17002{17003BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: face_index >= 6\n");17004return false;17005}17006}17007else if (face_index != 0)17008{17009BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: face_index != 0\n");17010return false;17011}1701217013if (layer_index >= basisu::maximum<uint32_t>(m_header.m_layer_count, 1))17014{17015BASISU_DEVEL_ERROR("ktx2_transcoder::get_image_level_info: layer_index >= maximum<uint32_t>(m_header.m_layer_count, 1)\n");17016return false;17017}1701817019const uint32_t level_width = basisu::maximum<uint32_t>(m_header.m_pixel_width >> level_index, 1);17020const uint32_t level_height = basisu::maximum<uint32_t>(m_header.m_pixel_height >> level_index, 1);17021const uint32_t num_blocks_x = (level_width + 3) >> 2;17022const uint32_t num_blocks_y = (level_height + 3) >> 2;1702317024level_info.m_face_index = face_index;17025level_info.m_layer_index = layer_index;17026level_info.m_level_index = level_index;17027level_info.m_orig_width = level_width;17028level_info.m_orig_height = level_height;17029level_info.m_width = num_blocks_x * 4;17030level_info.m_height = num_blocks_y * 4;17031level_info.m_num_blocks_x = num_blocks_x;17032level_info.m_num_blocks_y = num_blocks_y;17033level_info.m_total_blocks = num_blocks_x * num_blocks_y;17034level_info.m_alpha_flag = m_has_alpha;17035level_info.m_iframe_flag = false;17036if (m_etc1s_image_descs.size())17037{17038const uint32_t etc1s_image_index =17039(level_index * basisu::maximum<uint32_t>(m_header.m_layer_count, 1) * m_header.m_face_count) +17040layer_index * m_header.m_face_count +17041face_index;1704217043level_info.m_iframe_flag = (m_etc1s_image_descs[etc1s_image_index].m_image_flags & KTX2_IMAGE_IS_P_FRAME) == 0;17044}1704517046return true;17047}1704817049bool ktx2_transcoder::transcode_image_level(17050uint32_t level_index, uint32_t layer_index, uint32_t face_index,17051void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,17052basist::transcoder_texture_format fmt,17053uint32_t decode_flags, uint32_t output_row_pitch_in_blocks_or_pixels, uint32_t output_rows_in_pixels, int channel0, int channel1,17054ktx2_transcoder_state* pState)17055{17056if (!m_pData)17057{17058BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: Must call init() first\n");17059return false;17060}1706117062if (!pState)17063pState = &m_def_transcoder_state;1706417065if (level_index >= m_levels.size())17066{17067BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: level_index >= m_levels.size()\n");17068return false;17069}1707017071if (m_header.m_face_count > 1)17072{17073if (face_index >= 6)17074{17075BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: face_index >= 6\n");17076return false;17077}17078}17079else if (face_index != 0)17080{17081BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: face_index != 0\n");17082return false;17083}1708417085if (layer_index >= basisu::maximum<uint32_t>(m_header.m_layer_count, 1))17086{17087BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: layer_index >= maximum<uint32_t>(m_header.m_layer_count, 1)\n");17088return false;17089}1709017091const uint8_t* pComp_level_data = m_pData + m_levels[level_index].m_byte_offset;17092uint64_t comp_level_data_size = m_levels[level_index].m_byte_length;1709317094const uint8_t* pUncomp_level_data = pComp_level_data;17095uint64_t uncomp_level_data_size = comp_level_data_size;1709617097if (uncomp_level_data_size > UINT32_MAX)17098{17099BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: uncomp_level_data_size > UINT32_MAX\n");17100return false;17101}1710217103if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD)17104{17105// Check if we've already decompressed this level's supercompressed data.17106if ((int)level_index != pState->m_uncomp_data_level_index)17107{17108// Uncompress the entire level's supercompressed data.17109if (!decompress_level_data(level_index, pState->m_level_uncomp_data))17110{17111BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: decompress_level_data() failed\n");17112return false;17113}17114pState->m_uncomp_data_level_index = level_index;17115}1711617117pUncomp_level_data = pState->m_level_uncomp_data.data();17118uncomp_level_data_size = pState->m_level_uncomp_data.size();17119}1712017121const uint32_t level_width = basisu::maximum<uint32_t>(m_header.m_pixel_width >> level_index, 1);17122const uint32_t level_height = basisu::maximum<uint32_t>(m_header.m_pixel_height >> level_index, 1);17123const uint32_t num_blocks_x = (level_width + 3) >> 2;17124const uint32_t num_blocks_y = (level_height + 3) >> 2;1712517126if (m_format == basist::basis_tex_format::cETC1S)17127{17128// Ensure start_transcoding() was called.17129if (m_etc1s_transcoder.get_endpoints().empty())17130{17131BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: must call start_transcoding() first\n");17132return false;17133}1713417135const uint32_t etc1s_image_index =17136(level_index * basisu::maximum<uint32_t>(m_header.m_layer_count, 1) * m_header.m_face_count) +17137layer_index * m_header.m_face_count +17138face_index;1713917140// Sanity check17141if (etc1s_image_index >= m_etc1s_image_descs.size())17142{17143BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: etc1s_image_index >= m_etc1s_image_descs.size()\n");17144assert(0);17145return false;17146}1714717148if (static_cast<uint32_t>(m_data_size) != m_data_size)17149{17150BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: File is too large\n");17151return false;17152}1715317154const ktx2_etc1s_image_desc& image_desc = m_etc1s_image_descs[etc1s_image_index];1715517156if (!m_etc1s_transcoder.transcode_image(fmt,17157pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, m_pData, static_cast<uint32_t>(m_data_size),17158num_blocks_x, num_blocks_y, level_width, level_height,17159level_index,17160m_levels[level_index].m_byte_offset + image_desc.m_rgb_slice_byte_offset, image_desc.m_rgb_slice_byte_length,17161image_desc.m_alpha_slice_byte_length ? (m_levels[level_index].m_byte_offset + image_desc.m_alpha_slice_byte_offset) : 0, image_desc.m_alpha_slice_byte_length,17162decode_flags, m_has_alpha,17163m_is_video, output_row_pitch_in_blocks_or_pixels, &pState->m_transcoder_state, output_rows_in_pixels))17164{17165BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: ETC1S transcode_image() failed, this is either a bug or the file is corrupted/invalid\n");17166return false;17167}17168}17169else if (m_format == basist::basis_tex_format::cUASTC4x4)17170{17171// Compute length and offset to uncompressed 2D UASTC texture data, given the face/layer indices.17172assert(uncomp_level_data_size == m_levels[level_index].m_uncompressed_byte_length);17173const uint32_t total_2D_image_size = num_blocks_x * num_blocks_y * KTX2_UASTC_BLOCK_SIZE;1717417175const uint32_t uncomp_ofs = (layer_index * m_header.m_face_count + face_index) * total_2D_image_size;1717617177// Sanity checks17178if (uncomp_ofs >= uncomp_level_data_size)17179{17180BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: uncomp_ofs >= total_2D_image_size\n");17181return false;17182}1718317184if ((uncomp_level_data_size - uncomp_ofs) < total_2D_image_size)17185{17186BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: (uncomp_level_data_size - uncomp_ofs) < total_2D_image_size\n");17187return false;17188}1718917190if (!m_uastc_transcoder.transcode_image(fmt,17191pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels,17192(const uint8_t*)pUncomp_level_data + uncomp_ofs, (uint32_t)total_2D_image_size, num_blocks_x, num_blocks_y, level_width, level_height, level_index,171930, (uint32_t)total_2D_image_size,17194decode_flags, m_has_alpha, m_is_video, output_row_pitch_in_blocks_or_pixels, nullptr, output_rows_in_pixels, channel0, channel1))17195{17196BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: UASTC transcode_image() failed, this is either a bug or the file is corrupted/invalid\n");17197return false;17198}17199}17200else17201{17202// Shouldn't get here.17203BASISU_DEVEL_ERROR("ktx2_transcoder::transcode_image_2D: Internal error\n");17204assert(0);17205return false;17206}1720717208return true;17209}1721017211bool ktx2_transcoder::decompress_level_data(uint32_t level_index, basisu::uint8_vec& uncomp_data)17212{17213const uint8_t* pComp_data = m_levels[level_index].m_byte_offset + m_pData;17214const uint64_t comp_size = m_levels[level_index].m_byte_length;1721517216const uint64_t uncomp_size = m_levels[level_index].m_uncompressed_byte_length;1721717218if (((size_t)comp_size) != comp_size)17219{17220BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Compressed data too large\n");17221return false;17222}17223if (((size_t)uncomp_size) != uncomp_size)17224{17225BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Uncompressed data too large\n");17226return false;17227}1722817229if (!uncomp_data.try_resize((size_t)uncomp_size))17230{17231BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Out of memory\n");17232return false;17233}1723417235if (m_header.m_supercompression_scheme == KTX2_SS_ZSTANDARD)17236{17237#if BASISD_SUPPORT_KTX2_ZSTD17238size_t actualUncompSize = ZSTD_decompress(uncomp_data.data(), (size_t)uncomp_size, pComp_data, (size_t)comp_size);17239if (ZSTD_isError(actualUncompSize))17240{17241BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Zstd decompression failed, file is invalid or corrupted\n");17242return false;17243}17244if (actualUncompSize != uncomp_size)17245{17246BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: Zstd decompression returned too few bytes, file is invalid or corrupted\n");17247return false;17248}17249#else17250BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_level_data: File uses Zstd supercompression, but Zstd support was not enabled at compile time (BASISD_SUPPORT_KTX2_ZSTD is 0)\n");17251return false;17252#endif17253}1725417255return true;17256}1725717258bool ktx2_transcoder::decompress_etc1s_global_data()17259{17260// Note: we don't actually support 3D textures in here yet17261//uint32_t layer_pixel_depth = basisu::maximum<uint32_t>(m_header.m_pixel_depth, 1);17262//for (uint32_t i = 1; i < m_header.m_level_count; i++)17263// layer_pixel_depth += basisu::maximum<uint32_t>(m_header.m_pixel_depth >> i, 1);1726417265const uint32_t image_count = basisu::maximum<uint32_t>(m_header.m_layer_count, 1) * m_header.m_face_count * m_header.m_level_count;17266assert(image_count);1726717268const uint8_t* pSrc = m_pData + m_header.m_sgd_byte_offset;1726917270memcpy(&m_etc1s_header, pSrc, sizeof(ktx2_etc1s_global_data_header));17271pSrc += sizeof(ktx2_etc1s_global_data_header);1727217273if ((!m_etc1s_header.m_endpoints_byte_length) || (!m_etc1s_header.m_selectors_byte_length) || (!m_etc1s_header.m_tables_byte_length))17274{17275BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: Invalid ETC1S global data\n");17276return false;17277}1727817279if ((!m_etc1s_header.m_endpoint_count) || (!m_etc1s_header.m_selector_count))17280{17281BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: endpoint and/or selector count is 0, file is invalid or corrupted\n");17282return false;17283}1728417285// Sanity check the ETC1S header.17286if ((sizeof(ktx2_etc1s_global_data_header) +17287sizeof(ktx2_etc1s_image_desc) * image_count +17288m_etc1s_header.m_endpoints_byte_length +17289m_etc1s_header.m_selectors_byte_length +17290m_etc1s_header.m_tables_byte_length +17291m_etc1s_header.m_extended_byte_length) > m_header.m_sgd_byte_length)17292{17293BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: SGD byte length is too small, file is invalid or corrupted\n");17294return false;17295}1729617297if (!m_etc1s_image_descs.try_resize(image_count))17298{17299BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: Out of memory\n");17300return false;17301}1730217303memcpy(m_etc1s_image_descs.data(), pSrc, sizeof(ktx2_etc1s_image_desc) * image_count);17304pSrc += sizeof(ktx2_etc1s_image_desc) * image_count;1730517306// Sanity check the ETC1S image descs17307for (uint32_t i = 0; i < image_count; i++)17308{17309// m_etc1s_transcoder.transcode_image() will validate the slice offsets/lengths before transcoding.1731017311if (!m_etc1s_image_descs[i].m_rgb_slice_byte_length)17312{17313BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: ETC1S image descs sanity check failed (1)\n");17314return false;17315}1731617317if (m_has_alpha)17318{17319if (!m_etc1s_image_descs[i].m_alpha_slice_byte_length)17320{17321BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: ETC1S image descs sanity check failed (2)\n");17322return false;17323}17324}17325}1732617327const uint8_t* pEndpoint_data = pSrc;17328const uint8_t* pSelector_data = pSrc + m_etc1s_header.m_endpoints_byte_length;17329const uint8_t* pTables_data = pSrc + m_etc1s_header.m_endpoints_byte_length + m_etc1s_header.m_selectors_byte_length;1733017331if (!m_etc1s_transcoder.decode_tables(pTables_data, m_etc1s_header.m_tables_byte_length))17332{17333BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_tables() failed, file is invalid or corrupted\n");17334return false;17335}1733617337if (!m_etc1s_transcoder.decode_palettes(17338m_etc1s_header.m_endpoint_count, pEndpoint_data, m_etc1s_header.m_endpoints_byte_length,17339m_etc1s_header.m_selector_count, pSelector_data, m_etc1s_header.m_selectors_byte_length))17340{17341BASISU_DEVEL_ERROR("ktx2_transcoder::decompress_etc1s_global_data: decode_palettes() failed, file is likely corrupted\n");17342return false;17343}1734417345return true;17346}1734717348bool ktx2_transcoder::read_key_values()17349{17350if (!m_header.m_kvd_byte_length)17351{17352if (m_header.m_kvd_byte_offset)17353{17354BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Invalid KVD byte offset (it should be zero when the length is zero)\n");17355return false;17356}1735717358return true;17359}1736017361if (m_header.m_kvd_byte_offset < sizeof(ktx2_header))17362{17363BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Invalid KVD byte offset\n");17364return false;17365}1736617367if ((m_header.m_kvd_byte_offset + m_header.m_kvd_byte_length) > m_data_size)17368{17369BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Invalid KVD byte offset and/or length\n");17370return false;17371}1737217373const uint8_t* pSrc = m_pData + m_header.m_kvd_byte_offset;17374uint32_t src_left = m_header.m_kvd_byte_length;1737517376if (!m_key_values.try_reserve(8))17377{17378BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n");17379return false;17380}1738117382while (src_left > sizeof(uint32_t))17383{17384uint32_t l = basisu::read_le_dword(pSrc);1738517386pSrc += sizeof(uint32_t);17387src_left -= sizeof(uint32_t);1738817389if (l < 2)17390{17391BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Failed reading key value fields (0)\n");17392return false;17393}1739417395if (src_left < l)17396{17397BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Failed reading key value fields (1)\n");17398return false;17399}1740017401if (!m_key_values.try_resize(m_key_values.size() + 1))17402{17403BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n");17404return false;17405}1740617407basisu::uint8_vec& key_data = m_key_values.back().m_key;17408basisu::uint8_vec& value_data = m_key_values.back().m_value;1740917410do17411{17412if (!l)17413{17414BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Failed reading key value fields (2)\n");17415return false;17416}1741717418if (!key_data.try_push_back(*pSrc++))17419{17420BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n");17421return false;17422}1742317424src_left--;17425l--;1742617427} while (key_data.back());1742817429if (!value_data.try_resize(l))17430{17431BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Out of memory\n");17432return false;17433}1743417435if (l)17436{17437memcpy(value_data.data(), pSrc, l);17438pSrc += l;17439src_left -= l;17440}1744117442uint32_t ofs = (uint32_t)(pSrc - m_pData) & 3;17443uint32_t alignment_bytes = (4 - ofs) & 3;1744417445if (src_left < alignment_bytes)17446{17447BASISU_DEVEL_ERROR("ktx2_transcoder::read_key_values: Failed reading key value fields (3)\n");17448return false;17449}1745017451pSrc += alignment_bytes;17452src_left -= alignment_bytes;17453}1745417455return true;17456}1745717458#endif // BASISD_SUPPORT_KTX21745917460bool basisu_transcoder_supports_ktx2()17461{17462#if BASISD_SUPPORT_KTX217463return true;17464#else17465return false;17466#endif17467}1746817469bool basisu_transcoder_supports_ktx2_zstd()17470{17471#if BASISD_SUPPORT_KTX2_ZSTD17472return true;17473#else17474return false;17475#endif17476}1747717478} // namespace basist174791748017481