use super::decode::{decompress_image, XuastcInfo};
use crate::api::AstcBlock;
use crate::astc::pack::pack_astc_block;
use crate::astc::slice::{transcode_ldr, Target4x4};
use alloc::vec;
use alloc::vec::Vec;
const FLAG_HIGH_QUALITY: u32 = 32;
const FLAG_NO_DEBLOCK: u32 = 128;
const FLAG_FORCE_DEBLOCK: u32 = 512;
pub const FLAG_DISABLE_FAST_BC7: u32 = 1024;
fn decompress_to_blocks(
stream: &[u8],
block: AstcBlock,
bx: u32,
by: u32,
) -> Option<(Vec<u8>, bool, bool)> {
let (sbw, sbh) = block.dims();
use core::cell::{Cell, RefCell};
let blocks: RefCell<Vec<u8>> = RefCell::new(Vec::new());
let ok_dims = Cell::new(false);
let srgb = Cell::new(false);
let has_alpha = Cell::new(false);
let mut init_cb = |info: &XuastcInfo| -> bool {
if info.block_width != sbw || info.block_height != sbh {
return false;
}
let nbx = info.width.div_ceil(info.block_width);
let nby = info.height.div_ceil(info.block_height);
if nbx != bx || nby != by {
return false;
}
ok_dims.set(true);
srgb.set(info.srgb);
has_alpha.set(info.has_alpha);
*blocks.borrow_mut() = vec![0u8; (nbx * nby) as usize * 16];
true
};
let mut block_cb = |cbx: u32, cby: u32, log: &crate::astc::unpack::LogAstcBlock| -> bool {
match pack_astc_block(log) {
Some(phys) => {
let o = ((cby * bx + cbx) as usize) * 16;
blocks.borrow_mut()[o..o + 16].copy_from_slice(&phys);
true
}
None => false,
}
};
decompress_image(stream, &mut init_cb, &mut block_cb)?;
if !ok_dims.get() {
return None;
}
Some((blocks.into_inner(), srgb.get(), has_alpha.get()))
}
#[allow(clippy::too_many_arguments)]
pub fn transcode_xuastc(
stream: &[u8],
block: AstcBlock,
bx: u32,
by: u32,
lw: u32,
lh: u32,
fmt: i32,
flags: u32,
out: &mut [u8],
) -> Option<()> {
use crate::dispatch::target;
let (sbw, sbh) = block.dims();
let (blocks, srgb, has_alpha) = decompress_to_blocks(stream, block, bx, by)?;
if fmt == block.passthrough_target().as_i32() {
if out.len() != blocks.len() {
return None;
}
out.copy_from_slice(&blocks);
return Some(());
}
let high_quality = flags & FLAG_HIGH_QUALITY != 0;
let enable_fast_bc7 = flags & FLAG_DISABLE_FAST_BC7 == 0;
let disable_deblocking = flags & FLAG_NO_DEBLOCK != 0;
let force_deblocking = flags & FLAG_FORCE_DEBLOCK != 0;
let deblock_filtering = !disable_deblocking && (force_deblocking || sbw > 8 || sbh > 6);
if fmt == target::BC7_RGBA
&& enable_fast_bc7
&& !high_quality
&& !deblock_filtering
&& matches!((sbw, sbh), (4, 4) | (8, 6) | (6, 6))
{
return super::bc7_fast::transcode_bc7_fast(
&blocks, sbw, sbh, bx, by, lw, lh, srgb, has_alpha, out,
);
}
let t4 = match fmt {
target::RGBA32 => Target4x4::Rgba32,
target::RGB565 => Target4x4::Rgb565,
target::BGR565 => Target4x4::Bgr565,
target::RGBA4444 => Target4x4::Rgba4444,
target::BC1_RGB => Target4x4::Bc1,
target::BC3_RGBA => Target4x4::Bc3,
target::BC4_R => Target4x4::Bc4,
target::BC5_RG => Target4x4::Bc5,
target::EAC_R11 => Target4x4::EacR11,
target::EAC_RG11 => Target4x4::EacRg11,
target::ETC1_RGB => Target4x4::Etc1,
target::ETC2_RGBA => Target4x4::Etc2Rgba,
target::PVRTC1_4_RGB => Target4x4::Pvrtc1Rgb,
target::PVRTC1_4_RGBA => Target4x4::Pvrtc1Rgba,
target::BC7_RGBA => {
if has_alpha {
Target4x4::Bc7
} else {
Target4x4::Bc7Opaque
}
}
_ => return None,
};
transcode_ldr(
&blocks, sbw, sbh, bx, by, lw, lh, t4, flags, srgb, has_alpha, out,
)
}