use super::tables::ASTC_BISE_RANGE_TABLE;
use crate::once::OnceBox;
use alloc::boxed::Box;
struct UnquantParams {
pb: [u8; 9],
c: u32,
}
const fn up(pb: &[u8; 9], c: u32) -> UnquantParams {
UnquantParams { pb: *pb, c }
}
static PARAMS: [UnquantParams; 21] = [
up(b"000000000", 0), up(b"000000000", 0), up(b"000000000", 0), up(b"000000000", 0), up(b"000000000", 204), up(b"000000000", 0), up(b"000000000", 113), up(b"b000b0bb0", 93), up(b"000000000", 0), up(b"b0000bb00", 54), up(b"cb000cbcb", 44), up(b"000000000", 0), up(b"cb0000cbc", 26), up(b"dcb000dcb", 22), up(b"000000000", 0), up(b"dcb0000dc", 13), up(b"edcb000ed", 11), up(b"000000000", 0), up(b"edcb0000e", 6), up(b"fedcb000f", 5), up(b"000000000", 0), ];
pub fn astc_get_levels(range: u32) -> u32 {
let t = &ASTC_BISE_RANGE_TABLE[range as usize];
((1 + 2 * t[1] + 4 * t[2]) << t[0]) as u32
}
pub fn astc_is_valid_endpoint_range(range: u32) -> bool {
let t = &ASTC_BISE_RANGE_TABLE[range as usize];
if t[1] == 0 && t[2] == 0 {
return true;
}
PARAMS[range as usize].c != 0
}
pub fn unquant_astc_endpoint(
packed_bits: u32,
packed_trits: u32,
packed_quints: u32,
range: u32,
) -> u32 {
let t = &ASTC_BISE_RANGE_TABLE[range as usize];
let bits = t[0] as u32;
let trits = t[1] as u32;
let quints = t[2] as u32;
let mut val = 0u32;
if trits == 0 && quints == 0 {
let mut bits_left = 8i32;
while bits_left > 0 {
let mut v = packed_bits;
let n = bits_left.min(bits as i32);
if n < bits as i32 {
v >>= bits as i32 - n;
}
val |= v << (bits_left - n);
bits_left -= n;
}
} else {
let a = if packed_bits & 1 != 0 { 511 } else { 0 };
let c = PARAMS[range as usize].c;
let d = if trits != 0 {
packed_trits
} else {
packed_quints
};
let mut b = 0u32;
for i in 0..9 {
b <<= 1;
let ch = PARAMS[range as usize].pb[i];
if ch != b'0' {
let shift = (ch - b'a') as u32;
b |= (packed_bits >> shift) & 1;
}
}
val = d.wrapping_mul(c).wrapping_add(b);
val ^= a;
val = (a & 0x80) | (val >> 2);
}
val
}
pub fn unquant_astc_endpoint_val(packed_val: u32, range: u32) -> u32 {
let t = &ASTC_BISE_RANGE_TABLE[range as usize];
let bits = t[0] as u32;
let trits = t[1];
let quints = t[2];
if trits == 0 && quints == 0 {
unquant_astc_endpoint(packed_val, 0, 0, range)
} else if trits != 0 {
unquant_astc_endpoint(packed_val & ((1 << bits) - 1), packed_val >> bits, 0, range)
} else {
unquant_astc_endpoint(packed_val & ((1 << bits) - 1), 0, packed_val >> bits, range)
}
}
pub fn astc_unquant() -> &'static [[AstcQuantBin; 256]; TOTAL_ASTC_RANGES] {
static TABLE: OnceBox<[[AstcQuantBin; 256]; TOTAL_ASTC_RANGES]> = OnceBox::new();
TABLE.get_or_init(build_astc_unquant)
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct AstcQuantBin {
pub m_unquant: u8,
pub m_index: u8,
}
pub const TOTAL_ASTC_RANGES: usize = 21;
pub fn build_astc_unquant() -> Box<[[AstcQuantBin; 256]; TOTAL_ASTC_RANGES]> {
let mut table = Box::new([[AstcQuantBin::default(); 256]; TOTAL_ASTC_RANGES]);
for range in 0..TOTAL_ASTC_RANGES as u32 {
if !astc_is_valid_endpoint_range(range) {
continue;
}
let levels = astc_get_levels(range) as usize;
let mut vals = [0u32; 256];
for (i, v) in vals.iter_mut().enumerate().take(levels) {
*v = (unquant_astc_endpoint_val(i as u32, range) << 8) | i as u32;
}
vals[0..levels].sort_unstable();
for (i, &packed) in vals.iter().enumerate().take(levels) {
let order = (packed & 0xFF) as usize;
let unq = (packed >> 8) as u8;
table[range as usize][order].m_unquant = unq;
table[range as usize][order].m_index = i as u8;
}
}
table
}