use bevy_asset::RenderAssetUsages;
use bevy_image::Image;
use lz4_compression::{compress, decompress};
use serde::{Deserialize, Serialize};
use tracing::error;
use wgpu_types::{Extent3d, TextureDimension, TextureFormat};
use crate::binreflect::BINCODE_OPTIONS;
pub(crate) fn image_to_bin(image: &Image) -> Option<Vec<u8>> {
let img = ImageData {
width: image.texture_descriptor.size.width,
height: image.texture_descriptor.size.height,
depth_or_array_layers: image.texture_descriptor.size.depth_or_array_layers,
dimensions: image.texture_descriptor.dimension.into(),
format: image.texture_descriptor.format,
data: image.data.clone()?,
};
let input = match bincode::serde::encode_to_vec(&img, BINCODE_OPTIONS) {
Ok(x) => x,
Err(e) => {
error!("Error encoding image: {e}");
return None;
}
};
Some(compress::compress(&input))
}
pub(crate) fn bin_to_image(bin: &[u8]) -> Option<Image> {
let bin = match decompress::decompress(bin) {
Ok(x) => x,
Err(e) => {
error!("Error decompressing image: {e:?}");
return None;
}
};
let (img, _): (ImageData, _) = match bincode::serde::decode_from_slice(&bin, BINCODE_OPTIONS) {
Ok(x) => x,
Err(e) => {
error!("Error decoding mesh: {e}");
return None;
}
};
Some(Image::new(
Extent3d {
width: img.width,
height: img.height,
depth_or_array_layers: img.depth_or_array_layers,
},
img.dimensions.into(),
img.data,
img.format,
RenderAssetUsages::RENDER_WORLD | RenderAssetUsages::MAIN_WORLD,
))
}
#[derive(Serialize, Deserialize)]
struct ImageData {
width: u32,
height: u32,
depth_or_array_layers: u32,
dimensions: Dimensions,
format: TextureFormat,
data: Vec<u8>,
}
#[derive(Serialize, Deserialize)]
struct Dimensions(u8);
impl From<TextureDimension> for Dimensions {
fn from(value: TextureDimension) -> Self {
Self(match value {
TextureDimension::D1 => 1,
TextureDimension::D2 => 2,
TextureDimension::D3 => 3,
})
}
}
#[allow(clippy::match_same_arms)]
impl From<Dimensions> for TextureDimension {
fn from(value: Dimensions) -> Self {
match value.0 {
1 => TextureDimension::D1,
2 => TextureDimension::D2,
3 => TextureDimension::D3,
_ => TextureDimension::D2,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_image() {
let img = Image::default();
let bin = image_to_bin(&img).unwrap();
let img2 = bin_to_image(&bin).unwrap();
assert_eq!(img.data, img2.data);
}
}