diff options
| -rwxr-xr-x | build | 1 | ||||
| -rw-r--r-- | build.rs | 66 | ||||
| -rw-r--r-- | src/font.rs | 76 | ||||
| -rw-r--r-- | src/main.rs | 2 | 
4 files changed, 109 insertions, 36 deletions
| @@ -1,3 +1,4 @@  #!/bin/sh  set -eax  RUSTFLAGS="-Zfmt-debug=none -Zlocation-detail=none" cargo +nightly build -Z build-std=std,panic_abort -Z build-std-features="optimize_for_size" -Z build-std-features=panic_immediate_abort -r +upx --brute target/release/cosin-2025-invite-deck @@ -1,4 +1,4 @@ -use rusttype::{Font, Point, Scale}; +use rusttype::{Font, Point, Rect, Scale};  use std::fs::{self, File};  use std::io::{self, Write}; @@ -8,12 +8,41 @@ use std::io::{self, Write};  struct FontMetadata {    pub charset: &'static str,    pub name: &'static str, +  pub scale: Scale,    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 positioned_glyph = glyph.clone().positioned(Point { x: 0.0, y: 0.0 }); +    let pixel_bounding_box = { +      let bounding_box = positioned_glyph.pixel_bounding_box(); +      if bounding_box.is_none() { +        Rect { +          min: Point { x: 0, y: 0 }, +          max: Point { +            x: glyph.h_metrics().advance_width as i32, +            y: 0, +          }, +        } +      } else { +        bounding_box.unwrap() +      } +    }; +    let bounding_box = { +      let bounding_box = glyph.exact_bounding_box(); +      if bounding_box.is_none() { +        Rect { +          min: Point { x: 0.0, y: 0.0 }, +          max: Point { +            x: pixel_bounding_box.width() as f32, +            y: 0.0, +          }, +        } +      } else { +        bounding_box.unwrap() +      } +    };      let width = bounding_box.width() as u32;      let height = bounding_box.height() as u32; @@ -29,22 +58,27 @@ impl FontMetadata {          a[i] = v;        }      } -    define_item(&mut image, 2 + ((width as usize) * (height as usize)), 0x00); +    define_item( +      &mut image, +      10 + ((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!");      } +    // TODO: do we *really* need i32 values here? wouldn't i16 be sufficient? +    image[2..6].copy_from_slice(&pixel_bounding_box.min.x.to_le_bytes()); +    image[6..10].copy_from_slice(&(pixel_bounding_box.min.y + (scale.y / 2.0) as i32).to_le_bytes()); -    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); -        } -      }); +    positioned_glyph.draw(|gx: u32, gy: u32, v| { +      let bit = (v * 255.0) as u8; +      if gx < width { +        define_item(&mut image, (10 + (gy * width) + gx) as usize, bit); +      } +    });      image    }    pub fn img_to_hex(image: Vec<u8>) -> Vec<u8> { @@ -81,10 +115,8 @@ impl FontMetadata {  }  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); +    let image = font.render_character(font.scale, c);      save_bits_to_file(&font, c as u8, &image)?;    } @@ -164,12 +196,14 @@ use crate::font::BakedFont;      FontMetadata {        name: "Galmuri",        font: { Font::try_from_vec(fs::read("assets/fonts/Galmuri11.ttf")?).unwrap() }, -      charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz2053:", +      charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz2053: ", +      scale: Scale::uniform(64.0),      },      FontMetadata {        name: "CherryBombOne",        font: { Font::try_from_vec(fs::read("assets/fonts/CherryBombOne.ttf")?).unwrap() }, -      charset: "UwUSpace", +      charset: "UwUSpace ", +      scale: Scale::uniform(64.0),      },    ];    for font in fonts { diff --git a/src/font.rs b/src/font.rs index 0baa862..fc5217e 100644 --- a/src/font.rs +++ b/src/font.rs @@ -1,6 +1,12 @@  use std::sync::LazyLock; -use sdl2::{pixels::{Color, PixelFormatEnum}, rect::Rect, render::{Texture, TextureCreator, TextureValueError}, surface::Surface, video::WindowContext}; +use sdl2::{ +  pixels::{Color, PixelFormatEnum}, +  rect::{Point, Rect}, +  render::{Texture, TextureCreator, TextureValueError}, +  surface::Surface, +  video::WindowContext, +};  pub struct RenderableCharacter {    /** The width of the character, indicating where to break into a newline */ @@ -9,6 +15,8 @@ pub struct RenderableCharacter {    pub height: u16,    /** The raw alpha layer of the character */    pub data: &'static [u8], +  /** The offset to draw the character at */ +  pub offset: Point,  }  /**   A trait describing a generated font. @@ -19,11 +27,19 @@ pub trait BakedFont {    fn get_char_bytes(&self, character: char) -> &'static [u8];    fn get_char(&self, character: char) -> RenderableCharacter {      let bytes = self.get_char_bytes(character); -    let width = (bytes[0] as u16) | (bytes[1] as u16 >> 8); -    let data = &bytes[2..]; +    let width = u16::from_le_bytes(bytes[0..2].try_into().unwrap()); +    let offset_x = i32::from_le_bytes(bytes[2..6].try_into().unwrap()); +    let offset_y = i32::from_le_bytes(bytes[6..10].try_into().unwrap()); +    let data = &bytes[10..]; +    let height = if data.len() == 0 { +      0 +    } else { +      data.len() as u16 / width +    };      RenderableCharacter {        width, -      height: data.len() as u16 / width, +      height, +      offset: Point::new(offset_x, offset_y),        data,      }    } @@ -32,23 +48,39 @@ impl RenderableCharacter {    /** Alpha value of colour is currently ignored! */    pub fn to_surface(&self, colour: Color) -> Surface<'static> {      let mut surface = Surface::new( -      self.width.into(), -      self.height.into(), +      if self.width == 0 { +        1 +      } else { +        self.width.into() +      }, +      if self.height == 0 { +        1 +      } else { +        self.height.into() +      },        PixelFormatEnum::RGBA32,      )      .unwrap(); -    surface.with_lock_mut(|buffer: &mut [u8]| { -      let mut idx: usize = 0; -      print!("{} ({}x{})", self.data.len() * 4, self.width, self.height); -      for pixel in self.data { -        let index = idx * 4; -        buffer[index] = colour.r; // Red -        buffer[index + 1] = colour.g; // Green -        buffer[index + 2] = colour.b; // Blue -        buffer[index + 3] = *pixel; // Alpha -        idx += 1; -      } -    }); +    if self.width != 0 || self.height != 0 { +      surface.with_lock_mut(|buffer: &mut [u8]| { +        let mut idx: usize = 0; +        for pixel in self.data { +          let index = idx * 4; +          buffer[index] = colour.r; // Red +          buffer[index + 1] = colour.g; // Green +          buffer[index + 2] = colour.b; // Blue +          buffer[index + 3] = *pixel; // Alpha +          idx += 1; +        } +      }); +    } else { +      // Blank +      surface.with_lock_mut(|buffer: &mut [u8]| { +        for index in 0..buffer.len() { +          buffer[index] = 0; +        } +      }) +    }      surface    }    /** Colour Alpha Channel is ignored */ @@ -61,6 +93,12 @@ impl RenderableCharacter {      surface.as_texture(texture_creator)    }    pub fn to_rect(&self, x: i32, y: i32) -> Rect { -    Rect::new(x, y, self.width.into(), self.height.into()) +    println!("{:#?}",self.offset); +    Rect::new( +      x + self.offset.x, +      y + self.offset.y, +      i32::from(self.width).try_into().unwrap(), +      i32::from(self.height).try_into().unwrap(), +    )    }  } diff --git a/src/main.rs b/src/main.rs index 287847d..ebe73d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,7 +27,7 @@ pub fn main() {    // let uwu_font = font::UwUFont::new(&texture_creator);    canvas.clear();    let mut offset: u16 = 0; -  for c in "UwUSpace".chars() { +  for c in "UwU Space".chars() {      let char = FONT_CHERRY_BOMB_ONE.get_char(c);      canvas        .copy( |