2021-07-22 07:46:22 +10:00
|
|
|
use proc_macro::TokenStream;
|
2021-07-23 03:43:27 +10:00
|
|
|
use syn::parse_macro_input;
|
2021-04-20 08:01:28 +10:00
|
|
|
|
2021-07-22 07:46:22 +10:00
|
|
|
use std::path::Path;
|
2021-06-06 02:45:21 +10:00
|
|
|
|
2021-07-23 04:03:49 +10:00
|
|
|
use quote::{quote, format_ident};
|
|
|
|
|
2021-04-20 08:15:03 +10:00
|
|
|
mod colour;
|
2021-07-22 07:46:22 +10:00
|
|
|
mod config;
|
2021-04-20 09:40:07 +10:00
|
|
|
mod image_loader;
|
|
|
|
mod palette16;
|
2021-04-21 05:41:04 +10:00
|
|
|
mod rust_generator;
|
2021-04-20 09:40:07 +10:00
|
|
|
|
|
|
|
use image_loader::Image;
|
2021-04-20 08:15:03 +10:00
|
|
|
|
2021-07-22 07:07:09 +10:00
|
|
|
use colour::Colour;
|
2021-04-20 08:01:28 +10:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
2021-07-22 07:07:09 +10:00
|
|
|
pub(crate) enum TileSize {
|
2021-04-20 08:01:28 +10:00
|
|
|
Tile8,
|
|
|
|
Tile16,
|
|
|
|
}
|
|
|
|
|
2021-04-20 09:40:07 +10:00
|
|
|
impl TileSize {
|
2021-04-21 07:56:47 +10:00
|
|
|
fn to_size(self) -> usize {
|
|
|
|
match self {
|
2021-04-20 09:40:07 +10:00
|
|
|
TileSize::Tile8 => 8,
|
|
|
|
TileSize::Tile16 => 16,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 07:07:09 +10:00
|
|
|
#[proc_macro]
|
|
|
|
pub fn include_gfx(input: TokenStream) -> TokenStream {
|
2021-07-23 03:43:27 +10:00
|
|
|
let input = parse_macro_input!(input as syn::LitStr);
|
2021-06-06 02:47:13 +10:00
|
|
|
|
2021-07-23 03:43:27 +10:00
|
|
|
let filename = input.value();
|
2021-07-22 07:07:09 +10:00
|
|
|
|
|
|
|
let root = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get cargo manifest dir");
|
|
|
|
let path = Path::new(&root).join(&*filename);
|
2021-07-22 07:46:22 +10:00
|
|
|
let parent = path
|
|
|
|
.parent()
|
|
|
|
.expect("Expected a parent directory for the path");
|
2021-07-22 07:07:09 +10:00
|
|
|
|
|
|
|
let config = config::parse(&path.to_string_lossy());
|
|
|
|
|
2021-07-23 04:03:49 +10:00
|
|
|
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()).parse::<proc_macro2::TokenStream>().unwrap());
|
2021-07-22 07:07:09 +10:00
|
|
|
|
2021-07-23 04:03:49 +10:00
|
|
|
let module = quote! {
|
|
|
|
pub mod #module_name {
|
|
|
|
const _: &[u8] = include_bytes!(#include_path);
|
|
|
|
|
|
|
|
#(#image_code)*
|
|
|
|
}
|
|
|
|
};
|
2021-07-22 07:07:09 +10:00
|
|
|
|
2021-07-23 04:03:49 +10:00
|
|
|
TokenStream::from(module)
|
2021-04-20 09:40:07 +10:00
|
|
|
}
|
|
|
|
|
2021-07-22 07:46:22 +10:00
|
|
|
fn convert_image(
|
|
|
|
settings: &dyn config::Image,
|
|
|
|
parent: &Path,
|
|
|
|
variable_name: &str,
|
|
|
|
crate_prefix: &str,
|
|
|
|
) -> String {
|
2021-07-22 07:07:09 +10:00
|
|
|
let image_filename = &parent.join(&settings.filename());
|
|
|
|
let image = Image::load_from_file(image_filename);
|
2021-04-20 09:40:07 +10:00
|
|
|
|
2021-07-22 07:07:09 +10:00
|
|
|
let tile_size = settings.tilesize().to_size();
|
2021-04-20 09:40:07 +10:00
|
|
|
if image.width % tile_size != 0 || image.height % tile_size != 0 {
|
|
|
|
panic!("Image size not a multiple of tile size");
|
|
|
|
}
|
|
|
|
|
|
|
|
let optimiser = optimiser_for_image(&image, tile_size);
|
2021-07-22 07:07:09 +10:00
|
|
|
let optimisation_results = optimiser.optimise_palettes(settings.transparent_colour());
|
2021-04-20 09:40:07 +10:00
|
|
|
|
2021-07-22 07:07:09 +10:00
|
|
|
let mut writer = String::new();
|
2021-04-21 05:41:04 +10:00
|
|
|
|
|
|
|
rust_generator::generate_code(
|
|
|
|
&mut writer,
|
2021-07-22 07:07:09 +10:00
|
|
|
variable_name,
|
2021-04-21 05:41:04 +10:00
|
|
|
&optimisation_results,
|
|
|
|
&image,
|
2021-07-22 07:07:09 +10:00
|
|
|
&image_filename.to_string_lossy(),
|
|
|
|
settings.tilesize(),
|
|
|
|
crate_prefix.to_owned(),
|
|
|
|
);
|
|
|
|
|
|
|
|
writer
|
2021-04-20 08:01:28 +10:00
|
|
|
}
|
|
|
|
|
2021-04-20 09:40:07 +10:00
|
|
|
fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16Optimiser {
|
|
|
|
let tiles_x = image.width / tile_size;
|
|
|
|
let tiles_y = image.height / tile_size;
|
|
|
|
|
|
|
|
let mut palette_optimiser = palette16::Palette16Optimiser::new();
|
|
|
|
|
|
|
|
for y in 0..tiles_y {
|
|
|
|
for x in 0..tiles_x {
|
|
|
|
let mut palette = palette16::Palette16::new();
|
|
|
|
|
|
|
|
for j in 0..tile_size {
|
|
|
|
for i in 0..tile_size {
|
|
|
|
let colour = image.colour(x * tile_size + i, y * tile_size + j);
|
|
|
|
|
2021-04-20 09:57:47 +10:00
|
|
|
palette.add_colour(colour);
|
2021-04-20 09:40:07 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
palette_optimiser.add_palette(palette);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
palette_optimiser
|
|
|
|
}
|