rocketsplash_rt/font/
cls_font.rs1use std::collections::BTreeMap;
8use std::path::Path;
9
10use rocketsplash_formats::{FontMeta, RenderMode, StyleFlags};
11
12use crate::font::load_font_from_bytes;
13use crate::{Error, TextBuilder, TextStyle};
14
15#[derive(Clone, Debug)]
16pub struct Font {
17 pub meta: FontMeta,
18 pub line_height: u32,
19 pub mode: RenderMode,
20 pub available_styles: StyleFlags,
21 pub(crate) glyphs: BTreeMap<char, RuntimeGlyphVariants>,
22}
23
24impl Font {
25 pub fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
26 let bytes = std::fs::read(path)?;
27 load_font_from_bytes(&bytes)
28 }
29
30 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
31 load_font_from_bytes(bytes)
32 }
33
34 pub fn render<'a>(&'a self, text: &str) -> TextBuilder<'a> {
35 TextBuilder::new(self, text)
36 }
37
38 pub fn available_chars(&self) -> impl Iterator<Item = char> + '_ {
39 self.glyphs.keys().copied()
40 }
41
42 pub fn has_glyph(&self, ch: char) -> bool {
43 self.glyphs.contains_key(&ch)
44 }
45
46 pub fn has_style(&self, style: TextStyle) -> bool {
47 let bold = style.contains(TextStyle::BOLD);
48 let italic = style.contains(TextStyle::ITALIC);
49 if bold && italic && !self.available_styles.contains(StyleFlags::BOLD_ITALIC) {
50 return false;
51 }
52 if bold && !italic && !self.available_styles.contains(StyleFlags::BOLD) {
53 return false;
54 }
55 if italic && !bold && !self.available_styles.contains(StyleFlags::ITALIC) {
56 return false;
57 }
58 if style.contains(TextStyle::REVERSE)
59 && !self.available_styles.contains(StyleFlags::REVERSE)
60 {
61 return false;
62 }
63 true
64 }
65
66 pub fn mode(&self) -> RenderMode {
67 self.mode
68 }
69
70 pub fn line_height(&self) -> usize {
71 self.line_height as usize
72 }
73}
74
75#[derive(Clone, Debug)]
76pub(crate) struct RuntimeGlyph {
77 pub width: usize,
78 pub height: usize,
79 pub chars: Vec<char>,
80 pub opacity: Option<Vec<u8>>,
81}
82
83impl RuntimeGlyph {
84 pub fn char_at(&self, x: usize, y: usize) -> Option<char> {
85 if x >= self.width || y >= self.height {
86 return None;
87 }
88 let idx = y * self.width + x;
89 self.chars.get(idx).copied()
90 }
91}
92
93#[derive(Clone, Debug)]
94pub(crate) struct RuntimeGlyphVariants {
95 pub base: RuntimeGlyph,
96 pub bold: Option<RuntimeGlyph>,
97 pub italic: Option<RuntimeGlyph>,
98 pub bold_italic: Option<RuntimeGlyph>,
99 pub reverse: Option<RuntimeGlyph>,
100}
101
102impl RuntimeGlyphVariants {
103 pub fn select(&self, style: TextStyle) -> &RuntimeGlyph {
104 if style.contains(TextStyle::REVERSE) {
105 if let Some(glyph) = &self.reverse {
106 return glyph;
107 }
108 }
109 let bold = style.contains(TextStyle::BOLD);
110 let italic = style.contains(TextStyle::ITALIC);
111 if bold && italic {
112 if let Some(glyph) = &self.bold_italic {
113 return glyph;
114 }
115 }
116 if bold {
117 if let Some(glyph) = &self.bold {
118 return glyph;
119 }
120 }
121 if italic {
122 if let Some(glyph) = &self.italic {
123 return glyph;
124 }
125 }
126 &self.base
127 }
128}
129
130