diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs index ec4d6d33..02eddcf4 100644 --- a/agb-image-converter/src/lib.rs +++ b/agb-image-converter/src/lib.rs @@ -3,7 +3,7 @@ use syn::parse_macro_input; use std::path::Path; -use quote::{quote, format_ident}; +use quote::{format_ident, quote}; mod colour; mod config; @@ -44,13 +44,18 @@ pub fn include_gfx(input: TokenStream) -> TokenStream { let config = config::parse(&path.to_string_lossy()); - let module_name = format_ident!("{}", path.file_stem().expect("Expected a file stem").to_string_lossy()); + let module_name = format_ident!( + "{}", + path.file_stem() + .expect("Expected a file stem") + .to_string_lossy() + ); let include_path = path.to_string_lossy(); let images = config.images(); - let image_code = images - .iter() - .map(|(image_name, &image)| convert_image(image, parent, &image_name, &config.crate_prefix())); + let image_code = images.iter().map(|(image_name, &image)| { + convert_image(image, parent, &image_name, &config.crate_prefix()) + }); let module = quote! { pub mod #module_name { @@ -80,19 +85,14 @@ fn convert_image( let optimiser = optimiser_for_image(&image, tile_size); let optimisation_results = optimiser.optimise_palettes(settings.transparent_colour()); - let mut writer = String::new(); - rust_generator::generate_code( - &mut writer, variable_name, &optimisation_results, &image, &image_filename.to_string_lossy(), settings.tilesize(), crate_prefix.to_owned(), - ); - - writer.parse().unwrap() + ) } fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16Optimiser { diff --git a/agb-image-converter/src/rust_generator.rs b/agb-image-converter/src/rust_generator.rs index d8f71100..b8514085 100644 --- a/agb-image-converter/src/rust_generator.rs +++ b/agb-image-converter/src/rust_generator.rs @@ -1,121 +1,87 @@ -use std::fmt::Write; - use crate::image_loader::Image; use crate::palette16::Palette16OptimisationResults; use crate::TileSize; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +use std::iter; + pub(crate) fn generate_code( - output: &mut dyn Write, output_variable_name: &str, results: &Palette16OptimisationResults, image: &Image, image_filename: &str, tile_size: TileSize, crate_prefix: String, -) { - writeln!(output, "#[allow(non_upper_case_globals)]").unwrap(); - writeln!( - output, - "pub const {}: {}::display::tile_data::TileData = {{", - output_variable_name, crate_prefix - ) - .unwrap(); +) -> TokenStream { + let crate_prefix = format_ident!("{}", crate_prefix); + let output_variable_name = format_ident!("{}", output_variable_name); - writeln!( - output, - "const _: &[u8] = include_bytes!(\"{}\");", - image_filename - ) - .unwrap(); + let palette_data = results.optimised_palettes.iter().map(|palette| { + let colours = palette + .clone() + .into_iter() + .map(|colour| colour.to_rgb15()) + .chain(iter::repeat(0)) + .take(16); - writeln!( - output, - "const PALETTE_DATA: &[{}::display::palette16::Palette16] = &[", - crate_prefix, - ) - .unwrap(); - - for palette in &results.optimised_palettes { - write!( - output, - " {}::display::palette16::Palette16::new([", - crate_prefix - ) - .unwrap(); - - for colour in palette.clone() { - write!(output, "0x{:08x}, ", colour.to_rgb15()).unwrap(); + quote! { + #crate_prefix::display::palette16::Palette16::new([ + #(#colours),* + ]) } - - for _ in palette.clone().into_iter().len()..16 { - write!(output, "0x00000000, ").unwrap(); - } - - writeln!(output, "]),").unwrap(); - } - - writeln!(output, "];").unwrap(); - writeln!(output).unwrap(); - - writeln!(output, "const TILE_DATA: &[u32] = &[",).unwrap(); + }); let tile_size = tile_size.to_size(); let tiles_x = image.width / tile_size; let tiles_y = image.height / tile_size; - for y in 0..tiles_y { - for x in 0..tiles_x { - let palette_index = results.assignments[y * tiles_x + x]; - let palette = &results.optimised_palettes[palette_index]; - writeln!( - output, - " /* {}, {} (palette index {}) */", - x, y, palette_index - ) - .unwrap(); + let tile_data = (0..tiles_y) + .map(|y| { + (0..tiles_x).map(move |x| { + let palette_index = results.assignments[y * tiles_x + x]; + let palette = &results.optimised_palettes[palette_index]; - for inner_y in 0..tile_size / 8 { - write!(output, " ").unwrap(); + (0..tile_size / 8).map(move |inner_y| { + (0..tile_size / 8).map(move |inner_x| { + (inner_y * 8..inner_y * 8 + 8).map(move |j| { + (inner_x * 8..inner_x * 8 + 8).rev().map(move |i| { + let colour = image.colour(x * tile_size + i, y * tile_size + j); + palette.colour_index(colour) + }) + }) + }) + }) + }) + }) + .flatten() + .flatten() + .flatten() + .flatten() + .flatten(); - for inner_x in 0..tile_size / 8 { - for j in inner_y * 8..inner_y * 8 + 8 { - write!(output, "0x").unwrap(); + let assignments = &results.assignments; - for i in (inner_x * 8..inner_x * 8 + 8).rev() { - let colour = image.colour(x * tile_size + i, y * tile_size + j); - let colour_index = palette.colour_index(colour); + quote! { + #[allow(non_upper_case_globals)] + pub const #output_variable_name: #crate_prefix::display::tile_data::TileData = { + const _: &[u8] = include_bytes!(#image_filename); - write!(output, "{:x}", colour_index).unwrap(); - } + const PALETTE_DATA: &[#crate_prefix::display::palette16::Palette16] = &[ + #(#palette_data),* + ]; - write!(output, ", ").unwrap(); - } - } - } + const TILE_DATA: &[u32] = &[ + #(#tile_data),* + ]; - writeln!(output).unwrap(); - } + const PALETTE_ASSIGNMENT: &[u8] = &[ + #(#assignments),* + ]; + + #crate_prefix::display::tile_data::TileData::new(PALETTE_DATA, TILE_DATA, PALETTE_ASSIGNMENT) + }; } - - writeln!(output, "];").unwrap(); - writeln!(output).unwrap(); - - write!(output, "const PALETTE_ASSIGNMENT: &[u8] = &[").unwrap(); - - for (i, assignment) in results.assignments.iter().enumerate() { - if i % 16 == 0 { - write!(output, "\n ").unwrap(); - } - write!(output, "{}, ", assignment).unwrap(); - } - - writeln!(output, "\n];").unwrap(); - - writeln!( - output, - "{}::display::tile_data::TileData::new(PALETTE_DATA, TILE_DATA, PALETTE_ASSIGNMENT)\n}};", - crate_prefix - ) - .unwrap(); }