New include_gfx macro

This commit is contained in:
Gwilym Inzani 2023-04-13 21:53:13 +01:00
parent 63ca9b3cdb
commit cb127c7924
3 changed files with 144 additions and 8 deletions

View file

@ -2,9 +2,9 @@ use palette16::{Palette16OptimisationResults, Palette16Optimiser};
use palette256::Palette256;
use proc_macro::TokenStream;
use proc_macro2::Literal;
use syn::parse::Parser;
use syn::parse::{Parse, Parser};
use syn::{parse_macro_input, punctuated::Punctuated, LitStr};
use syn::{Expr, ExprLit, Lit};
use syn::{Expr, ExprLit, Lit, Token};
use std::collections::HashMap;
use std::path::PathBuf;
@ -33,6 +33,7 @@ pub(crate) enum TileSize {
Tile32,
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum Colours {
Colours16,
Colours256,
@ -48,6 +49,132 @@ impl TileSize {
}
}
struct BackgroundGfxOption {
module_name: String,
file_name: String,
colours: Colours,
}
impl config::Image for BackgroundGfxOption {
fn filename(&self) -> String {
self.file_name.clone()
}
fn tile_size(&self) -> TileSize {
TileSize::Tile8
}
fn colours(&self) -> Colours {
self.colours
}
}
impl Parse for BackgroundGfxOption {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
let module_name: syn::Ident = input.parse()?;
let _: Token![=>] = input.parse()?;
let colours = if lookahead.peek(syn::LitInt) {
let num_colours: syn::LitInt = input.parse()?;
match num_colours.base10_parse()? {
16 => Colours::Colours16,
256 => Colours::Colours256,
_ => {
return Err(syn::Error::new_spanned(
num_colours,
"Number of colours must be 16 or 256",
))
}
}
} else {
Colours::Colours16
};
let file_name: syn::LitStr = input.parse()?;
Ok(Self {
module_name: module_name.to_string(),
file_name: file_name.value(),
colours,
})
}
}
struct IncludeBackgroundGfxInput {
module_name: syn::Ident,
crate_prefix: String,
transparent_colour: Colour,
background_gfx_options: Vec<BackgroundGfxOption>,
}
impl Parse for IncludeBackgroundGfxInput {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
let crate_prefix: syn::Ident = if lookahead.peek(Token![crate]) {
let _: Token![crate] = input.parse()?;
let _: Token![,] = input.parse()?;
format_ident!("crate")
} else {
format_ident!("agb")
};
let module_name: syn::Ident = input.parse()?;
let _: Token![,] = input.parse()?;
let transparent_colour: Colour = if lookahead.peek(syn::LitStr) {
let colour_str: syn::LitStr = input.parse()?;
let _: Token![,] = input.parse()?;
colour_str
.value()
.parse()
.map_err(|msg| syn::Error::new_spanned(colour_str, msg))?
} else {
Colour::from_rgb(255, 0, 255, 0)
};
let background_gfx_options =
input.parse_terminated(BackgroundGfxOption::parse, Token![,])?;
Ok(Self {
module_name,
crate_prefix: crate_prefix.to_string(),
transparent_colour,
background_gfx_options: background_gfx_options.into_iter().collect(),
})
}
}
impl config::Config for IncludeBackgroundGfxInput {
fn crate_prefix(&self) -> String {
self.crate_prefix.clone()
}
fn images(&self) -> HashMap<String, &dyn config::Image> {
self.background_gfx_options
.iter()
.map(|options| (options.module_name.clone(), options as &dyn config::Image))
.collect()
}
fn transparent_colour(&self) -> Option<Colour> {
Some(self.transparent_colour)
}
}
#[proc_macro]
pub fn include_background_gfx(input: TokenStream) -> TokenStream {
let config = Box::new(parse_macro_input!(input as IncludeBackgroundGfxInput));
let root = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get cargo manifest dir");
let module_name = config.module_name.clone();
include_gfx_from_config(config, module_name, Path::new(&root))
}
#[proc_macro]
pub fn include_gfx(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as syn::LitStr);
@ -56,20 +183,28 @@ pub fn include_gfx(input: TokenStream) -> TokenStream {
let root = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get cargo manifest dir");
let path = Path::new(&root).join(&*filename);
let config = config::parse(&path.to_string_lossy());
let parent = path
.parent()
.expect("Expected a parent directory for the path");
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 include_path = path.to_string_lossy();
include_gfx_from_config(config, module_name, parent)
}
fn include_gfx_from_config(
config: Box<dyn config::Config>,
module_name: syn::Ident,
parent: &Path,
) -> TokenStream {
let images = config.images();
let mut optimiser = Palette16Optimiser::new(config.transparent_colour());
@ -132,8 +267,6 @@ pub fn include_gfx(input: TokenStream) -> TokenStream {
let module = quote! {
mod #module_name {
const _: &[u8] = include_bytes!(#include_path);
#palette_code
#(#image_code)*

View file

@ -1,6 +1,6 @@
use super::tiled::{RegularMap, TileFormat, TileSet, TileSetting, TiledMap, VRamManager};
crate::include_gfx!("gfx/agb_logo.toml");
crate::include_background_gfx!(crate, agb_logo, test_logo => "gfx/test_logo.png");
pub fn display_logo(map: &mut RegularMap, vram: &mut VRamManager) {
vram.set_background_palettes(agb_logo::PALETTES);

View file

@ -13,6 +13,7 @@
#![feature(alloc_error_handler)]
#![feature(allocator_api)]
#![feature(asm_const)]
#![feature(trace_macros)]
#![warn(clippy::all)]
#![deny(clippy::must_use_candidate)]
#![deny(clippy::trivially_copy_pass_by_ref)]
@ -120,6 +121,8 @@ pub use agb_image_converter::include_aseprite_inner;
#[doc(hidden)]
pub use agb_image_converter::include_font as include_font_inner;
pub use agb_image_converter::include_background_gfx;
#[macro_export]
macro_rules! include_font {
($font_path: literal, $font_size: literal) => {{