mirror of
https://github.com/italicsjenga/agb.git
synced 2025-02-02 12:36:35 +11:00
Theory a font renderer
This commit is contained in:
parent
c3a64690cd
commit
c5cebb9520
3 changed files with 92 additions and 0 deletions
|
@ -17,3 +17,4 @@ syn = "1"
|
|||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
asefile = "0.3.4"
|
||||
fontdue = "0.7"
|
||||
|
|
36
agb-image-converter/src/font_loader.rs
Normal file
36
agb-image-converter/src/font_loader.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use crate::ByteString;
|
||||
use quote::quote;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
struct LetterData {
|
||||
width: usize,
|
||||
rendered: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn load_font(font_data: &[u8], pixels_per_em: f32) -> TokenStream {
|
||||
let font = fontdue::Font::from_bytes(font_data, Default::default()).expect("Invalid font data");
|
||||
|
||||
let font = (0..128)
|
||||
.map(|i| font.rasterize(char::from_u32(i).unwrap(), pixels_per_em))
|
||||
.map(|(metrics, bitmap)| {
|
||||
let width = metrics.width;
|
||||
LetterData {
|
||||
width,
|
||||
rendered: bitmap,
|
||||
}
|
||||
})
|
||||
.map(|letter_data| {
|
||||
let data_raw = ByteString(&letter_data.rendered);
|
||||
let width = letter_data.width as u8;
|
||||
|
||||
quote!(agb::display::FontLetter {
|
||||
width: #width,
|
||||
data: #data_raw,
|
||||
})
|
||||
});
|
||||
|
||||
quote![
|
||||
#(#font),*
|
||||
]
|
||||
}
|
|
@ -3,7 +3,9 @@ use proc_macro::TokenStream;
|
|||
use proc_macro2::Literal;
|
||||
use syn::parse::Parser;
|
||||
use syn::{parse_macro_input, punctuated::Punctuated, LitStr};
|
||||
use syn::{Expr, ExprLit, Lit};
|
||||
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use std::{iter, path::Path, str};
|
||||
|
||||
|
@ -12,6 +14,7 @@ use quote::{format_ident, quote, ToTokens};
|
|||
mod aseprite;
|
||||
mod colour;
|
||||
mod config;
|
||||
mod font_loader;
|
||||
mod image_loader;
|
||||
mod palette16;
|
||||
mod rust_generator;
|
||||
|
@ -309,6 +312,58 @@ fn palete_tile_data(
|
|||
(palette_data, tile_data, assignments)
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn include_font(input: TokenStream) -> TokenStream {
|
||||
let parser = Punctuated::<Expr, syn::Token![,]>::parse_separated_nonempty;
|
||||
let parsed = match parser.parse(input) {
|
||||
Ok(e) => e,
|
||||
Err(e) => return e.to_compile_error().into(),
|
||||
};
|
||||
|
||||
let all_args: Vec<_> = parsed.into_iter().collect();
|
||||
if all_args.len() != 2 {
|
||||
panic!("Include_font requires 2 arguments, got {}", all_args.len());
|
||||
}
|
||||
|
||||
let filename = match &all_args[0] {
|
||||
Expr::Lit(ExprLit {
|
||||
lit: Lit::Str(str_lit),
|
||||
..
|
||||
}) => str_lit.value(),
|
||||
_ => panic!("Expected literal string as first argument to include_font"),
|
||||
};
|
||||
|
||||
let font_size = match &all_args[1] {
|
||||
Expr::Lit(ExprLit {
|
||||
lit: Lit::Float(value),
|
||||
..
|
||||
}) => value.base10_parse::<f32>().expect("Invalid float literal"),
|
||||
Expr::Lit(ExprLit {
|
||||
lit: Lit::Int(value),
|
||||
..
|
||||
}) => value
|
||||
.base10_parse::<i32>()
|
||||
.expect("Invalid integer literal") as f32,
|
||||
_ => panic!("Expected literal float or integer as second argument to include_font"),
|
||||
};
|
||||
|
||||
let root = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get cargo manifest dir");
|
||||
let path = Path::new(&root).join(&*filename);
|
||||
|
||||
let file_content = std::fs::read(&path).expect("Failed to read ttf file");
|
||||
|
||||
let rendered = font_loader::load_font(&file_content, font_size);
|
||||
|
||||
let include_path = path.to_string_lossy();
|
||||
|
||||
quote!({
|
||||
let _ = include_bytes!(#include_path);
|
||||
|
||||
#rendered
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use asefile::AnimationDirection;
|
||||
|
|
Loading…
Add table
Reference in a new issue