From f5152a1e36f7e765f5894370fead0d5602894f8b Mon Sep 17 00:00:00 2001 From: memdmp Date: Sat, 11 Jan 2025 23:23:43 +0100 Subject: feat: code generation :3 --- .gitignore | 2 + Cargo.lock | 269 --------------------------------------------------- Cargo.toml | 1 - build.rs | 213 ++++++++++++++++++++++++---------------- src/font.rs | 3 + src/generated/mod.rs | 1 + src/main.rs | 1 + 7 files changed, 134 insertions(+), 356 deletions(-) create mode 100644 src/generated/mod.rs diff --git a/.gitignore b/.gitignore index f647193..9a61ec6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target /assets/computed-fonts +/src/generated/* +!/src/generated/mod.rs diff --git a/Cargo.lock b/Cargo.lock index e40be8f..28792f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,227 +8,38 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bytemuck" -version = "1.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "cosin-2025-invite-deck" version = "0.1.0" dependencies = [ - "image", "rusttype", "sdl2", ] -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "exr" -version = "1.73.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" -dependencies = [ - "bit_field", - "half", - "lebe", - "miniz_oxide", - "rayon-core", - "smallvec", - "zune-inflate", -] - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "flate2" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "gif" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" -dependencies = [ - "color_quant", - "weezl", -] - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "exr", - "gif", - "jpeg-decoder", - "num-traits", - "png", - "qoi", - "tiff", -] - -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" -dependencies = [ - "rayon", -] - [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - [[package]] name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" -[[package]] -name = "miniz_oxide" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "owned_ttf_parser" version = "0.15.2" @@ -238,48 +49,6 @@ dependencies = [ "ttf-parser", ] -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "rusttype" version = "0.9.3" @@ -313,29 +82,6 @@ dependencies = [ "version-compare", ] -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - [[package]] name = "ttf-parser" version = "0.15.2" @@ -347,18 +93,3 @@ name = "version-compare" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" - -[[package]] -name = "weezl" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] diff --git a/Cargo.toml b/Cargo.toml index 13e1d28..dd60646 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,5 +14,4 @@ codegen-units = 1 panic = "abort" [build-dependencies] -image = "0.24.9" rusttype = "0.9.3" diff --git a/build.rs b/build.rs index a6a53d2..3a4b452 100644 --- a/build.rs +++ b/build.rs @@ -1,112 +1,153 @@ -use image::{GrayImage, Luma}; -use rusttype::{point, Font, Point, Scale}; -use std::env; +use rusttype::{Font, Point, Scale}; use std::fs::{self, File}; use std::io::{self, Write}; -use std::path::Path; -fn exec(font_path: &str, characters: Vec, font_name: &str) -> io::Result<()> { - let font_data = fs::read(font_path)?; - let font = Font::try_from_vec(font_data).expect("Failed to load font"); - - let scale = Scale::uniform(32.0); // Set the font size - - for &c in &characters { - let image = render_character(&font, scale, c); - save_bits_to_file(font_name, c, &image)?; - } - - Ok(()) +#[derive(Clone)] +struct FontMetadata { + pub charset: &'static str, + pub name: &'static str, + pub font: Font<'static>, } +impl FontMetadata { + pub fn render_character(&self, scale: Scale, character: char) -> Vec { + let glyph = self.font.glyph(character).scaled(scale); + let bounding_box = glyph.exact_bounding_box().unwrap(); + let width = bounding_box.width() as u32; + let height = bounding_box.height() as u32; -fn render_character(font: &Font, scale: Scale, character: char) -> Vec { - let glyph = font.glyph(character).scaled(scale); - let bounding_box = glyph.exact_bounding_box().unwrap(); - let width = bounding_box.width() as u32; - let height = bounding_box.height() as u32; + let mut image: Vec = Vec::new(); - let mut image: Vec = Vec::new(); - - fn define_item(a: &mut Vec, i: usize, v: u8) { - if a.len() <= i { - while a.len() < i { - a.push(0x00); + fn define_item(a: &mut Vec, i: usize, v: u8) { + if a.len() <= i { + while a.len() < i { + a.push(0x00); + } + a.push(v) + } else { + a[i] = v; } - a.push(v) - } else { - a[i] = v; } - } - define_item(&mut image, 2 + ((width as usize) * (height as usize)), 0x00); + define_item(&mut image, 2 + ((width as usize) * (height as usize)), 0x00); - image[0] = (width & 0b0000_0000_1111_1111) as u8; - image[1] = (width & 0b1111_1111_0000_0000 << 8) as u8; - if (image[0] as u16) | (image[1] as u16 >> 8) != width as u16 { - panic!("Width missmatch!"); - } + image[0] = (width & 0b0000_0000_1111_1111) as u8; + image[1] = (width & 0b1111_1111_0000_0000 << 8) as u8; + if (image[0] as u16) | (image[1] as u16 >> 8) != width as u16 { + panic!("Width missmatch!"); + } - glyph - .positioned(Point { x: 0.0, y: 0.0 }) - .draw(|gx: u32, gy: u32, v| { - let bit = (v * 255.0) as u8; - if gx < width { - define_item(&mut image, (2 + (gy * width) + gx) as usize, bit); - } - }); - image -} -fn img_to_hex(image: Vec) -> Vec { - let mut image2: Vec = Vec::new(); - let width = (image[0] as u16) | (image[1] as u16 >> 8); + glyph + .positioned(Point { x: 0.0, y: 0.0 }) + .draw(|gx: u32, gy: u32, v| { + let bit = (v * 255.0) as u8; + if gx < width { + define_item(&mut image, (2 + (gy * width) + gx) as usize, bit); + } + }); + image + } + pub fn img_to_hex(image: Vec) -> Vec { + let mut image2: Vec = Vec::new(); + let width = (image[0] as u16) | (image[1] as u16 >> 8); - let mut i: i32 = -3; - for bit in image { - i += 1; - if i >= 0 { - if i as u16 == width { - i = 0; - image2.push('\n' as u8); + let mut i: i32 = -3; + for bit in image { + i += 1; + if i >= 0 { + if i as u16 == width { + i = 0; + image2.push('\n' as u8); + } + let v = format!("{:x?}", bit); + let v = if v.len() == 1 { format!("0{}", v) } else { v }; + for char in v.chars() { + image2.push(char as u8); + } + // image2.push(if bit < 80 {' ' as u8} else if bit < 150 {'-' as u8} else {'#' as u8}) } - let v = format!("{:x?}", bit); - let v = if v.len() == 1 { format!("0{}", v) } else { v }; - for char in v.chars() { - image2.push(char as u8); + } + image2 + } + fn unique_chars(&self) -> Vec { + let mut v: Vec = Vec::new(); + for char in self.charset.chars() { + if !v.contains(&char) { + v.push(char); } - // image2.push(if bit < 80 {' ' as u8} else if bit < 150 {'-' as u8} else {'#' as u8}) } + v } - image2 } -fn save_bits_to_file(font_name: &str, character: char, bits: &[u8]) -> io::Result<()> { - fs::create_dir_all(format!("assets/computed-fonts/{}/", font_name))?; - let filename = format!( - "assets/computed-fonts/{}/{}.bin", - font_name, character as u8 - ); +fn exec(font: FontMetadata) -> io::Result<()> { + let scale = Scale::uniform(32.0); // Set the font size + + for c in font.unique_chars() { + let image = font.render_character(scale, c); + save_bits_to_file(&font, c as u8, &image)?; + } + + Ok(()) +} + +fn save_bits_to_file(font: &FontMetadata, char: u8, bits: &[u8]) -> io::Result<()> { + fs::create_dir_all(format!("assets/computed-fonts/{}/", font.name))?; + let filename = format!("assets/computed-fonts/{}/{}.bin", font.name, char); let mut file = File::create(&filename)?; file.write_all(bits)?; - let filename = format!( - "assets/computed-fonts/{}/{}.txt", - font_name, character as u8 - ); + let filename = format!("assets/computed-fonts/{}/{}.txt", font.name, char); let mut file = File::create(&filename)?; - file.write_all(&img_to_hex(bits.to_vec()))?; + file.write_all(&FontMetadata::img_to_hex(bits.to_vec()))?; Ok(()) } +fn generate_struct(font: &FontMetadata) -> io::Result { + let name = font.name; + let mut contents = format!( + "pub struct {name} {{}} +impl {name} {{}} +impl BakedFont for {name} {{ + fn get_char(c: char) -> &'static [u8] {{ + match c as u8 {{ +" + ); + for char in font.unique_chars() { + contents = format!( + "{contents} {} => include_bytes!(\"../../assets/computed-fonts/{}/{}.bin\"), +", + char as u8, font.name, char as u8 + ); + } + contents = format!( + "{contents} _ => panic!(\"Glyph {{}} not included in precomputed fonts\", c) + }} + }} +}} +" + ); + Ok(contents) +} fn main() -> Result<(), Box> { - exec( - "assets/fonts/Galmuri11.ttf", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz2053:" - .chars() - .collect(), - "Galmuri", - )?; - exec( - "assets/fonts/CherryBombOne.ttf", - "UwUSpace".chars().collect(), - "CherryBombOne", - )?; + fs::create_dir_all("src/generated")?; + let mut modrs = format!("// Copyright is a sham this is a @generated file. +use crate::font::BakedFont; +"); + let fonts = [ + FontMetadata { + name: "Galmuri", + font: { Font::try_from_vec(fs::read("assets/fonts/Galmuri11.ttf")?).unwrap() }, + charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz2053:", + }, + FontMetadata { + name: "CherryBombOne", + font: { Font::try_from_vec(fs::read("assets/fonts/CherryBombOne.ttf")?).unwrap() }, + charset: "UwUSpace", + }, + ]; + for font in fonts { + modrs=format!("{modrs}{} +",generate_struct(&font)?); + exec(font)?; + } + File::create(&"src/generated/fonts.rs")?.write_all(modrs.as_bytes())?; Ok(()) } diff --git a/src/font.rs b/src/font.rs index 738ae30..546fabe 100644 --- a/src/font.rs +++ b/src/font.rs @@ -15,6 +15,9 @@ fn insert_value(arr: &mut Vec<*const Glyph>, idx: usize, glyph: *const Glyph) { arr[idx] = glyph; } +pub trait BakedFont { + fn get_char(character: char) -> &'static [u8]; +} pub struct Font<'a> { pub texture: &'a [u8], pub glyphs: Vec<*const Glyph>, diff --git a/src/generated/mod.rs b/src/generated/mod.rs new file mode 100644 index 0000000..bfbdc1d --- /dev/null +++ b/src/generated/mod.rs @@ -0,0 +1 @@ +pub mod fonts; diff --git a/src/main.rs b/src/main.rs index bfcc5f6..39f39d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ extern crate sdl2; mod font; +pub mod generated; use font::{UwUFont, UWU_WIDTH}; use sdl2::event::Event; -- cgit v1.2.3