aboutsummaryrefslogblamecommitdiffstats
path: root/build.rs
blob: 3a4b452946c2b89c75417080bc499b318b4e8727 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                   

                           
 




                            
 





                                                                            
 
                                        
 







                                                      
       
     
                                                                              
 




                                                                   
 












                                                                         
 













                                                                                              
       







                                       
       
     
     
   

 













                                                                                    

                                          
                                                                             
                                          
                                                            

        

























                                                                                       

                                                     





















                                                                                         

        
use rusttype::{Font, Point, Scale};
use std::fs::{self, File};
use std::io::{self, Write};

#[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<u8> {
    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;

    let mut image: Vec<u8> = Vec::new();

    fn define_item(a: &mut Vec<u8>, i: usize, v: u8) {
      if a.len() <= i {
        while a.len() < i {
          a.push(0x00);
        }
        a.push(v)
      } else {
        a[i] = v;
      }
    }
    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!");
    }

    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<u8>) -> Vec<u8> {
    let mut image2: Vec<u8> = 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 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})
      }
    }
    image2
  }
  fn unique_chars(&self) -> Vec<char> {
    let mut v: Vec<char> = Vec::new();
    for char in self.charset.chars() {
      if !v.contains(&char) {
        v.push(char);
      }
    }
    v
  }
}

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, char);
  let mut file = File::create(&filename)?;
  file.write_all(&FontMetadata::img_to_hex(bits.to_vec()))?;
  Ok(())
}
fn generate_struct(font: &FontMetadata) -> io::Result<String> {
  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<dyn std::error::Error>> {
  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(())
}