pub fn bc1(compressed_block: &[u8], decompressed_block: &mut [u8], destination_pitch: usize) {
color_block(
compressed_block,
decompressed_block,
destination_pitch,
false,
)
}
pub fn bc2(compressed_block: &[u8], decompressed_block: &mut [u8], destination_pitch: usize) {
color_block(
&compressed_block[8..],
decompressed_block,
destination_pitch,
true,
);
sharp_alpha_block(compressed_block, decompressed_block, destination_pitch);
}
pub fn bc3(compressed_block: &[u8], decompressed_block: &mut [u8], destination_pitch: usize) {
color_block(
&compressed_block[8..],
decompressed_block,
destination_pitch,
true,
);
smooth_alpha_block(
compressed_block,
&mut decompressed_block[3..],
destination_pitch,
4,
);
}
pub fn bc4(
compressed_block: &[u8],
decompressed_block: &mut [u8],
destination_pitch: usize,
is_signed: bool,
) {
bc4_block(
compressed_block,
decompressed_block,
destination_pitch,
1,
is_signed,
);
}
pub fn bc4_float(
compressed_block: &[u8],
decompressed_block: &mut [f32],
destination_pitch: usize,
is_signed: bool,
) {
bc4_block_float(
compressed_block,
decompressed_block,
destination_pitch,
1,
is_signed,
)
}
pub fn bc5(
compressed_block: &[u8],
decompressed_block: &mut [u8],
destination_pitch: usize,
is_signed: bool,
) {
bc4_block(
compressed_block,
decompressed_block,
destination_pitch,
2,
is_signed,
);
bc4_block(
&compressed_block[8..],
&mut decompressed_block[1..],
destination_pitch,
2,
is_signed,
);
}
pub fn bc5_float(
compressed_block: &[u8],
decompressed_block: &mut [f32],
destination_pitch: usize,
is_signed: bool,
) {
bc4_block_float(
compressed_block,
decompressed_block,
destination_pitch,
2,
is_signed,
);
bc4_block_float(
&compressed_block[8..],
&mut decompressed_block[1..],
destination_pitch,
2,
is_signed,
);
}
pub fn bc6h_half(
compressed_block: &[u8],
decompressed_block: &mut [u16],
destination_pitch: usize,
is_signed: bool,
) {
static ACTUAL_BITS_COUNT: [[u8; 14]; 4] = [
[10, 7, 11, 11, 11, 9, 8, 8, 8, 6, 10, 11, 12, 16], [5, 6, 5, 4, 4, 5, 6, 5, 5, 6, 10, 9, 8, 4], [5, 6, 4, 5, 4, 5, 5, 6, 5, 6, 10, 9, 8, 4], [5, 6, 4, 4, 5, 5, 5, 5, 6, 6, 10, 9, 8, 4], ];
static PARTITION_SETS: [[[u8; 4]; 4]; 32] = [
[[128, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 129]], [[128, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 129]], [[128, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 129]], [[128, 0, 0, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 129]], [[128, 0, 0, 0], [1, 0, 0, 0], [1, 1, 1, 0], [1, 1, 1, 129]], [[128, 1, 129, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 0, 0, 0], [1, 1, 1, 0]], [[128, 1, 129, 1], [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]], [[128, 0, 129, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [1, 0, 0, 0], [129, 1, 0, 0], [1, 1, 1, 0]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 0, 0, 0], [1, 1, 0, 0]], [[128, 1, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 0, 129]], [[128, 0, 129, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 0]], [[128, 0, 0, 0], [1, 0, 0, 0], [129, 0, 0, 0], [1, 1, 0, 0]], [[128, 1, 129, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 1, 1, 0]], [[128, 0, 129, 1], [0, 1, 1, 0], [0, 1, 1, 0], [1, 1, 0, 0]], [[128, 0, 0, 1], [0, 1, 1, 1], [129, 1, 1, 0], [1, 0, 0, 0]], [[128, 0, 0, 0], [1, 1, 1, 1], [129, 1, 1, 1], [0, 0, 0, 0]], [[128, 1, 129, 1], [0, 0, 0, 1], [1, 0, 0, 0], [1, 1, 1, 0]], [[128, 0, 129, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 0, 0]], ];
let a_weight3 = [0, 9, 18, 27, 37, 46, 55, 64];
let a_weight4 = [0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64];
let mut bstream = Bitstream {
low: u64::from_le_bytes(compressed_block[0..8].try_into().unwrap()),
high: u64::from_le_bytes(compressed_block[8..16].try_into().unwrap()),
};
let mut r = [0i32; 4]; let mut g = [0i32; 4]; let mut b = [0i32; 4];
let mut mode = bstream.read_bits(2);
if mode > 1 {
mode |= bstream.read_bits(3) << 2;
}
let mut partition = 0;
match mode {
0b00 => {
g[2] |= bstream.read_bit_i32() << 4; b[2] |= bstream.read_bit_i32() << 4; b[3] |= bstream.read_bit_i32() << 4; r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(5); g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 0;
}
0b01 => {
g[2] |= bstream.read_bit_i32() << 5; g[3] |= bstream.read_bit_i32() << 4; g[3] |= bstream.read_bit_i32() << 5; r[0] |= bstream.read_bits_i32(7); b[3] |= bstream.read_bit_i32(); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(7); b[2] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 2; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(7); b[3] |= bstream.read_bit_i32() << 3; b[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(6); g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(6); b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(6); r[3] |= bstream.read_bits_i32(6); partition = bstream.read_bits_i32(5); mode = 1;
}
0b00010 => {
r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(5); r[0] |= bstream.read_bit_i32() << 10; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(4); g[0] |= bstream.read_bit_i32() << 10; b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(4); b[0] |= bstream.read_bit_i32() << 10; b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 2;
}
0b00110 => {
r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(4); r[0] |= bstream.read_bit_i32() << 10; g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); g[0] |= bstream.read_bit_i32() << 10; g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(4); b[0] |= bstream.read_bit_i32() << 10; b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(4); b[3] |= bstream.read_bit_i32(); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(4); g[2] |= bstream.read_bit_i32() << 4; b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 3;
}
0b01010 => {
r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(4); r[0] |= bstream.read_bit_i32() << 10; b[2] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(4); g[0] |= bstream.read_bit_i32() << 10; b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[0] |= bstream.read_bit_i32() << 10; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(4); b[3] |= bstream.read_bit_i32() << 1; b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(4); b[3] |= bstream.read_bit_i32() << 4; b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 4;
}
0b01110 => {
r[0] |= bstream.read_bits_i32(9); b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(9); g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(9); b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(5); g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 5;
}
0b10010 => {
r[0] |= bstream.read_bits_i32(8); g[3] |= bstream.read_bit_i32() << 4; b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32() << 2; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32() << 3; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(6); g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(6); r[3] |= bstream.read_bits_i32(6); partition = bstream.read_bits_i32(5); mode = 6;
}
0b10110 => {
r[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32(); b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(8); g[2] |= bstream.read_bit_i32() << 5; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(8); g[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(5); g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 7;
}
0b11010 => {
r[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(8); b[2] |= bstream.read_bit_i32() << 5; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(5); g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(6); b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 8;
}
0b11110 => {
r[0] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bit_i32() << 4; b[3] |= bstream.read_bit_i32(); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(6); g[2] |= bstream.read_bit_i32() << 5; b[2] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 2; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 3; b[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(6); g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(6); b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(6); r[3] |= bstream.read_bits_i32(6); partition = bstream.read_bits_i32(5); mode = 9;
}
0b00011 => {
r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(10); g[1] |= bstream.read_bits_i32(10); b[1] |= bstream.read_bits_i32(10); mode = 10;
}
0b00111 => {
r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(9); r[0] |= bstream.read_bit_i32() << 10; g[1] |= bstream.read_bits_i32(9); g[0] |= bstream.read_bit_i32() << 10; b[1] |= bstream.read_bits_i32(9); b[0] |= bstream.read_bit_i32() << 10; mode = 11;
}
0b01011 => {
r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(8); r[0] |= bstream.read_bits_r(2) << 10; g[1] |= bstream.read_bits_i32(8); g[0] |= bstream.read_bits_r(2) << 10; b[1] |= bstream.read_bits_i32(8); b[0] |= bstream.read_bits_r(2) << 10; mode = 12;
}
0b01111 => {
r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(4); r[0] |= bstream.read_bits_r(6) << 10; g[1] |= bstream.read_bits_i32(4); g[0] |= bstream.read_bits_r(6) << 10; b[1] |= bstream.read_bits_i32(4); b[0] |= bstream.read_bits_r(6) << 10; mode = 13;
}
_ => {
for i in 0..4 {
let index = i * destination_pitch;
decompressed_block[index..index + 4 * 3].fill(0);
}
return;
}
}
let num_partitions = if mode >= 10 { 0 } else { 1 };
let actual_bits0_mode = ACTUAL_BITS_COUNT[0][mode as usize] as i32;
if is_signed {
r[0] = extend_sign(r[0], actual_bits0_mode);
g[0] = extend_sign(g[0], actual_bits0_mode);
b[0] = extend_sign(b[0], actual_bits0_mode);
}
if mode != 9 && mode != 10 || is_signed {
for i in 1..(num_partitions + 1) * 2 {
r[i] = extend_sign(r[i], ACTUAL_BITS_COUNT[1][mode as usize] as i32);
g[i] = extend_sign(g[i], ACTUAL_BITS_COUNT[2][mode as usize] as i32);
b[i] = extend_sign(b[i], ACTUAL_BITS_COUNT[3][mode as usize] as i32);
}
}
if mode != 9 && mode != 10 {
for i in 1..(num_partitions + 1) * 2 {
r[i] = transform_inverse(r[i], r[0], actual_bits0_mode, is_signed);
g[i] = transform_inverse(g[i], g[0], actual_bits0_mode, is_signed);
b[i] = transform_inverse(b[i], b[0], actual_bits0_mode, is_signed);
}
}
for i in 0..(num_partitions + 1) * 2 {
r[i] = unquantize(r[i], actual_bits0_mode, is_signed);
g[i] = unquantize(g[i], actual_bits0_mode, is_signed);
b[i] = unquantize(b[i], actual_bits0_mode, is_signed);
}
let weights = if mode >= 10 {
&a_weight4[..]
} else {
&a_weight3[..]
};
for i in 0..4 {
for j in 0..4 {
let mut partition_set = if mode >= 10 {
if i | j != 0 {
0usize
} else {
128usize
}
} else {
PARTITION_SETS[partition as usize][i][j] as usize
};
let mut index_bits = if mode >= 10 { 4 } else { 3 };
if (partition_set & 0x80) != 0 {
index_bits -= 1;
}
partition_set &= 0x01;
let index = bstream.read_bits(index_bits);
let weight = weights[index as usize];
let ep_i = partition_set * 2;
let out = i * destination_pitch + j * 3;
decompressed_block[out..out + 3].copy_from_slice(&[
finish_unquantize(interpolate_i32(r[ep_i], r[ep_i + 1], weight), is_signed),
finish_unquantize(interpolate_i32(g[ep_i], g[ep_i + 1], weight), is_signed),
finish_unquantize(interpolate_i32(b[ep_i], b[ep_i + 1], weight), is_signed),
]);
}
}
}
pub fn bc6h_float(
compressed_block: &[u8],
decompressed_block: &mut [f32],
destination_pitch: usize,
is_signed: bool,
) {
let input_pitch = 4 * 3;
let mut block = [0u16; 4 * 4 * 3];
bc6h_half(compressed_block, &mut block, input_pitch, is_signed);
for i in 0..4 {
for j in 0..4 {
let in_index = i * input_pitch + j * 3;
let out_index = i * destination_pitch + j * 3;
decompressed_block[out_index..out_index + 3].copy_from_slice(&[
half_to_float_quick(block[in_index]),
half_to_float_quick(block[in_index + 1]),
half_to_float_quick(block[in_index + 2]),
]);
}
}
}
pub fn bc7(compressed_block: &[u8], decompressed_block: &mut [u8], destination_pitch: usize) {
static ACTUAL_BITS_COUNT: [[u8; 8]; 2] = [
[4, 6, 5, 7, 5, 7, 7, 5], [0, 0, 0, 0, 6, 8, 7, 5], ];
static PARTITION_SETS: [[[[u8; 4]; 4]; 64]; 2] = [
[
[[128, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 129]], [[128, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 129]], [[128, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 129]], [[128, 0, 0, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 129]], [[128, 0, 0, 0], [1, 0, 0, 0], [1, 1, 1, 0], [1, 1, 1, 129]], [[128, 1, 129, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 0, 0, 0], [1, 1, 1, 0]], [[128, 1, 129, 1], [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]], [[128, 0, 129, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [1, 0, 0, 0], [129, 1, 0, 0], [1, 1, 1, 0]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 0, 0, 0], [1, 1, 0, 0]], [[128, 1, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 0, 129]], [[128, 0, 129, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 0]], [[128, 0, 0, 0], [1, 0, 0, 0], [129, 0, 0, 0], [1, 1, 0, 0]], [[128, 1, 129, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 1, 1, 0]], [[128, 0, 129, 1], [0, 1, 1, 0], [0, 1, 1, 0], [1, 1, 0, 0]], [[128, 0, 0, 1], [0, 1, 1, 1], [129, 1, 1, 0], [1, 0, 0, 0]], [[128, 0, 0, 0], [1, 1, 1, 1], [129, 1, 1, 1], [0, 0, 0, 0]], [[128, 1, 129, 1], [0, 0, 0, 1], [1, 0, 0, 0], [1, 1, 1, 0]], [[128, 0, 129, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 0, 0]], [[128, 1, 0, 1], [0, 1, 0, 1], [0, 1, 0, 1], [0, 1, 0, 129]], [[128, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [1, 1, 1, 129]], [[128, 1, 0, 1], [1, 0, 129, 0], [0, 1, 0, 1], [1, 0, 1, 0]], [[128, 0, 1, 1], [0, 0, 1, 1], [129, 1, 0, 0], [1, 1, 0, 0]], [[128, 0, 129, 1], [1, 1, 0, 0], [0, 0, 1, 1], [1, 1, 0, 0]], [[128, 1, 0, 1], [0, 1, 0, 1], [129, 0, 1, 0], [1, 0, 1, 0]], [[128, 1, 1, 0], [1, 0, 0, 1], [0, 1, 1, 0], [1, 0, 0, 129]], [[128, 1, 0, 1], [1, 0, 1, 0], [1, 0, 1, 0], [0, 1, 0, 129]], [[128, 1, 129, 1], [0, 0, 1, 1], [1, 1, 0, 0], [1, 1, 1, 0]], [[128, 0, 0, 1], [0, 0, 1, 1], [129, 1, 0, 0], [1, 0, 0, 0]], [[128, 0, 129, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 1, 0, 0]], [[128, 0, 129, 1], [1, 0, 1, 1], [1, 1, 0, 1], [1, 1, 0, 0]], [[128, 1, 129, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]], [[128, 0, 1, 1], [1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 129]], [[128, 1, 1, 0], [0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 129]], [[128, 0, 0, 0], [0, 1, 129, 0], [0, 1, 1, 0], [0, 0, 0, 0]], [[128, 1, 0, 0], [1, 1, 129, 0], [0, 1, 0, 0], [0, 0, 0, 0]], [[128, 0, 129, 0], [0, 1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [0, 0, 129, 0], [0, 1, 1, 1], [0, 0, 1, 0]], [[128, 0, 0, 0], [0, 1, 0, 0], [129, 1, 1, 0], [0, 1, 0, 0]], [[128, 1, 1, 0], [1, 1, 0, 0], [1, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 0], [1, 1, 0, 0], [1, 0, 0, 129]], [[128, 1, 129, 0], [0, 0, 1, 1], [1, 0, 0, 1], [1, 1, 0, 0]], [[128, 0, 129, 1], [1, 0, 0, 1], [1, 1, 0, 0], [0, 1, 1, 0]], [[128, 1, 1, 0], [1, 1, 0, 0], [1, 1, 0, 0], [1, 0, 0, 129]], [[128, 1, 1, 0], [0, 0, 1, 1], [0, 0, 1, 1], [1, 0, 0, 129]], [[128, 1, 1, 1], [1, 1, 1, 0], [1, 0, 0, 0], [0, 0, 0, 129]], [[128, 0, 0, 1], [1, 0, 0, 0], [1, 1, 1, 0], [0, 1, 1, 129]], [[128, 0, 0, 0], [1, 1, 1, 1], [0, 0, 1, 1], [0, 0, 1, 129]], [[128, 0, 129, 1], [0, 0, 1, 1], [1, 1, 1, 1], [0, 0, 0, 0]], [[128, 0, 129, 0], [0, 0, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0]], [[128, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 1], [0, 1, 1, 129]], ],
[
[[128, 0, 1, 129], [0, 0, 1, 1], [0, 2, 2, 1], [2, 2, 2, 130]], [[128, 0, 0, 129], [0, 0, 1, 1], [130, 2, 1, 1], [2, 2, 2, 1]], [[128, 0, 0, 0], [2, 0, 0, 1], [130, 2, 1, 1], [2, 2, 1, 129]], [[128, 2, 2, 130], [0, 0, 2, 2], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 1, 2, 2], [1, 1, 2, 130]], [[128, 0, 1, 129], [0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 2, 130]], [[128, 0, 2, 130], [0, 0, 2, 2], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 1, 1], [0, 0, 1, 1], [130, 2, 1, 1], [2, 2, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 1, 1, 1], [2, 2, 2, 130]], [[128, 0, 0, 0], [1, 1, 1, 1], [129, 1, 1, 1], [2, 2, 2, 130]], [[128, 0, 0, 0], [1, 1, 129, 1], [2, 2, 2, 2], [2, 2, 2, 130]], [[128, 0, 1, 2], [0, 0, 129, 2], [0, 0, 1, 2], [0, 0, 1, 130]], [[128, 1, 1, 2], [0, 1, 129, 2], [0, 1, 1, 2], [0, 1, 1, 130]], [[128, 1, 2, 2], [0, 129, 2, 2], [0, 1, 2, 2], [0, 1, 2, 130]], [[128, 0, 1, 129], [0, 1, 1, 2], [1, 1, 2, 2], [1, 2, 2, 130]], [[128, 0, 1, 129], [2, 0, 0, 1], [130, 2, 0, 0], [2, 2, 2, 0]], [[128, 0, 0, 129], [0, 0, 1, 1], [0, 1, 1, 2], [1, 1, 2, 130]], [[128, 1, 1, 129], [0, 0, 1, 1], [130, 0, 0, 1], [2, 2, 0, 0]], [[128, 0, 0, 0], [1, 1, 2, 2], [129, 1, 2, 2], [1, 1, 2, 130]], [[128, 0, 2, 130], [0, 0, 2, 2], [0, 0, 2, 2], [1, 1, 1, 129]], [[128, 1, 1, 129], [0, 1, 1, 1], [0, 2, 2, 2], [0, 2, 2, 130]], [[128, 0, 0, 129], [0, 0, 0, 1], [130, 2, 2, 1], [2, 2, 2, 1]], [[128, 0, 0, 0], [0, 0, 129, 1], [0, 1, 2, 2], [0, 1, 2, 130]], [[128, 0, 0, 0], [1, 1, 0, 0], [130, 2, 129, 0], [2, 2, 1, 0]], [[128, 1, 2, 130], [0, 129, 2, 2], [0, 0, 1, 1], [0, 0, 0, 0]], [[128, 0, 1, 2], [0, 0, 1, 2], [129, 1, 2, 2], [2, 2, 2, 130]], [[128, 1, 1, 0], [1, 2, 130, 1], [129, 2, 2, 1], [0, 1, 1, 0]], [[128, 0, 0, 0], [0, 1, 129, 0], [1, 2, 130, 1], [1, 2, 2, 1]], [[128, 0, 2, 2], [1, 1, 0, 2], [129, 1, 0, 2], [0, 0, 2, 130]], [[128, 1, 1, 0], [0, 129, 1, 0], [2, 0, 0, 2], [2, 2, 2, 130]], [[128, 0, 1, 1], [0, 1, 2, 2], [0, 1, 130, 2], [0, 0, 1, 129]], [[128, 0, 0, 0], [2, 0, 0, 0], [130, 2, 1, 1], [2, 2, 2, 129]], [[128, 0, 0, 0], [0, 0, 0, 2], [129, 1, 2, 2], [1, 2, 2, 130]], [[128, 2, 2, 130], [0, 0, 2, 2], [0, 0, 1, 2], [0, 0, 1, 129]], [[128, 0, 1, 129], [0, 0, 1, 2], [0, 0, 2, 2], [0, 2, 2, 130]], [[128, 1, 2, 0], [0, 129, 2, 0], [0, 1, 130, 0], [0, 1, 2, 0]], [[128, 0, 0, 0], [1, 1, 129, 1], [2, 2, 130, 2], [0, 0, 0, 0]], [[128, 1, 2, 0], [1, 2, 0, 1], [130, 0, 129, 2], [0, 1, 2, 0]], [[128, 1, 2, 0], [2, 0, 1, 2], [129, 130, 0, 1], [0, 1, 2, 0]], [[128, 0, 1, 1], [2, 2, 0, 0], [1, 1, 130, 2], [0, 0, 1, 129]], [[128, 0, 1, 1], [1, 1, 130, 2], [2, 2, 0, 0], [0, 0, 1, 129]], [[128, 1, 0, 129], [0, 1, 0, 1], [2, 2, 2, 2], [2, 2, 2, 130]], [[128, 0, 0, 0], [0, 0, 0, 0], [130, 1, 2, 1], [2, 1, 2, 129]], [[128, 0, 2, 2], [1, 129, 2, 2], [0, 0, 2, 2], [1, 1, 2, 130]], [[128, 0, 2, 130], [0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 1, 129]], [[128, 2, 2, 0], [1, 2, 130, 1], [0, 2, 2, 0], [1, 2, 2, 129]], [[128, 1, 0, 1], [2, 2, 130, 2], [2, 2, 2, 2], [0, 1, 0, 129]], [[128, 0, 0, 0], [2, 1, 2, 1], [130, 1, 2, 1], [2, 1, 2, 129]], [[128, 1, 0, 129], [0, 1, 0, 1], [0, 1, 0, 1], [2, 2, 2, 130]], [[128, 2, 2, 130], [0, 1, 1, 1], [0, 2, 2, 2], [0, 1, 1, 129]], [[128, 0, 0, 2], [1, 129, 1, 2], [0, 0, 0, 2], [1, 1, 1, 130]], [[128, 0, 0, 0], [2, 129, 1, 2], [2, 1, 1, 2], [2, 1, 1, 130]], [[128, 2, 2, 2], [0, 129, 1, 1], [0, 1, 1, 1], [0, 2, 2, 130]], [[128, 0, 0, 2], [1, 1, 1, 2], [129, 1, 1, 2], [0, 0, 0, 130]], [[128, 1, 1, 0], [0, 129, 1, 0], [0, 1, 1, 0], [2, 2, 2, 130]], [[128, 0, 0, 0], [0, 0, 0, 0], [2, 1, 129, 2], [2, 1, 1, 130]], [[128, 1, 1, 0], [0, 129, 1, 0], [2, 2, 2, 2], [2, 2, 2, 130]], [[128, 0, 2, 2], [0, 0, 1, 1], [0, 0, 129, 1], [0, 0, 2, 130]], [[128, 0, 2, 2], [1, 1, 2, 2], [129, 1, 2, 2], [0, 0, 2, 130]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 129, 1, 130]], [[128, 0, 0, 130], [0, 0, 0, 1], [0, 0, 0, 2], [0, 0, 0, 129]], [[128, 2, 2, 2], [1, 2, 2, 2], [0, 2, 2, 2], [129, 2, 2, 130]], [[128, 1, 0, 129], [2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 130]], [[128, 1, 1, 129], [2, 0, 1, 1], [130, 2, 0, 1], [2, 2, 2, 0]], ],
];
let a_weight2 = [0, 21, 43, 64];
let a_weight3 = [0, 9, 18, 27, 37, 46, 55, 64];
let a_weight4 = [0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64];
let s_mode_has_pbits = 0b11001011;
let mut bstream = Bitstream {
low: u64::from_le_bytes(compressed_block[0..8].try_into().unwrap()),
high: u64::from_le_bytes(compressed_block[8..16].try_into().unwrap()),
};
let mut endpoints = [[0; 4]; 6];
let mut indices = [[0u8; 4]; 4];
let mut mode = 0;
while mode < 8 && (0 == bstream.read_bit()) {
mode += 1;
}
if mode >= 8 {
for i in 0..4 {
let index = i * destination_pitch;
decompressed_block[index..index + 4 * 4].fill(0);
}
return;
}
let mut partition = 0;
let mut num_partitions = 1;
let mut rotation = 0;
let mut index_selection_bit = 0;
if mode == 0 || mode == 1 || mode == 2 || mode == 3 || mode == 7 {
num_partitions = if mode == 0 || mode == 2 { 3 } else { 2 };
partition = bstream.read_bits(if mode == 0 { 4 } else { 6 });
}
let num_endpoints = num_partitions * 2;
if mode == 4 || mode == 5 {
rotation = bstream.read_bits(2);
if mode == 4 {
index_selection_bit = bstream.read_bit();
}
}
for i in 0..3 {
for endpoint in endpoints.iter_mut().take(num_endpoints) {
endpoint[i] = bstream.read_bits(ACTUAL_BITS_COUNT[0][mode] as u32);
}
}
if ACTUAL_BITS_COUNT[1][mode] > 0 {
for endpoint in endpoints.iter_mut().take(num_endpoints) {
endpoint[3] = bstream.read_bits(ACTUAL_BITS_COUNT[1][mode] as u32);
}
}
if mode == 0 || mode == 1 || mode == 3 || mode == 6 || mode == 7 {
for endpoint in endpoints.iter_mut().take(num_endpoints) {
for endpoint in endpoint.iter_mut().take(4) {
*endpoint <<= 1;
}
}
if mode == 1 {
let i = bstream.read_bit();
let j = bstream.read_bit();
for k in 0..3 {
endpoints[0][k] |= i;
endpoints[1][k] |= i;
endpoints[2][k] |= j;
endpoints[3][k] |= j;
}
} else if (s_mode_has_pbits & (1 << mode)) != 0 {
for endpoint in endpoints.iter_mut().take(num_endpoints) {
let j = bstream.read_bit();
for endpoint in endpoint.iter_mut().take(4) {
*endpoint |= j;
}
}
}
}
for endpoint in endpoints.iter_mut().take(num_endpoints) {
let j = ACTUAL_BITS_COUNT[0][mode] + ((s_mode_has_pbits >> mode) & 1);
for endpoint in endpoint.iter_mut().take(3) {
*endpoint <<= 8 - j;
*endpoint |= *endpoint >> j;
}
let j = ACTUAL_BITS_COUNT[1][mode] + ((s_mode_has_pbits >> mode) & 1);
endpoint[3] <<= 8 - j;
endpoint[3] |= endpoint[3] >> j;
}
if ACTUAL_BITS_COUNT[1][mode] == 0 {
for endpoint in endpoints.iter_mut().take(num_endpoints) {
endpoint[3] = 0xFF;
}
}
let mut index_bits = if mode == 0 || mode == 1 {
3
} else if mode == 6 {
4
} else {
2
};
let index_bits2 = if mode == 4 {
3
} else if mode == 5 {
2
} else {
0
};
let weights = if index_bits == 2 {
&a_weight2[..]
} else if index_bits == 3 {
&a_weight3[..]
} else {
&a_weight4[..]
};
let weights2 = if index_bits2 == 2 {
&a_weight2[..]
} else {
&a_weight3[..]
};
for (i, indices) in indices.iter_mut().enumerate() {
for (j, index) in indices.iter_mut().enumerate() {
let partition_set = if num_partitions == 1 {
if i | j != 0 {
0
} else {
128
}
} else {
PARTITION_SETS[num_partitions - 2][partition as usize][i][j]
};
index_bits = if mode == 0 || mode == 1 {
3
} else if mode == 6 {
4
} else {
2
};
if partition_set & 0x80 != 0 {
index_bits -= 1;
}
*index = bstream.read_bits(index_bits) as u8;
}
}
for (i, indices) in indices.iter().enumerate() {
assert!(decompressed_block.len() >= i * destination_pitch + 4 * 4);
for (j, index) in indices.iter().enumerate() {
let mut partition_set = if num_partitions == 1 {
if i | j != 0 {
0usize
} else {
128usize
}
} else {
PARTITION_SETS[num_partitions - 2][partition as usize][i][j] as usize
};
partition_set &= 0x03;
let weight = weights[*index as usize];
let mut r;
let mut g;
let mut b;
let mut a;
if index_bits2 == 0 {
r = interpolate(
endpoints[partition_set * 2][0],
endpoints[partition_set * 2 + 1][0],
weight,
);
g = interpolate(
endpoints[partition_set * 2][1],
endpoints[partition_set * 2 + 1][1],
weight,
);
b = interpolate(
endpoints[partition_set * 2][2],
endpoints[partition_set * 2 + 1][2],
weight,
);
a = interpolate(
endpoints[partition_set * 2][3],
endpoints[partition_set * 2 + 1][3],
weight,
);
} else {
let index2 = bstream.read_bits(if i | j != 0 {
index_bits2
} else {
index_bits2 - 1
});
let weight2 = weights2[index2 as usize];
if index_selection_bit == 0 {
r = interpolate(
endpoints[partition_set * 2][0],
endpoints[partition_set * 2 + 1][0],
weight,
);
g = interpolate(
endpoints[partition_set * 2][1],
endpoints[partition_set * 2 + 1][1],
weight,
);
b = interpolate(
endpoints[partition_set * 2][2],
endpoints[partition_set * 2 + 1][2],
weight,
);
a = interpolate(
endpoints[partition_set * 2][3],
endpoints[partition_set * 2 + 1][3],
weight2,
);
} else {
r = interpolate(
endpoints[partition_set * 2][0],
endpoints[partition_set * 2 + 1][0],
weight2,
);
g = interpolate(
endpoints[partition_set * 2][1],
endpoints[partition_set * 2 + 1][1],
weight2,
);
b = interpolate(
endpoints[partition_set * 2][2],
endpoints[partition_set * 2 + 1][2],
weight2,
);
a = interpolate(
endpoints[partition_set * 2][3],
endpoints[partition_set * 2 + 1][3],
weight,
);
}
}
match rotation {
1 => {
core::mem::swap(&mut a, &mut r);
}
2 => {
core::mem::swap(&mut a, &mut g);
}
3 => {
core::mem::swap(&mut a, &mut b);
}
_ => (),
}
let index = i * destination_pitch + j * 4;
decompressed_block[index..index + 4]
.copy_from_slice(&[r as u8, g as u8, b as u8, a as u8]);
}
}
}
fn color_block(
compressed_block: &[u8],
decompressed_block: &mut [u8],
destination_pitch: usize,
only_opaque_mode: bool,
) {
let mut ref_colors = [[0u8; 4]; 4];
let c0 = u16::from_le_bytes(compressed_block[0..2].try_into().unwrap());
let c1 = u16::from_le_bytes(compressed_block[2..4].try_into().unwrap());
let r0 = (c0 as u32 >> 11) & 0x1F;
let g0 = (c0 as u32 >> 5) & 0x3F;
let b0 = c0 as u32 & 0x1F;
let r1 = (c1 as u32 >> 11) & 0x1F;
let g1 = (c1 as u32 >> 5) & 0x3F;
let b1 = c1 as u32 & 0x1F;
let r = (r0 * 527 + 23) >> 6;
let g = (g0 * 259 + 33) >> 6;
let b = (b0 * 527 + 23) >> 6;
ref_colors[0] = [r as u8, g as u8, b as u8, 255];
let r = (r1 * 527 + 23) >> 6;
let g = (g1 * 259 + 33) >> 6;
let b = (b1 * 527 + 23) >> 6;
ref_colors[1] = [r as u8, g as u8, b as u8, 255];
if c0 > c1 || only_opaque_mode {
let r = ((2 * r0 + r1) * 351 + 61) >> 7;
let g = ((2 * g0 + g1) * 2763 + 1039) >> 11;
let b = ((2 * b0 + b1) * 351 + 61) >> 7;
ref_colors[2] = [r as u8, g as u8, b as u8, 255u8];
let r = ((r0 + r1 * 2) * 351 + 61) >> 7;
let g = ((g0 + g1 * 2) * 2763 + 1039) >> 11;
let b = ((b0 + b1 * 2) * 351 + 61) >> 7;
ref_colors[3] = [r as u8, g as u8, b as u8, 255u8];
} else {
let r = ((r0 + r1) * 1053 + 125) >> 8;
let g = ((g0 + g1) * 4145 + 1019) >> 11;
let b = ((b0 + b1) * 1053 + 125) >> 8;
ref_colors[2] = [r as u8, g as u8, b as u8, 255u8];
ref_colors[3] = [0u8; 4];
}
let mut color_indices = u32::from_le_bytes(compressed_block[4..8].try_into().unwrap());
for i in 0..4 {
for j in 0..4 {
let idx = color_indices & 0x03;
let start = i * destination_pitch + j * 4;
decompressed_block[start..start + 4].copy_from_slice(&ref_colors[idx as usize]);
color_indices >>= 2;
}
}
}
fn sharp_alpha_block(
compressed_block: &[u8],
decompressed_block: &mut [u8],
destination_pitch: usize,
) {
for i in 0..4 {
for j in 0..4 {
let index = i * destination_pitch + j * 4 + 3;
let alpha = u16::from_le_bytes(compressed_block[i * 2..i * 2 + 2].try_into().unwrap());
decompressed_block[index] = ((alpha >> (4 * j)) & 0x0F) as u8 * 17;
}
}
}
fn smooth_alpha_block(
compressed_block: &[u8],
decompressed_block: &mut [u8],
destination_pitch: usize,
pixel_size: usize,
) {
let mut alpha = [0u32; 8];
alpha[0] = compressed_block[0] as u32;
alpha[1] = compressed_block[1] as u32;
if alpha[0] > alpha[1] {
alpha[2] = (6 * alpha[0] + alpha[1] + 1) / 7; alpha[3] = (5 * alpha[0] + 2 * alpha[1] + 1) / 7; alpha[4] = (4 * alpha[0] + 3 * alpha[1] + 1) / 7; alpha[5] = (3 * alpha[0] + 4 * alpha[1] + 1) / 7; alpha[6] = (2 * alpha[0] + 5 * alpha[1] + 1) / 7; alpha[7] = (alpha[0] + 6 * alpha[1] + 1) / 7; } else {
alpha[2] = (4 * alpha[0] + alpha[1] + 1) / 5; alpha[3] = (3 * alpha[0] + 2 * alpha[1] + 1) / 5; alpha[4] = (2 * alpha[0] + 3 * alpha[1] + 1) / 5; alpha[5] = (alpha[0] + 4 * alpha[1] + 1) / 5; alpha[6] = 0x00;
alpha[7] = 0xFF;
}
let block = u64::from_le_bytes(compressed_block[..8].try_into().unwrap());
let mut indices = block >> 16;
for i in 0..4 {
for j in 0..4 {
let index = i * destination_pitch + j * pixel_size;
decompressed_block[index] = alpha[(indices & 0x07) as usize] as u8;
indices >>= 3;
}
}
}
fn bc4_block(
compressed_block: &[u8],
decompressed_block: &mut [u8],
destination_pitch: usize,
pixel_size: usize,
is_signed: bool,
) {
let mut alpha = [0; 8];
let a_weights4 = [13107, 26215, 39321, 52429];
let a_weights6 = [9363, 18724, 28086, 37450, 46812, 56173];
if is_signed {
alpha[0] = (compressed_block[0] as i8) as i32;
alpha[1] = (compressed_block[1] as i8) as i32;
if alpha[0] < -127 {
alpha[0] = -127
};
if alpha[1] < -127 {
alpha[1] = -127
};
} else {
alpha[0] = compressed_block[0] as i32;
alpha[1] = compressed_block[1] as i32;
}
if alpha[0] > alpha[1] {
alpha[2] = (a_weights6[5] * alpha[0] + a_weights6[0] * alpha[1] + 32768) >> 16; alpha[3] = (a_weights6[4] * alpha[0] + a_weights6[1] * alpha[1] + 32768) >> 16; alpha[4] = (a_weights6[3] * alpha[0] + a_weights6[2] * alpha[1] + 32768) >> 16; alpha[5] = (a_weights6[2] * alpha[0] + a_weights6[3] * alpha[1] + 32768) >> 16; alpha[6] = (a_weights6[1] * alpha[0] + a_weights6[4] * alpha[1] + 32768) >> 16; alpha[7] = (a_weights6[0] * alpha[0] + a_weights6[5] * alpha[1] + 32768) >> 16;
} else {
alpha[2] = (a_weights4[3] * alpha[0] + a_weights4[0] * alpha[1] + 32768) >> 16; alpha[3] = (a_weights4[2] * alpha[0] + a_weights4[1] * alpha[1] + 32768) >> 16; alpha[4] = (a_weights4[1] * alpha[0] + a_weights4[2] * alpha[1] + 32768) >> 16; alpha[5] = (a_weights4[0] * alpha[0] + a_weights4[3] * alpha[1] + 32768) >> 16; alpha[6] = if is_signed { -127 } else { 0 };
alpha[7] = if is_signed { 127 } else { 255 };
}
let block = u64::from_le_bytes(compressed_block[..8].try_into().unwrap());
let mut indices = block >> 16;
for i in 0..4 {
for j in 0..4 {
let index = i * destination_pitch + j * pixel_size;
decompressed_block[index] = alpha[indices as usize & 0x7] as u8;
indices >>= 3;
}
}
}
fn bc4_block_float(
compressed_block: &[u8],
decompressed_block: &mut [f32],
destination_pitch: usize,
pixel_size: usize,
is_signed: bool,
) {
let mut alpha = [0.0; 8];
if is_signed {
alpha[0] = (compressed_block[0] as i8) as f32 / 127.0;
alpha[1] = (compressed_block[1] as i8) as f32 / 127.0;
if alpha[0] < -1.0 {
alpha[0] = -1.0
};
if alpha[1] < -1.0 {
alpha[1] = -1.0
};
} else {
alpha[0] = compressed_block[0] as f32 / 255.0;
alpha[1] = compressed_block[1] as f32 / 255.0;
}
if alpha[0] > alpha[1] {
alpha[2] = (6.0 * alpha[0] + alpha[1]) / 7.0; alpha[3] = (5.0 * alpha[0] + 2.0 * alpha[1]) / 7.0; alpha[4] = (4.0 * alpha[0] + 3.0 * alpha[1]) / 7.0; alpha[5] = (3.0 * alpha[0] + 4.0 * alpha[1]) / 7.0; alpha[6] = (2.0 * alpha[0] + 5.0 * alpha[1]) / 7.0; alpha[7] = (alpha[0] + 6.0 * alpha[1]) / 7.0; } else {
alpha[2] = (4.0 * alpha[0] + alpha[1]) / 5.0; alpha[3] = (3.0 * alpha[0] + 2.0 * alpha[1]) / 5.0; alpha[4] = (2.0 * alpha[0] + 3.0 * alpha[1]) / 5.0; alpha[5] = (alpha[0] + 4.0 * alpha[1]) / 5.0; alpha[6] = if is_signed { -1.0 } else { 0.0 };
alpha[7] = 1.0;
}
let block = u64::from_le_bytes(compressed_block[..8].try_into().unwrap());
let mut indices = block >> 16;
for i in 0..4 {
for j in 0..4 {
let index = i * destination_pitch + j * pixel_size;
decompressed_block[index] = alpha[indices as usize & 0x7];
indices >>= 3;
}
}
}
struct Bitstream {
low: u64,
high: u64,
}
impl Bitstream {
fn read_bits(&mut self, num_bits: u32) -> u32 {
let mask = (1 << num_bits) - 1;
let bits = self.low & mask;
self.low >>= num_bits;
self.low |= (self.high & mask) << (u64::BITS as u64 - num_bits as u64);
self.high >>= num_bits;
bits as u32
}
fn read_bit(&mut self) -> u32 {
self.read_bits(1)
}
fn read_bits_i32(&mut self, num_bits: u32) -> i32 {
self.read_bits(num_bits) as i32
}
fn read_bit_i32(&mut self) -> i32 {
self.read_bit() as i32
}
fn read_bits_r(&mut self, num_bits: u32) -> i32 {
let mut bits = self.read_bits_i32(num_bits);
let mut result = 0;
for _ in 0..num_bits {
result <<= 1;
result |= bits & 1;
bits >>= 1;
}
result
}
}
fn extend_sign(val: i32, bits: i32) -> i32 {
(val << (32 - bits)) >> (32 - bits)
}
fn transform_inverse(val: i32, a0: i32, bits: i32, is_signed: bool) -> i32 {
let mut val = (val + a0) & ((1 << bits) - 1);
if is_signed {
val = extend_sign(val, bits);
}
val
}
fn unquantize(val: i32, bits: i32, is_signed: bool) -> i32 {
let mut unq;
let mut s = 0;
let mut val = val;
if !is_signed {
if bits >= 15 {
unq = val;
} else if val == 0 {
unq = 0;
} else if val == (1 << bits) - 1 {
unq = 0xFFFF;
} else {
unq = ((val << 16) + 0x8000) >> bits;
}
} else {
if bits >= 16 {
} else if val < 0 {
s = 1;
val = -val;
}
if val == 0 {
unq = 0;
} else if val >= ((1 << (bits - 1)) - 1) {
unq = 0x7FFF;
} else {
unq = ((val << 15) + 0x4000) >> (bits - 1);
}
if s != 0 {
unq = -unq;
}
}
unq
}
fn interpolate(a: u32, b: u32, weight: u32) -> u32 {
(a * (64 - weight) + b * weight + 32) >> 6
}
fn interpolate_i32(a: i32, b: i32, weight: i32) -> i32 {
(a * (64 - weight) + b * weight + 32) >> 6
}
fn finish_unquantize(val: i32, is_signed: bool) -> u16 {
if !is_signed {
((val * 31) >> 6) as u16 } else {
let mut val = if val < 0 {
-((-val * 31) >> 5)
} else {
(val * 31) >> 5
}; let mut s = 0;
if val < 0 {
s = 0x8000;
val = -val;
}
(s | val) as u16
}
}
fn half_to_float_quick(half: u16) -> f32 {
let magic = f32::from_bits(113 << 23);
let shifted_exp = 0x7c00 << 13;
let mut o = (half as u32 & 0x7fff) << 13; let exp = shifted_exp & o; o += (127 - 15) << 23;
if exp == shifted_exp {
o += (128 - 16) << 23; } else if exp == 0 {
o += 1 << 23; o = (f32::from_bits(o) - magic).to_bits(); }
o |= (half as u32 & 0x8000) << 16; f32::from_bits(o)
}