use std::collections::HashMap;
use std::error::Error;
use std::io::Cursor;
use base64::Engine;
use image::ImageOutputFormat;
use log::debug;
use serde::{Deserialize, Serialize};
use crate::textures::TextureManager;
pub const SPRITESHEET_IMAGE_FILE: &[u8] = include_bytes!("../../../assets/dist/spritesheet.png");
pub const SPRITESHEET_DATA_FILE: &str = include_str!("../../../assets/dist/spritesheet.ron");
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct SpritePosition {
pub name: String,
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
pub offsets: Option<[f32; 2]>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct SerializedSpriteSheet {
pub texture_width: f32,
pub texture_height: f32,
pub sprites: Vec<SpritePosition>,
}
#[derive(Debug)]
pub struct TextureLoader {
pub sprites: HashMap<String, String>
}
impl TextureManager for TextureLoader {
fn load() -> Result<Self, Box<dyn Error>> where Self: Sized {
// load the generated spritesheet data
let spritesheet_data: SerializedSpriteSheet = ron::from_str(SPRITESHEET_DATA_FILE)?;
// load the generated spritesheet image
let spritesheet_image = image::load_from_memory(SPRITESHEET_IMAGE_FILE)?;
if spritesheet_image.width() as f32 != spritesheet_data.texture_width {
return Err("Image width mismatch between spritesheet and data file".into());
}
if spritesheet_image.height() as f32 != spritesheet_data.texture_height {
return Err("Image height mismatch between spritesheet and data file".into());
}
let mut sprites = HashMap::new();
for sprite in spritesheet_data.sprites {
debug!("Loading texture {} ({}x{}, start at {}, {})", sprite.name, sprite.width, sprite.height, sprite.x, sprite.y);
let sprite_img = spritesheet_image.crop_imm(sprite.x as u32, sprite.y as u32, sprite.width as u32, sprite.height as u32);
let mut image_data: Vec<u8> = Vec::new();
sprite_img.write_to(&mut Cursor::new(&mut image_data), ImageOutputFormat::Png)
.unwrap();
let res_base64 = base64::engine::general_purpose::STANDARD.encode(image_data);
sprites.insert(sprite.name, res_base64);
}
debug!("Loaded {} sprites from spritesheet", sprites.len());
Ok(Self {
sprites,
})
}
fn get_texture(&self, texture_id: &str) -> Option<&String> {
self.sprites.get(texture_id)
}
}