use std::sync::OnceLock;
use concinnity_core::bake;
use concinnity_core::ecs::{FontHandle, World};
const FONT_BYTES: &[u8] = include_bytes!("../../assets/fonts/JetBrainsMono-Regular.ttf");
const FONT_FILE: &str = "JetBrainsMono-Regular.ttf";
const BAKE_PX: u32 = 20;
pub(crate) const TEXT_PX: f32 = 14.0;
pub(crate) const LINE_H: f32 = 19.0;
pub(crate) const SCALE: f32 = TEXT_PX / BAKE_PX as f32;
struct Baked {
payload: Vec<u8>,
advance_per_px: f32,
}
fn baked() -> Result<&'static Baked, &'static str> {
static BAKED: OnceLock<Result<Baked, String>> = OnceLock::new();
BAKED
.get_or_init(bake_face)
.as_ref()
.map_err(String::as_str)
}
fn bake_face() -> Result<Baked, String> {
let payload = bake::font::compile(FONT_BYTES, BAKE_PX, FONT_FILE)?;
let (_, _, _, size_px, _, metrics) = bake::font::deserialize(&payload)?;
let space = metrics
.iter()
.find(|m| m.char_code == u32::from(b' '))
.ok_or("the monospace face has no space glyph")?;
Ok(Baked {
advance_per_px: space.advance_px / size_px as f32,
payload,
})
}
pub(crate) fn advance() -> f32 {
match baked() {
Ok(b) => b.advance_per_px * TEXT_PX,
Err(_) => 0.6 * TEXT_PX,
}
}
pub(crate) fn inject(world: &mut World) -> Option<FontHandle> {
match baked() {
Ok(b) => Some(concinnity_core::resource::append_font(
&mut world.context(),
b.payload.clone(),
)),
Err(e) => {
tracing::error!("the editor's code font failed to bake: {e}");
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_face_bakes_with_a_monospace_advance() {
let b = baked().expect("the bundled face bakes");
let (_, _, _, size_px, _, metrics) = bake::font::deserialize(&b.payload).unwrap();
let glyph_advance = |c: char| {
metrics
.iter()
.find(|m| m.char_code == c as u32)
.map(|m| m.advance_px)
.unwrap()
};
assert_eq!(
glyph_advance('i'),
glyph_advance('W'),
"every glyph shares one advance"
);
assert_eq!(glyph_advance('.'), glyph_advance('m'));
assert!((glyph_advance(' ') / size_px as f32 - b.advance_per_px).abs() < 1e-6);
assert!(advance() > 0.4 * TEXT_PX && advance() < 0.8 * TEXT_PX);
}
#[test]
fn inject_appends_a_face_to_the_world() {
let mut world = World::new();
let first = inject(&mut world).expect("a handle");
let second = inject(&mut world).expect("a handle");
assert_ne!(first, second, "each call appends");
}
}