tomolib 1.1.0

Library for reading, modifying, and extracting Tomodachi Life data formats.
Documentation
#![allow(clippy::unnecessary_wraps)]

use crate::formats::bntx::format::ChannelFormat;
use crate::formats::bntx::image::RgbaImage;
use crate::{Error, Result};

const ASTC_PRESET: ctt_astcenc::Preset = ctt_astcenc::Preset::Medium;

pub(crate) fn encode_astc(img: &RgbaImage, ch: ChannelFormat, srgb: bool) -> Result<Vec<u8>> {
    use ctt_astcenc::{Context, Flags, Profile, Swizzle, bindings, config_init};

    let (bw, bh) = ch.block_dim();
    let profile = if srgb { Profile::LdrSrgb } else { Profile::Ldr };

    let config = config_init(profile, bw, bh, 1, ASTC_PRESET, Flags::USE_DECODE_UNORM8)
        .map_err(|e| Error::decode(format!("ASTC config: {e}")))?;
    let mut ctx = Context::new(&config).map_err(|e| Error::decode(format!("ASTC ctx: {e}")))?;

    let blocks_x = img.width.div_ceil(bw) as usize;
    let blocks_y = img.height.div_ceil(bh) as usize;
    let mut out = vec![0u8; blocks_x * blocks_y * 16];

    let mut buf = img.data.clone();
    let mut plane: *mut core::ffi::c_void = buf.as_mut_ptr().cast();
    let mut image = bindings::astcenc_image {
        dim_x: img.width,
        dim_y: img.height,
        dim_z: 1,
        data_type: bindings::astcenc_type_ASTCENC_TYPE_U8,
        data: &raw mut plane,
    };

    ctx.compress(&mut image, Swizzle::IDENTITY, &mut out)
        .map_err(|e| Error::decode(format!("ASTC encode: {e}")))?;
    Ok(out)
}

pub(crate) fn encode_bc4(img: &RgbaImage) -> Result<Vec<u8>> {
    let r: Vec<u8> = img.data.chunks_exact(4).map(|p| p[0]).collect();
    let surf = intel_tex_2::RSurface {
        width: img.width,
        height: img.height,
        stride: img.width,
        data: &r,
    };
    Ok(intel_tex_2::bc4::compress_blocks(&surf))
}

pub(crate) fn encode_bc5(img: &RgbaImage) -> Result<Vec<u8>> {
    let rg: Vec<u8> = img
        .data
        .chunks_exact(4)
        .flat_map(|p| [p[0], p[1]])
        .collect();
    let surf = intel_tex_2::RgSurface {
        width: img.width,
        height: img.height,
        stride: img.width * 2,
        data: &rg,
    };
    Ok(intel_tex_2::bc5::compress_blocks(&surf))
}

pub(crate) fn encode_bc7(img: &RgbaImage) -> Result<Vec<u8>> {
    let surf = intel_tex_2::RgbaSurface {
        width: img.width,
        height: img.height,
        stride: img.width * 4,
        data: &img.data,
    };
    Ok(intel_tex_2::bc7::compress_blocks(
        &intel_tex_2::bc7::alpha_basic_settings(),
        &surf,
    ))
}