use anyhow::{Context, Result};
use ktx2_rw::{BasisCompressionParams, Ktx2Texture, VkFormat};
pub struct UastcOptions {
pub quality: u32,
pub rdo_quality: Option<f32>,
pub mipmaps: bool,
pub srgb: bool,
}
impl Default for UastcOptions {
fn default() -> Self {
Self {
quality: 2,
rdo_quality: None,
mipmaps: false,
srgb: true,
}
}
}
pub fn encode_uastc(rgba: &[u8], width: u32, height: u32, opts: &UastcOptions) -> Result<Vec<u8>> {
let vk_format = if opts.srgb {
VkFormat::R8G8B8A8Srgb
} else {
VkFormat::R8G8B8A8Unorm
};
let levels = if opts.mipmaps {
((width.max(height) as f32).log2().floor() as u32 + 1).max(1)
} else {
1
};
let mut texture = Ktx2Texture::create(width, height, 1, 1, 1, levels, vk_format)
.context("Failed to create KTX2 texture")?;
texture
.set_image_data(0, 0, 0, rgba)
.context("Failed to set KTX2 image data")?;
let quality_255 = match opts.quality {
0 | 1 => 64,
2 => 128,
3 => 192,
_ => 255,
};
let mut params_builder = BasisCompressionParams::builder()
.uastc(true)
.quality_level(quality_255)
.thread_count(4);
if let Some(rdo) = opts.rdo_quality {
params_builder = params_builder.uastc_rdo_quality_scalar(rdo);
}
let params = params_builder.build();
texture
.compress_basis(¶ms)
.context("UASTC compression failed")?;
texture
.write_to_memory()
.context("Failed to write KTX2 to memory")
}