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}