1use std::{collections::BTreeMap, convert::TryFrom};
2
3use image::{GenericImage, GenericImageView, GrayImage, ImageBuffer, Luma};
4use lyon::tessellation::{FillVertex, FillVertexConstructor};
5use prost::{DecodeError, Message};
6
7use crate::render::shaders::ShaderSymbolVertex;
8
9pub mod sdf_glyphs {
10 include!(concat!(env!("OUT_DIR"), "/glyphs.rs"));
11}
12
13pub type UnicodePoint = char;
14
15#[derive(Debug)]
16pub struct Glyph {
17 pub codepoint: UnicodePoint,
18 pub width: u32,
19 pub height: u32,
20 pub left_bearing: i32,
21 pub top_bearing: i32,
22 pub h_advance: u32,
23
24 pub tex_origin_x: u32,
26 pub tex_origin_y: u32,
28}
29
30impl Glyph {
31 fn from_pbf(g: sdf_glyphs::Glyph, origin_x: u32, origin_y: u32) -> Self {
32 Self {
33 codepoint: char::try_from(g.id).unwrap(),
34 width: g.width,
35 height: g.height,
36 left_bearing: g.left,
37 top_bearing: g.top,
38 h_advance: g.advance,
39 tex_origin_x: origin_x,
40 tex_origin_y: origin_y,
41 }
42 }
43
44 pub fn buffered_dimensions(&self) -> (u32, u32) {
45 (self.width + 3 * 2, self.height + 3 * 2)
46 }
47 pub fn origin_offset(&self) -> (u32, u32) {
48 (self.tex_origin_x, self.tex_origin_y)
49 }
50 pub fn advance(&self) -> u32 {
51 self.h_advance
52 }
53}
54
55pub struct GlyphSet {
56 texture_bytes: Vec<u8>,
57 texture_dimensions: (usize, usize),
58 pub glyphs: BTreeMap<UnicodePoint, Glyph>,
59}
60
61impl TryFrom<&[u8]> for GlyphSet {
62 type Error = DecodeError;
63
64 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
65 Ok(GlyphSet::from(sdf_glyphs::Glyphs::decode(value)?))
66 }
67}
68
69impl From<sdf_glyphs::Glyphs> for GlyphSet {
70 fn from(pbf_glyphs: sdf_glyphs::Glyphs) -> Self {
71 let stacks = pbf_glyphs.stacks;
72 let mut texture: GrayImage = ImageBuffer::new(4096, 4096);
73 let mut last_position = (0, 0);
74 let mut max_height = 0;
75
76 let glyphs = stacks
77 .into_iter()
78 .flat_map(|stack| {
79 stack
80 .glyphs
81 .into_iter()
82 .filter_map(|mut glyph| {
83 let bitmap = glyph.bitmap.take()?;
85
86 let glyph = Glyph::from_pbf(glyph, last_position.0, last_position.1);
87
88 let buffered_width = glyph.width + 3 * 2;
89 let buffered_height = glyph.height + 3 * 2;
90
91 let glyph_texture = ImageBuffer::<Luma<u8>, _>::from_vec(
92 buffered_width,
93 buffered_height,
94 bitmap,
95 )?;
96 assert_eq!(buffered_height, glyph_texture.height());
97 assert_eq!(buffered_width, glyph_texture.width());
98
99 texture
101 .copy_from(&glyph_texture, last_position.0, last_position.1)
102 .expect("Unable to copy glyph texture.");
103
104 last_position.0 += glyph_texture.width();
105 max_height = max_height.max(glyph_texture.height());
106
107 Some((glyph.codepoint, glyph))
108 })
109 .collect::<Vec<_>>()
110 })
111 .collect();
112
113 Self {
114 texture_bytes: texture
115 .view(0, 0, last_position.0, max_height)
116 .pixels()
117 .map(|(_x, _y, p)| p[0])
118 .collect(),
119 texture_dimensions: (last_position.0 as _, max_height as _),
120 glyphs,
121 }
122 }
123}
124
125impl GlyphSet {
126 pub fn get_texture_dimensions(&self) -> (usize, usize) {
127 self.texture_dimensions
128 }
129
130 pub fn get_texture_bytes(&self) -> &[u8] {
131 self.texture_bytes.as_slice()
132 }
133}
134
135pub struct SymbolVertexBuilder {
136 pub glyph_anchor: [f32; 3],
138 pub text_anchor: [f32; 3],
140 pub texture_dimensions: (f32, f32),
142 pub sprite_dimensions: (f32, f32),
144 pub sprite_offset: (f32, f32),
146 pub glyph: bool,
147 pub color: [u8; 4],
148}
149
150impl FillVertexConstructor<ShaderSymbolVertex> for SymbolVertexBuilder {
151 fn new_vertex(&mut self, vertex: FillVertex) -> ShaderSymbolVertex {
152 let vertex_position = vertex.position();
153
154 let sprite_ratio_x = self.sprite_dimensions.0 / self.texture_dimensions.0;
155 let sprite_ratio_y = self.sprite_dimensions.1 / self.texture_dimensions.1;
156
157 let x_offset = self.sprite_offset.0 / self.texture_dimensions.0;
158 let y_offset = self.sprite_offset.1 / self.texture_dimensions.1;
159
160 let tex_coords = [
161 x_offset
162 + ((vertex_position.x - self.glyph_anchor[0]) / self.sprite_dimensions.0)
163 * sprite_ratio_x,
164 y_offset
165 + ((vertex_position.y - self.glyph_anchor[1]) / self.sprite_dimensions.1)
166 * sprite_ratio_y,
167 ];
168
169 ShaderSymbolVertex {
170 position: [vertex_position.x, vertex_position.y, 0.],
171 text_anchor: self.text_anchor,
172 is_glyph: if self.glyph { 1 } else { 0 },
173 color: self.color,
174 tex_coords,
175 }
176 }
177}
178
179#[derive(Debug, Copy, Clone)]
180pub enum Anchor {
181 Center,
182 Left,
183 Right,
184 Top,
185 Bottom,
186 TopLeft,
187 TopRight,
188 BottomLeft,
189 BottomRight,
190}