Switch entirely to using quote to generate the code

This commit is contained in:
Gwilym Kuiper 2021-07-26 23:27:16 +01:00
parent aa32be1a27
commit fdff081c32
2 changed files with 70 additions and 104 deletions

View file

@ -3,7 +3,7 @@ use syn::parse_macro_input;
use std::path::Path; use std::path::Path;
use quote::{quote, format_ident}; use quote::{format_ident, quote};
mod colour; mod colour;
mod config; mod config;
@ -44,13 +44,18 @@ pub fn include_gfx(input: TokenStream) -> TokenStream {
let config = config::parse(&path.to_string_lossy()); 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 include_path = path.to_string_lossy();
let images = config.images(); let images = config.images();
let image_code = images let image_code = images.iter().map(|(image_name, &image)| {
.iter() convert_image(image, parent, &image_name, &config.crate_prefix())
.map(|(image_name, &image)| convert_image(image, parent, &image_name, &config.crate_prefix())); });
let module = quote! { let module = quote! {
pub mod #module_name { pub mod #module_name {
@ -80,19 +85,14 @@ fn convert_image(
let optimiser = optimiser_for_image(&image, tile_size); let optimiser = optimiser_for_image(&image, tile_size);
let optimisation_results = optimiser.optimise_palettes(settings.transparent_colour()); let optimisation_results = optimiser.optimise_palettes(settings.transparent_colour());
let mut writer = String::new();
rust_generator::generate_code( rust_generator::generate_code(
&mut writer,
variable_name, variable_name,
&optimisation_results, &optimisation_results,
&image, &image,
&image_filename.to_string_lossy(), &image_filename.to_string_lossy(),
settings.tilesize(), settings.tilesize(),
crate_prefix.to_owned(), crate_prefix.to_owned(),
); )
writer.parse().unwrap()
} }
fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16Optimiser { fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16Optimiser {

View file

@ -1,121 +1,87 @@
use std::fmt::Write;
use crate::image_loader::Image; use crate::image_loader::Image;
use crate::palette16::Palette16OptimisationResults; use crate::palette16::Palette16OptimisationResults;
use crate::TileSize; use crate::TileSize;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::iter;
pub(crate) fn generate_code( pub(crate) fn generate_code(
output: &mut dyn Write,
output_variable_name: &str, output_variable_name: &str,
results: &Palette16OptimisationResults, results: &Palette16OptimisationResults,
image: &Image, image: &Image,
image_filename: &str, image_filename: &str,
tile_size: TileSize, tile_size: TileSize,
crate_prefix: String, crate_prefix: String,
) { ) -> TokenStream {
writeln!(output, "#[allow(non_upper_case_globals)]").unwrap(); let crate_prefix = format_ident!("{}", crate_prefix);
writeln!( let output_variable_name = format_ident!("{}", output_variable_name);
output,
"pub const {}: {}::display::tile_data::TileData = {{",
output_variable_name, crate_prefix
)
.unwrap();
writeln!( let palette_data = results.optimised_palettes.iter().map(|palette| {
output, let colours = palette
"const _: &[u8] = include_bytes!(\"{}\");", .clone()
image_filename .into_iter()
) .map(|colour| colour.to_rgb15())
.unwrap(); .chain(iter::repeat(0))
.take(16);
writeln!( quote! {
output, #crate_prefix::display::palette16::Palette16::new([
"const PALETTE_DATA: &[{}::display::palette16::Palette16] = &[", #(#colours),*
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();
} }
});
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 tile_size = tile_size.to_size();
let tiles_x = image.width / tile_size; let tiles_x = image.width / tile_size;
let tiles_y = image.height / tile_size; let tiles_y = image.height / tile_size;
for y in 0..tiles_y { let tile_data = (0..tiles_y)
for x in 0..tiles_x { .map(|y| {
(0..tiles_x).map(move |x| {
let palette_index = results.assignments[y * tiles_x + x]; let palette_index = results.assignments[y * tiles_x + x];
let palette = &results.optimised_palettes[palette_index]; let palette = &results.optimised_palettes[palette_index];
writeln!(
output,
" /* {}, {} (palette index {}) */",
x, y, palette_index
)
.unwrap();
for inner_y in 0..tile_size / 8 { (0..tile_size / 8).map(move |inner_y| {
write!(output, " ").unwrap(); (0..tile_size / 8).map(move |inner_x| {
(inner_y * 8..inner_y * 8 + 8).map(move |j| {
for inner_x in 0..tile_size / 8 { (inner_x * 8..inner_x * 8 + 8).rev().map(move |i| {
for j in inner_y * 8..inner_y * 8 + 8 {
write!(output, "0x").unwrap();
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 = image.colour(x * tile_size + i, y * tile_size + j);
let colour_index = palette.colour_index(colour); palette.colour_index(colour)
})
})
})
})
})
})
.flatten()
.flatten()
.flatten()
.flatten()
.flatten();
write!(output, "{:x}", colour_index).unwrap(); let assignments = &results.assignments;
}
write!(output, ", ").unwrap(); quote! {
} #[allow(non_upper_case_globals)]
} pub const #output_variable_name: #crate_prefix::display::tile_data::TileData = {
} const _: &[u8] = include_bytes!(#image_filename);
writeln!(output).unwrap(); const PALETTE_DATA: &[#crate_prefix::display::palette16::Palette16] = &[
#(#palette_data),*
];
const TILE_DATA: &[u32] = &[
#(#tile_data),*
];
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();
} }