diff --git a/ggdt/Cargo.toml b/ggdt/Cargo.toml index 246ed01..fabe646 100644 --- a/ggdt/Cargo.toml +++ b/ggdt/Cargo.toml @@ -16,6 +16,8 @@ num-traits = "0.2.15" bitflags = "2.1.0" flate2 = "1.0.25" crc32fast = "1.3.2" +serde = { version = "1.0.136", features = ["derive"] } +serde_json = "1.0.79" [target.'cfg(not(windows))'.dependencies] sdl2 = { git = "https://github.com/Rust-SDL2/rust-sdl2/", rev = "819ab438ac971a922d6ee1da558822002d343b4e", features = ["static-link", "bundled", "use-pkgconfig", "unsafe_textures"] } diff --git a/ggdt/src/graphics/bitmapatlas.rs b/ggdt/src/graphics/bitmapatlas.rs index dd26587..3fe5b7b 100644 --- a/ggdt/src/graphics/bitmapatlas.rs +++ b/ggdt/src/graphics/bitmapatlas.rs @@ -1,4 +1,7 @@ +use std::fs::File; +use std::io::{BufReader, BufWriter, Read, Write}; use std::ops::Index; +use std::path::Path; use thiserror::Error; @@ -15,6 +18,9 @@ pub enum BitmapAtlasError { #[error("Invalid dimensions for region")] InvalidDimensions, + + #[error("No bitmap atlas entries in the descriptor")] + NoEntries, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -40,6 +46,27 @@ where } } + pub fn from_descriptor(descriptor: &BitmapAtlasDescriptor, bitmap: BitmapType) -> Result { + if descriptor.tiles.is_empty() { + return Err(BitmapAtlasError::NoEntries); + } + + let mut atlas = BitmapAtlas::new(bitmap); + for entry in descriptor.tiles.iter() { + use BitmapAtlasDescriptorEntry::*; + match entry { + Tile { x, y, width, height } => { + atlas.add(Rect::new(*x as i32, *y as i32, *width, *height))?; + } + Autogrid { x, y, tile_width, tile_height, num_tiles_x, num_tiles_y, border } => { + atlas.add_custom_grid(*x, *y, *tile_width, *tile_height, *num_tiles_x, *num_tiles_y, *border)?; + } + } + } + + Ok(atlas) + } + pub fn add(&mut self, rect: Rect) -> Result { if rect.width == 0 || rect.height == 0 { return Err(BitmapAtlasError::InvalidDimensions); @@ -158,6 +185,70 @@ where } } +#[derive(Error, Debug)] +pub enum BitmapAtlasDescriptorError { + #[error("Serde Json serialization/deserialization error: {0}")] + SerdeJsonError(String), + + #[error("I/O error")] + IOError(#[from] std::io::Error), +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "lowercase")] +pub enum BitmapAtlasDescriptorEntry { + Tile { + x: u32, // + y: u32, + width: u32, + height: u32, + }, + Autogrid { + x: u32, // + y: u32, + tile_width: u32, + tile_height: u32, + num_tiles_x: u32, + num_tiles_y: u32, + border: u32, + }, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct BitmapAtlasDescriptor { + pub bitmap: String, + pub tiles: Vec, +} + +impl BitmapAtlasDescriptor { + pub fn load_from_file(path: &Path) -> Result { + let f = File::open(path)?; + let mut reader = BufReader::new(f); + Self::load_from_bytes(&mut reader) + } + + pub fn load_from_bytes(reader: &mut T) -> Result { + match serde_json::from_reader(reader) { + Ok(desc) => Ok(desc), + Err(error) => Err(BitmapAtlasDescriptorError::SerdeJsonError(error.to_string())), + } + } + + pub fn to_file(&self, path: &Path) -> Result<(), BitmapAtlasDescriptorError> { + let f = File::create(path)?; + let mut writer = BufWriter::new(f); + self.to_bytes(&mut writer) + } + + pub fn to_bytes(&self, writer: &mut T) -> Result<(), BitmapAtlasDescriptorError> { + if let Err(error) = serde_json::to_writer_pretty(writer, &self) { + Err(BitmapAtlasDescriptorError::SerdeJsonError(error.to_string())) + } else { + Ok(()) + } + } +} + #[cfg(test)] mod tests { use claim::*;