diff --git a/agb-image-converter/Cargo.lock b/agb-image-converter/Cargo.lock index 71a2c9ee..531ab8ed 100644 --- a/agb-image-converter/Cargo.lock +++ b/agb-image-converter/Cargo.lock @@ -18,15 +18,29 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" name = "agb_image_converter" version = "0.6.0" dependencies = [ + "asefile", "image", "proc-macro2", "quote", "serde", - "serde_json", "syn", "toml", ] +[[package]] +name = "asefile" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d5f7de918fd4cb18249819fc4bd27f6a5dbfbc9dcb271727f27dacf17ce880" +dependencies = [ + "bitflags", + "byteorder", + "flate2", + "image", + "log", + "nohash", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -81,6 +95,18 @@ dependencies = [ "adler32", ] +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide 0.4.4", +] + [[package]] name = "image" version = "0.24.1" @@ -97,10 +123,19 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.1" +name = "libc" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] [[package]] name = "miniz_oxide" @@ -111,6 +146,22 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "nohash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0f889fb66f7acdf83442c35775764b51fed3c606ab9cee51500dbde2cf528ca" + [[package]] name = "num-integer" version = "0.1.44" @@ -161,7 +212,7 @@ dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide", + "miniz_oxide 0.3.7", ] [[package]] @@ -182,12 +233,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - [[package]] name = "serde" version = "1.0.136" @@ -208,17 +253,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "syn" version = "1.0.86" diff --git a/agb-image-converter/Cargo.toml b/agb-image-converter/Cargo.toml index 52fdf639..63f41d98 100644 --- a/agb-image-converter/Cargo.toml +++ b/agb-image-converter/Cargo.toml @@ -16,4 +16,4 @@ serde = { version = "1.0", features = ["derive"] } syn = "1.0.86" proc-macro2 = "1.0.36" quote = "1.0.15" -serde_json = "1.0" \ No newline at end of file +asefile = "0.3.2" diff --git a/agb-image-converter/src/aseprite.rs b/agb-image-converter/src/aseprite.rs index 72a6cbb4..694c0cfd 100644 --- a/agb-image-converter/src/aseprite.rs +++ b/agb-image-converter/src/aseprite.rs @@ -1,102 +1,23 @@ -use std::{ - fs::File, - path::{Path, PathBuf}, - process::Command, - str, -}; +use std::path::Path; +use asefile::{AsepriteFile, Tag}; use image::DynamicImage; -use serde::Deserialize; -#[derive(Deserialize)] -pub struct Aseprite { - pub frames: Vec, - pub meta: Meta, -} - -#[derive(Deserialize)] -pub struct Meta { - pub app: String, - pub version: String, - pub image: String, - pub format: String, - pub size: Size, - pub scale: String, - #[serde(rename = "frameTags")] - pub frame_tags: Vec, -} - -#[derive(Deserialize)] -pub struct Size { - pub w: u32, - pub h: u32, -} - -#[derive(Deserialize, Clone, Copy)] -#[serde(rename_all = "lowercase")] -pub enum Direction { - Forward, - Backward, - Pingpong, -} - -#[derive(Deserialize, Clone)] -pub struct FrameTag { - pub name: String, - pub from: u32, - pub to: u32, - pub direction: Direction, -} - -#[derive(Deserialize, Clone)] -pub struct Frame { - pub frame: Frame2, - pub trimmed: bool, -} - -#[derive(Deserialize, Clone)] -pub struct Frame2 { - pub x: u32, - pub y: u32, - pub w: u32, - pub h: u32, -} - -pub fn generate_from_file(filename: &Path) -> (Aseprite, DynamicImage) { - let out_dir = std::env::var("OUT_DIR").expect("Expected OUT_DIR"); - - let output_filename = Path::new(&out_dir).join(filename.file_name().unwrap()); - - let image_output = output_filename.with_extension("png"); - let json_output = output_filename.with_extension("json"); - - let command = Command::new("aseprite") - .args([ - &PathBuf::from("-b"), - &PathBuf::from(filename), - &"--sheet".into(), - &image_output, - &"--format".into(), - &"json-array".into(), - &"--data".into(), - &json_output, - &"--list-tags".into(), - ]) - .output() - .expect("Could not run aseprite"); - assert!( - command.status.success(), - "Aseprite did not complete successfully : {}", - str::from_utf8(&*command.stdout).unwrap_or("Output contains invalid string") - ); - - let json: Aseprite = serde_json::from_reader( - File::open(&json_output).expect("The json output from aseprite could not be openned"), - ) - .expect("The output from aseprite could not be decoded"); - - ( - json, - image::open(image_output).expect("Image should be readable"), - ) +pub fn generate_from_file(filename: &Path) -> (Vec, Vec) { + let ase = AsepriteFile::read_file(filename).expect("Aseprite file should exist"); + + let mut images = Vec::new(); + let mut tags = Vec::new(); + + for frame in 0..ase.num_frames() { + let image = ase.frame(frame).image(); + + images.push(DynamicImage::ImageRgba8(image)) + } + + for tag in 0..ase.num_tags() { + tags.push(ase.tag(tag).clone()) + } + + (images, tags) } diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs index 4c1a93ae..3278147e 100644 --- a/agb-image-converter/src/lib.rs +++ b/agb-image-converter/src/lib.rs @@ -16,6 +16,7 @@ mod image_loader; mod palette16; mod rust_generator; +use image::GenericImageView; use image_loader::Image; use colour::Colour; @@ -93,7 +94,6 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream { let mut optimiser = palette16::Palette16Optimiser::new(); let mut images = Vec::new(); - let mut frames = Vec::new(); let mut tags = Vec::new(); let root = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get cargo manifest dir"); @@ -105,24 +105,18 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream { .collect(); for filename in filenames.iter() { - let (json, image) = aseprite::generate_from_file(filename); - let tile_size = json.frames[0].frame.w; + let (frames, tag) = aseprite::generate_from_file(filename); - for frame in json.frames.iter() { - assert!(frame.frame.w == tile_size); - assert!( - frame.frame.w == frame.frame.h - && frame.frame.w.is_power_of_two() - && frame.frame.w <= 32 - ); + tags.push((tag, images.len())); + + for frame in frames { + let width = frame.width(); + assert!(width == frame.height() && width.is_power_of_two() && width <= 32); + + let image = Image::load_from_dyn_image(frame); + add_to_optimiser(&mut optimiser, &image, width as usize); + images.push(image); } - - let image = Image::load_from_dyn_image(image); - - add_to_optimiser(&mut optimiser, &image, tile_size as usize); - images.push(image); - frames.push(json.frames.clone()); - tags.push(json.meta.frame_tags.clone()); } let optimised_results = optimiser.optimise_palettes(None); @@ -138,17 +132,16 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream { }); let mut pre = 0; - let sprites = frames + let sprites = images .iter() - .flatten() .zip(assignments.iter()) .map(|(f, assignment)| { let start: usize = pre; - let end: usize = pre + (f.frame.w as usize / 8) * (f.frame.h as usize / 8) * 32; + let end: usize = pre + (f.width / 8) * (f.height / 8) * 32; let data = ByteString(&tile_data[start..end]); pre = end; - let width = f.frame.w as usize; - let height = f.frame.h as usize; + let width = f.width; + let height = f.height; quote! { Sprite::new( &PALETTES[#assignment], @@ -160,15 +153,13 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream { let tags = tags .iter() - .enumerate() - .map(|(i, tag)| { - tag.iter().map(move |tag| (i, tag)).map(|(i, tag)| { - let offset: usize = frames[0..i].iter().map(|s| s.len()).sum(); - let start = tag.from as usize + offset; - let end = tag.to as usize + offset; - let direction = tag.direction as usize; + .map(|(tag, num_images)| { + tag.iter().map(move |tag| { + let start = tag.from_frame() as usize + num_images; + let end = tag.to_frame() as usize + num_images; + let direction = tag.animation_direction() as usize; - let name = &tag.name; + let name = tag.name(); assert!(start <= end, "Tag {} has start > end", name); quote! { diff --git a/agb/Cargo.lock b/agb/Cargo.lock index 3ba21947..017e679b 100644 --- a/agb/Cargo.lock +++ b/agb/Cargo.lock @@ -41,11 +41,11 @@ dependencies = [ name = "agb_image_converter" version = "0.6.0" dependencies = [ + "asefile", "image", "proc-macro2", "quote", "serde", - "serde_json", "syn", "toml", ] @@ -80,6 +80,20 @@ dependencies = [ "version_check", ] +[[package]] +name = "asefile" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d5f7de918fd4cb18249819fc4bd27f6a5dbfbc9dcb271727f27dacf17ce880" +dependencies = [ + "bitflags", + "byteorder", + "flate2", + "image", + "log", + "nohash", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -140,6 +154,18 @@ dependencies = [ "adler32", ] +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide 0.4.4", +] + [[package]] name = "getrandom" version = "0.2.5" @@ -181,18 +207,21 @@ dependencies = [ "png", ] -[[package]] -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - [[package]] name = "libc" version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + [[package]] name = "miniz_oxide" version = "0.5.1" @@ -202,6 +231,16 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "modular-bitfield" version = "0.11.2" @@ -223,6 +262,12 @@ dependencies = [ "syn", ] +[[package]] +name = "nohash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0f889fb66f7acdf83442c35775764b51fed3c606ab9cee51500dbde2cf528ca" + [[package]] name = "num-integer" version = "0.1.44" @@ -323,7 +368,7 @@ dependencies = [ "bitflags", "crc32fast", "deflate", - "miniz_oxide", + "miniz_oxide 0.3.7", ] [[package]] @@ -402,12 +447,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - [[package]] name = "serde" version = "1.0.136" @@ -428,17 +467,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "siphasher" version = "0.3.9"