use glyphon::{
Attrs, Buffer, Color as GlyphonColor, Family, FontSystem, Metrics, Shaping, SwashCache,
TextArea, TextAtlas, TextBounds, TextRenderer, Viewport, Weight,
};
pub struct GlyphPipeline {
pub font_system: FontSystem,
pub swash_cache: SwashCache,
pub atlas: TextAtlas,
pub text_renderer: TextRenderer,
pub viewport: Viewport,
pub text_buffers: Vec<(Buffer, f32, f32, GlyphonColor)>,
}
impl GlyphPipeline {
pub fn new(
device: &wgpu::Device,
queue: &wgpu::Queue,
format: wgpu::TextureFormat,
) -> Self {
let font_system = FontSystem::new();
let swash_cache = SwashCache::new();
let cache = glyphon::Cache::new(device);
let mut atlas = TextAtlas::new(device, queue, &cache, format);
let text_renderer =
TextRenderer::new(&mut atlas, device, wgpu::MultisampleState::default(), None);
let viewport = Viewport::new(device, &cache);
Self {
font_system,
swash_cache,
atlas,
text_renderer,
viewport,
text_buffers: Vec::new(),
}
}
pub fn push_text(
&mut self,
text: &str,
x: f32,
y: f32,
color: [f32; 4],
font_size: f32,
bold: bool,
_italic: bool,
_monospace: bool,
) {
let metrics = Metrics::new(font_size, font_size * 1.2);
let mut buffer = Buffer::new(&mut self.font_system, metrics);
let weight = if bold { Weight::BOLD } else { Weight::NORMAL };
let attrs = Attrs::new().family(Family::Monospace).weight(weight);
buffer.set_text(&mut self.font_system, text, &attrs, Shaping::Advanced);
buffer.shape_until_scroll(&mut self.font_system, false);
let glyphon_color = GlyphonColor::rgba(
(color[0] * 255.0) as u8,
(color[1] * 255.0) as u8,
(color[2] * 255.0) as u8,
(color[3] * 255.0) as u8,
);
self.text_buffers.push((buffer, x, y, glyphon_color));
}
pub fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
width: u32,
height: u32,
) {
self.viewport.update(
queue,
glyphon::Resolution { width, height },
);
let text_areas: Vec<TextArea> = self
.text_buffers
.iter()
.map(|(buffer, x, y, color)| TextArea {
buffer,
left: *x,
top: *y,
scale: 1.0,
bounds: TextBounds {
left: 0,
top: 0,
right: width as i32,
bottom: height as i32,
},
default_color: *color,
custom_glyphs: &[],
})
.collect();
self.text_renderer
.prepare(
device,
queue,
&mut self.font_system,
&mut self.atlas,
&self.viewport,
text_areas,
&mut self.swash_cache,
)
.expect("text prepare failed");
}
pub fn render<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>) {
self.text_renderer
.render(&self.atlas, &self.viewport, pass)
.expect("text render failed");
}
pub fn clear(&mut self) {
self.text_buffers.clear();
}
pub fn trim(&mut self) {
self.atlas.trim();
}
}