Skip to main content

concinnity_asset/
font.rs

1// Font glyph-atlas schema.
2
3use crate::{AssetId, PayloadLocator};
4use alloc::string::String;
5
6/// Rasterises a TrueType font into a glyph atlas at build time.
7///
8/// Reference a Font by name from a [TextLabel](#textlabel). Declaring one is
9/// optional: text naming no Font draws with the engine's built-in face at 24px,
10/// and compiles no atlas at all. Declare a Font to pick the face, or to pick the
11/// size the glyphs are rasterised at.
12///
13/// An empty `path` rasterises that same built-in face, which is how to get it at
14/// a different `size_px`.
15///
16/// ```rust
17/// # use concinnity_asset::Font;
18/// Font {
19///     path: "assets/fonts/JetBrainsMono-Regular.ttf".into(),
20///     size_px: 20,
21///     ..Default::default()
22/// };
23/// ```
24#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
25#[serde(default)]
26pub struct Font {
27    /// Asset identity; injected via `inject_name`. Not part of `args`.
28    #[serde(skip)]
29    pub asset_id: AssetId,
30    /// Path to the TTF file, relative to the project root.
31    pub path: String,
32    /// Rasterisation size in pixels. Determines the rendered glyph height.
33    pub size_px: u32,
34    /// Filled by inject_locator after the build step packs the payload.
35    #[serde(skip)]
36    pub locator: Option<PayloadLocator>,
37}
38
39impl Default for Font {
40    fn default() -> Self {
41        Self {
42            asset_id: AssetId::default(),
43            path: String::new(),
44            size_px: 20,
45            locator: None,
46        }
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn a_blank_font_rasterises_at_a_readable_body_size() {
56        let f = Font::default();
57        assert!(f.path.is_empty());
58        assert_eq!(f.size_px, 20);
59        assert_eq!(f.asset_id, AssetId::default());
60        assert!(f.locator.is_none());
61    }
62
63    #[test]
64    fn an_authored_atlas_size_parses_and_round_trips_through_postcard() {
65        let f: Font = serde_json::from_str(r#"{"path":"fonts/body.ttf","size_px":48}"#).unwrap();
66        assert_eq!(f.path, "fonts/body.ttf");
67        assert_eq!(f.size_px, 48);
68
69        let bytes = postcard::to_allocvec(&f).unwrap();
70        let back: Font = postcard::from_bytes(&bytes).unwrap();
71        assert_eq!(back.path, "fonts/body.ttf");
72        assert_eq!(back.size_px, 48);
73        // The glyph atlas rides the blob, so the locator is injected at load.
74        assert!(back.locator.is_none());
75    }
76}