-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
/
Copy pathpipeline.rs
130 lines (110 loc) · 3.81 KB
/
pipeline.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::hash::Hash;
use ab_glyph::{PxScale, ScaleFont};
use bevy_asset::{Assets, Handle, HandleId};
use bevy_math::Size;
use bevy_render::texture::Image;
use bevy_sprite::TextureAtlas;
use bevy_utils::HashMap;
use glyph_brush_layout::{FontId, SectionText};
use crate::{
error::TextError, glyph_brush::GlyphBrush, scale_value, Font, FontAtlasSet, PositionedGlyph,
TextAlignment, TextSection,
};
pub struct TextPipeline<ID> {
brush: GlyphBrush,
glyph_map: HashMap<ID, TextLayoutInfo>,
map_font_id: HashMap<HandleId, FontId>,
}
impl<ID> Default for TextPipeline<ID> {
fn default() -> Self {
TextPipeline {
brush: GlyphBrush::default(),
glyph_map: Default::default(),
map_font_id: Default::default(),
}
}
}
pub struct TextLayoutInfo {
pub glyphs: Vec<PositionedGlyph>,
pub size: Size,
}
impl<ID: Hash + Eq> TextPipeline<ID> {
pub fn get_or_insert_font_id(&mut self, handle: &Handle<Font>, font: &Font) -> FontId {
let brush = &mut self.brush;
*self
.map_font_id
.entry(handle.id)
.or_insert_with(|| brush.add_font(handle.clone(), font.font.clone()))
}
pub fn get_glyphs(&self, id: &ID) -> Option<&TextLayoutInfo> {
self.glyph_map.get(id)
}
#[allow(clippy::too_many_arguments)]
pub fn queue_text(
&mut self,
id: ID,
fonts: &Assets<Font>,
sections: &[TextSection],
scale_factor: f64,
text_alignment: TextAlignment,
bounds: Size,
font_atlas_set_storage: &mut Assets<FontAtlasSet>,
texture_atlases: &mut Assets<TextureAtlas>,
textures: &mut Assets<Image>,
) -> Result<(), TextError> {
let mut scaled_fonts = Vec::new();
let sections = sections
.iter()
.map(|section| {
let font = fonts
.get(section.style.font.id)
.ok_or(TextError::NoSuchFont)?;
let font_id = self.get_or_insert_font_id(§ion.style.font, font);
let font_size = scale_value(section.style.font_size, scale_factor);
scaled_fonts.push(ab_glyph::Font::as_scaled(&font.font, font_size));
let section = SectionText {
font_id,
scale: PxScale::from(font_size),
text: §ion.value,
};
Ok(section)
})
.collect::<Result<Vec<_>, _>>()?;
let section_glyphs = self
.brush
.compute_glyphs(§ions, bounds, text_alignment)?;
if section_glyphs.is_empty() {
self.glyph_map.insert(
id,
TextLayoutInfo {
glyphs: Vec::new(),
size: Size::new(0., 0.),
},
);
return Ok(());
}
let mut min_x: f32 = std::f32::MAX;
let mut min_y: f32 = std::f32::MAX;
let mut max_x: f32 = std::f32::MIN;
let mut max_y: f32 = std::f32::MIN;
for sg in §ion_glyphs {
let scaled_font = scaled_fonts[sg.section_index];
let glyph = &sg.glyph;
min_x = min_x.min(glyph.position.x);
min_y = min_y.min(glyph.position.y - scaled_font.ascent());
max_x = max_x.max(glyph.position.x + scaled_font.h_advance(glyph.id));
max_y = max_y.max(glyph.position.y - scaled_font.descent());
}
let size = Size::new(max_x - min_x, max_y - min_y);
let glyphs = self.brush.process_glyphs(
section_glyphs,
§ions,
font_atlas_set_storage,
fonts,
texture_atlases,
textures,
)?;
self.glyph_map.insert(id, TextLayoutInfo { glyphs, size });
Ok(())
}
}