use libasp::{
AspPacket, AspResult, Color, ColorPalette, DPacketPayload, IPacketPayload, QualityLevel, Rect,
RegionDescriptor,
};
use crate::types::SdfTree;
const ASP_BINCODE_LIMIT: usize = 256 * 1024 * 1024;
pub fn create_sdf_i_packet(tree: &SdfTree, sequence: u32) -> AspResult<AspPacket> {
let asdf_bytes = bincode::serde::encode_to_vec(
tree,
bincode::config::legacy().with_limit::<ASP_BINCODE_LIMIT>(),
)
.map_err(|e| libasp::AspError::SerializationError(e.to_string()))?;
let mut payload = IPacketPayload::new(0, 0, 0.0);
payload.quality = QualityLevel::High;
payload.timestamp_ms = 0;
let region = RegionDescriptor {
bounds: Rect::new(0, 0, 0, 0),
pattern_type: libasp::PatternType::Complex,
palette: ColorPalette {
colors: vec![Color::new(
(asdf_bytes.len() >> 16) as u8,
(asdf_bytes.len() >> 8) as u8,
asdf_bytes.len() as u8,
)],
weights: None,
},
dct_coefficients: Some(
asdf_bytes
.iter()
.enumerate()
.map(|(i, &b)| (i as u32, 0, b as f32))
.collect(),
),
texture_id: None,
params: Some(vec![("asdf_len".to_string(), asdf_bytes.len() as f32)]),
};
payload.regions.push(region);
AspPacket::create_i_packet(sequence, payload)
}
pub fn create_sdf_d_packet(
delta_asdf: &[u8],
ref_sequence: u32,
sequence: u32,
) -> AspResult<AspPacket> {
let mut payload = DPacketPayload::new(ref_sequence);
payload.timestamp_ms = 0;
let delta = libasp::RegionDelta {
region_index: 0,
palette_delta: None,
dct_delta: Some(
delta_asdf
.iter()
.enumerate()
.map(|(i, &b)| (i as u32, 0, b as f32))
.collect(),
),
param_delta: Some(vec![("asdf_len".to_string(), delta_asdf.len() as f32)]),
};
payload.region_deltas.push(delta);
AspPacket::create_d_packet(sequence, payload)
}
pub fn decode_sdf_i_packet(packet: &AspPacket) -> Result<SdfTree, String> {
let i_payload = packet
.as_i_packet()
.ok_or_else(|| "Not an I-packet".to_string())?;
let region = i_payload
.regions
.first()
.ok_or_else(|| "No regions in I-packet".to_string())?;
let asdf_len = region
.params
.as_ref()
.and_then(|p| p.iter().find(|(k, _)| k == "asdf_len"))
.map(|(_, v)| *v as usize)
.ok_or_else(|| "Missing asdf_len param".to_string())?;
let coeffs = region
.dct_coefficients
.as_ref()
.ok_or_else(|| "No DCT data in region".to_string())?;
let mut asdf_bytes = vec![0u8; asdf_len];
for &(idx, _, val) in coeffs {
if (idx as usize) < asdf_len {
asdf_bytes[idx as usize] = val as u8;
}
}
bincode::serde::decode_from_slice(
&asdf_bytes,
bincode::config::legacy().with_limit::<ASP_BINCODE_LIMIT>(),
)
.map(|(tree, _)| tree)
.map_err(|e| format!("ASDF decode failed: {}", e))
}
pub fn estimate_packet_size(tree: &SdfTree) -> (usize, usize) {
let asdf_bytes = bincode::serde::encode_to_vec(
tree,
bincode::config::legacy().with_limit::<ASP_BINCODE_LIMIT>(),
)
.unwrap_or_default();
let asdf_len = asdf_bytes.len();
let packet_overhead = 16 + 4 + 64; (asdf_len, asdf_len * 12 + packet_overhead)
}