diff options
author | 2023-01-31 06:29:21 +0100 | |
---|---|---|
committer | 2023-02-24 13:19:48 +0100 | |
commit | baf51a8fcffc78e4ca20f7dcbba18ca3655f2840 (patch) | |
tree | fd7ba1920ac0ff57b6ddefd692d8cad5d57274cd /wgpu/src/text.rs | |
parent | b9a9576207ddfc7afd89da30b7cfc7ca0d7e335c (diff) | |
download | iced-baf51a8fcffc78e4ca20f7dcbba18ca3655f2840.tar.gz iced-baf51a8fcffc78e4ca20f7dcbba18ca3655f2840.tar.bz2 iced-baf51a8fcffc78e4ca20f7dcbba18ca3655f2840.zip |
Draft `glyphon` implementation of text pipeline for `iced_wgpu`
Diffstat (limited to 'wgpu/src/text.rs')
-rw-r--r-- | wgpu/src/text.rs | 160 |
1 files changed, 150 insertions, 10 deletions
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 125e6be0..ccb627cd 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -1,26 +1,166 @@ pub use iced_native::text::Hit; -#[derive(Debug)] -pub struct Pipeline; +use iced_graphics::layer::Text; +use iced_native::{Font, Size}; + +#[allow(missing_debug_implementations)] +pub struct Pipeline { + renderer: glyphon::TextRenderer, + atlas: glyphon::TextAtlas, + cache: glyphon::SwashCache<'static>, +} + +// TODO: Share with `iced_graphics` +static FONT_SYSTEM: once_cell::sync::Lazy<glyphon::FontSystem> = + once_cell::sync::Lazy::new(glyphon::FontSystem::new); impl Pipeline { pub fn new( - _device: &wgpu::Device, - _format: wgpu::TextureFormat, + device: &wgpu::Device, + queue: &wgpu::Queue, + format: wgpu::TextureFormat, _default_font: Option<&[u8]>, _multithreading: bool, ) -> Self { - Pipeline + Pipeline { + renderer: glyphon::TextRenderer::new(device, queue), + atlas: glyphon::TextAtlas::new(device, queue, format), + cache: glyphon::SwashCache::new(&FONT_SYSTEM), + } + } + + pub fn prepare( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + sections: &[Text<'_>], + scale_factor: f32, + target_size: Size<u32>, + ) { + let buffers: Vec<_> = sections + .iter() + .map(|section| { + let metrics = glyphon::Metrics::new( + (section.size * scale_factor) as i32, + (section.size * 1.2 * scale_factor) as i32, + ); + + let mut buffer = glyphon::Buffer::new(&FONT_SYSTEM, metrics); + + buffer.set_size( + (section.bounds.width * scale_factor).ceil() as i32, + (section.bounds.height * scale_factor).ceil() as i32, + ); + + buffer.set_text( + section.content, + glyphon::Attrs::new() + .color({ + let [r, g, b, a] = section.color.into_rgba8(); + glyphon::Color::rgba(r, g, b, a) + }) + .family(match section.font { + Font::Default => glyphon::Family::SansSerif, + Font::External { name, .. } => { + glyphon::Family::Name(name) + } + }), + ); + + buffer.shape_until_scroll(); + + buffer + }) + .collect(); + + let text_areas: Vec<_> = sections + .iter() + .zip(buffers.iter()) + .map(|(section, buffer)| glyphon::TextArea { + buffer, + left: (section.bounds.x * scale_factor) as i32, + top: (section.bounds.y * scale_factor) as i32, + bounds: glyphon::TextBounds { + left: (section.bounds.x * scale_factor) as i32, + top: (section.bounds.y * scale_factor) as i32, + right: ((section.bounds.x + section.bounds.width) + * scale_factor) as i32, + bottom: ((section.bounds.y + section.bounds.height) + * scale_factor) as i32, + }, + }) + .collect(); + + self.renderer + .prepare( + device, + queue, + &mut self.atlas, + glyphon::Resolution { + width: target_size.width, + height: target_size.height, + }, + &text_areas, + glyphon::Color::rgb(0, 0, 0), + &mut self.cache, + ) + .expect("Prepare text sections"); + } + + pub fn render( + &mut self, + encoder: &mut wgpu::CommandEncoder, + target: &wgpu::TextureView, + ) { + let mut render_pass = + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: target, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, + }, + })], + depth_stencil_attachment: None, + }); + + self.renderer + .render(&self.atlas, &mut render_pass) + .expect("Render text"); } pub fn measure( &self, - _content: &str, - _size: f32, - _font: iced_native::Font, - _bounds: iced_native::Size, + content: &str, + size: f32, + font: Font, + bounds: Size, ) -> (f32, f32) { - (0.0, 0.0) + let attrs = match font { + Font::Default => glyphon::Attrs::new(), + Font::External { name, .. } => glyphon::Attrs { + family: glyphon::Family::Name(name), + ..glyphon::Attrs::new() + }, + }; + + let mut paragraph = + glyphon::BufferLine::new(content, glyphon::AttrsList::new(attrs)); + + // TODO: Cache layout + let layout = paragraph.layout( + &FONT_SYSTEM, + size as i32, + bounds.width as i32, + glyphon::Wrap::Word, + ); + + ( + layout.iter().fold(0.0, |max, line| line.w.max(max)), + size * 1.2 * layout.len() as f32, + ) } pub fn hit_test( |