rocketsplash_formats/
font_atlas.rs1use std::collections::BTreeMap;
8
9use serde::{Deserialize, Serialize};
10
11use crate::{validate_dimensions, RenderMode, StyleFlags};
12
13pub const FONT_ATLAS_VERSION: u8 = 1;
15pub const FONT_ATLAS_MIN_SUPPORTED: u8 = 1;
16
17#[derive(Clone, Debug, Serialize, Deserialize)]
19pub struct FontAtlas {
20 pub version: u8,
21 pub meta: FontMeta,
22 pub glyphs: BTreeMap<char, GlyphVariants>,
23 pub line_height: u32,
24 pub mode: RenderMode,
25 pub available_styles: StyleFlags,
26}
27
28#[derive(Clone, Debug, Serialize, Deserialize)]
29pub struct FontMeta {
30 pub font_name: String,
31 pub font_size: f32,
32 pub created_at: u64,
33 pub editor_version: String,
34}
35
36#[derive(Clone, Debug, Serialize, Deserialize)]
38pub struct GlyphVariants {
39 pub base: GlyphData,
40 pub bold: Option<GlyphData>,
41 pub italic: Option<GlyphData>,
42 pub bold_italic: Option<GlyphData>,
43 pub reverse: Option<GlyphData>,
44}
45
46impl GlyphVariants {
47 pub fn validate(&self) -> Result<(), String> {
49 self.base.validate()?;
50 if let Some(glyph) = &self.bold {
51 glyph.validate()?;
52 }
53 if let Some(glyph) = &self.italic {
54 glyph.validate()?;
55 }
56 if let Some(glyph) = &self.bold_italic {
57 glyph.validate()?;
58 }
59 if let Some(glyph) = &self.reverse {
60 glyph.validate()?;
61 }
62 Ok(())
63 }
64
65 pub fn select(&self, bold: bool, italic: bool, reverse: bool) -> &GlyphData {
67 if reverse {
68 if let Some(glyph) = &self.reverse {
69 return glyph;
70 }
71 }
72 if bold && italic {
73 if let Some(glyph) = &self.bold_italic {
74 return glyph;
75 }
76 }
77 if bold {
78 if let Some(glyph) = &self.bold {
79 return glyph;
80 }
81 }
82 if italic {
83 if let Some(glyph) = &self.italic {
84 return glyph;
85 }
86 }
87 &self.base
88 }
89}
90
91#[derive(Clone, Debug, Serialize, Deserialize)]
93pub struct GlyphData {
94 pub chars: String,
95 pub width: u32,
96 pub height: u32,
97 pub opacity: Option<Vec<u8>>,
98}
99
100impl GlyphData {
101 pub fn validate(&self) -> Result<(), String> {
102 let cells = validate_dimensions(self.width, self.height)?;
103 let char_count = self.chars.chars().count();
104 if char_count != cells {
105 return Err(format!(
106 "Glyph char count {} does not match {}x{}",
107 char_count, self.width, self.height
108 ));
109 }
110 if let Some(opacity) = &self.opacity {
111 if opacity.len() != cells {
112 return Err(format!(
113 "Glyph opacity length {} does not match {}x{}",
114 opacity.len(),
115 self.width,
116 self.height
117 ));
118 }
119 }
120 Ok(())
121 }
122}
123
124