Update wgpu_glyph
and glyph_brush
This commit is contained in:
parent
5324eb1024
commit
f5ee6d0e51
@ -13,9 +13,9 @@ canvas = ["lyon"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wgpu = "0.5"
|
wgpu = "0.5"
|
||||||
wgpu_glyph = "0.8"
|
wgpu_glyph = { git = "https://github.com/hecrj/wgpu_glyph.git", branch = "feature/update-glyph-brush" }
|
||||||
zerocopy = "0.3"
|
zerocopy = "0.3"
|
||||||
glyph_brush = "0.6"
|
glyph_brush = "0.7"
|
||||||
raw-window-handle = "0.3"
|
raw-window-handle = "0.3"
|
||||||
glam = "0.8"
|
glam = "0.8"
|
||||||
font-kit = "0.6"
|
font-kit = "0.6"
|
||||||
|
@ -7,7 +7,8 @@ use crate::{
|
|||||||
use crate::image::{self, Image};
|
use crate::image::{self, Image};
|
||||||
|
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
layout, mouse, Background, Color, Layout, Point, Rectangle, Vector, Widget,
|
layout, mouse, Background, Color, Font, HorizontalAlignment, Layout, Point,
|
||||||
|
Rectangle, Size, Vector, VerticalAlignment, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod widget;
|
mod widget;
|
||||||
@ -29,12 +30,23 @@ struct Layer<'a> {
|
|||||||
bounds: Rectangle<u32>,
|
bounds: Rectangle<u32>,
|
||||||
quads: Vec<Quad>,
|
quads: Vec<Quad>,
|
||||||
meshes: Vec<(Vector, Rectangle<u32>, &'a triangle::Mesh2D)>,
|
meshes: Vec<(Vector, Rectangle<u32>, &'a triangle::Mesh2D)>,
|
||||||
text: Vec<wgpu_glyph::Section<'a>>,
|
text: Vec<Text<'a>>,
|
||||||
|
|
||||||
#[cfg(any(feature = "image", feature = "svg"))]
|
#[cfg(any(feature = "image", feature = "svg"))]
|
||||||
images: Vec<Image>,
|
images: Vec<Image>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Text<'a> {
|
||||||
|
pub content: &'a str,
|
||||||
|
pub bounds: Rectangle,
|
||||||
|
pub color: [f32; 4],
|
||||||
|
pub size: f32,
|
||||||
|
pub font: Font,
|
||||||
|
pub horizontal_alignment: HorizontalAlignment,
|
||||||
|
pub vertical_alignment: VerticalAlignment,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Layer<'a> {
|
impl<'a> Layer<'a> {
|
||||||
pub fn new(bounds: Rectangle<u32>) -> Self {
|
pub fn new(bounds: Rectangle<u32>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -159,41 +171,15 @@ impl Renderer {
|
|||||||
} => {
|
} => {
|
||||||
let layer = layers.last_mut().unwrap();
|
let layer = layers.last_mut().unwrap();
|
||||||
|
|
||||||
layer.text.push(wgpu_glyph::Section {
|
layer.text.push(Text {
|
||||||
text: &content,
|
content,
|
||||||
screen_position: (
|
bounds: *bounds + translation,
|
||||||
bounds.x + translation.x,
|
size: *size,
|
||||||
bounds.y + translation.y,
|
|
||||||
),
|
|
||||||
bounds: (bounds.width, bounds.height),
|
|
||||||
scale: wgpu_glyph::Scale { x: *size, y: *size },
|
|
||||||
color: color.into_linear(),
|
color: color.into_linear(),
|
||||||
font_id: self.text_pipeline.find_font(*font),
|
font: *font,
|
||||||
layout: wgpu_glyph::Layout::default()
|
horizontal_alignment: *horizontal_alignment,
|
||||||
.h_align(match horizontal_alignment {
|
vertical_alignment: *vertical_alignment,
|
||||||
iced_native::HorizontalAlignment::Left => {
|
});
|
||||||
wgpu_glyph::HorizontalAlign::Left
|
|
||||||
}
|
|
||||||
iced_native::HorizontalAlignment::Center => {
|
|
||||||
wgpu_glyph::HorizontalAlign::Center
|
|
||||||
}
|
|
||||||
iced_native::HorizontalAlignment::Right => {
|
|
||||||
wgpu_glyph::HorizontalAlign::Right
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.v_align(match vertical_alignment {
|
|
||||||
iced_native::VerticalAlignment::Top => {
|
|
||||||
wgpu_glyph::VerticalAlign::Top
|
|
||||||
}
|
|
||||||
iced_native::VerticalAlignment::Center => {
|
|
||||||
wgpu_glyph::VerticalAlign::Center
|
|
||||||
}
|
|
||||||
iced_native::VerticalAlignment::Bottom => {
|
|
||||||
wgpu_glyph::VerticalAlign::Bottom
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Primitive::Quad {
|
Primitive::Quad {
|
||||||
bounds,
|
bounds,
|
||||||
@ -315,26 +301,26 @@ impl Renderer {
|
|||||||
let first = layers.first().unwrap();
|
let first = layers.first().unwrap();
|
||||||
let mut overlay = Layer::new(first.bounds);
|
let mut overlay = Layer::new(first.bounds);
|
||||||
|
|
||||||
let font_id = self.text_pipeline.overlay_font();
|
|
||||||
let scale = wgpu_glyph::Scale { x: 20.0, y: 20.0 };
|
|
||||||
|
|
||||||
for (i, line) in lines.iter().enumerate() {
|
for (i, line) in lines.iter().enumerate() {
|
||||||
overlay.text.push(wgpu_glyph::Section {
|
let text = Text {
|
||||||
text: line.as_ref(),
|
content: line.as_ref(),
|
||||||
screen_position: (11.0, 11.0 + 25.0 * i as f32),
|
bounds: Rectangle::new(
|
||||||
|
Point::new(11.0, 11.0 + 25.0 * i as f32),
|
||||||
|
Size::INFINITY,
|
||||||
|
),
|
||||||
color: [0.9, 0.9, 0.9, 1.0],
|
color: [0.9, 0.9, 0.9, 1.0],
|
||||||
scale,
|
size: 20.0,
|
||||||
font_id,
|
font: Font::Default,
|
||||||
..wgpu_glyph::Section::default()
|
horizontal_alignment: HorizontalAlignment::Left,
|
||||||
});
|
vertical_alignment: VerticalAlignment::Top,
|
||||||
|
};
|
||||||
|
|
||||||
overlay.text.push(wgpu_glyph::Section {
|
overlay.text.push(text);
|
||||||
text: line.as_ref(),
|
|
||||||
screen_position: (10.0, 10.0 + 25.0 * i as f32),
|
overlay.text.push(Text {
|
||||||
|
bounds: text.bounds + Vector::new(-1.0, -1.0),
|
||||||
color: [0.0, 0.0, 0.0, 1.0],
|
color: [0.0, 0.0, 0.0, 1.0],
|
||||||
scale,
|
..text
|
||||||
font_id,
|
|
||||||
..wgpu_glyph::Section::default()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,8 +395,8 @@ impl Renderer {
|
|||||||
// bit "jumpy". We may be able to do better once we improve
|
// bit "jumpy". We may be able to do better once we improve
|
||||||
// our text rendering/caching pipeline.
|
// our text rendering/caching pipeline.
|
||||||
screen_position: (
|
screen_position: (
|
||||||
(text.screen_position.0 * scale_factor).round(),
|
(text.bounds.x * scale_factor).round(),
|
||||||
(text.screen_position.1 * scale_factor).round(),
|
(text.bounds.y * scale_factor).round(),
|
||||||
),
|
),
|
||||||
// TODO: Fix precision issues with some scale factors.
|
// TODO: Fix precision issues with some scale factors.
|
||||||
//
|
//
|
||||||
@ -422,14 +408,45 @@ impl Renderer {
|
|||||||
// scaling when rendering. This would ensure that both
|
// scaling when rendering. This would ensure that both
|
||||||
// measuring and rendering follow the same layout rules.
|
// measuring and rendering follow the same layout rules.
|
||||||
bounds: (
|
bounds: (
|
||||||
(text.bounds.0 * scale_factor).ceil(),
|
(text.bounds.width * scale_factor).ceil(),
|
||||||
(text.bounds.1 * scale_factor).ceil(),
|
(text.bounds.height * scale_factor).ceil(),
|
||||||
),
|
),
|
||||||
scale: wgpu_glyph::Scale {
|
text: vec![wgpu_glyph::Text {
|
||||||
x: text.scale.x * scale_factor,
|
text: text.content,
|
||||||
y: text.scale.y * scale_factor,
|
scale: wgpu_glyph::ab_glyph::PxScale {
|
||||||
|
x: text.size * scale_factor,
|
||||||
|
y: text.size * scale_factor,
|
||||||
},
|
},
|
||||||
..*text
|
font_id: self.text_pipeline.find_font(text.font),
|
||||||
|
extra: wgpu_glyph::Extra {
|
||||||
|
color: text.color,
|
||||||
|
z: 0.0,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
layout: wgpu_glyph::Layout::default()
|
||||||
|
.h_align(match text.horizontal_alignment {
|
||||||
|
HorizontalAlignment::Left => {
|
||||||
|
wgpu_glyph::HorizontalAlign::Left
|
||||||
|
}
|
||||||
|
HorizontalAlignment::Center => {
|
||||||
|
wgpu_glyph::HorizontalAlign::Center
|
||||||
|
}
|
||||||
|
HorizontalAlignment::Right => {
|
||||||
|
wgpu_glyph::HorizontalAlign::Right
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.v_align(match text.vertical_alignment {
|
||||||
|
VerticalAlignment::Top => {
|
||||||
|
wgpu_glyph::VerticalAlign::Top
|
||||||
|
}
|
||||||
|
VerticalAlignment::Center => {
|
||||||
|
wgpu_glyph::VerticalAlign::Center
|
||||||
|
}
|
||||||
|
VerticalAlignment::Bottom => {
|
||||||
|
wgpu_glyph::VerticalAlign::Bottom
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.text_pipeline.queue(text);
|
self.text_pipeline.queue(text);
|
||||||
|
@ -17,20 +17,13 @@ impl text_input::Renderer for Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn measure_value(&self, value: &str, size: u16, font: Font) -> f32 {
|
fn measure_value(&self, value: &str, size: u16, font: Font) -> f32 {
|
||||||
let (mut width, _) = self.text_pipeline.measure(
|
let (width, _) = self.text_pipeline.measure(
|
||||||
value,
|
value,
|
||||||
f32::from(size),
|
f32::from(size),
|
||||||
font,
|
font,
|
||||||
Size::INFINITY,
|
Size::INFINITY,
|
||||||
);
|
);
|
||||||
|
|
||||||
let spaces_around = value.len() - value.trim().len();
|
|
||||||
|
|
||||||
if spaces_around > 0 {
|
|
||||||
let space_width = self.text_pipeline.space_width(size as f32);
|
|
||||||
width += spaces_around as f32 * space_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
width
|
width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ mod font;
|
|||||||
use crate::Transformation;
|
use crate::Transformation;
|
||||||
|
|
||||||
use std::{cell::RefCell, collections::HashMap};
|
use std::{cell::RefCell, collections::HashMap};
|
||||||
|
use wgpu_glyph::ab_glyph;
|
||||||
|
|
||||||
pub const BUILTIN_ICONS: iced_native::Font = iced_native::Font::External {
|
pub const BUILTIN_ICONS: iced_native::Font = iced_native::Font::External {
|
||||||
name: "iced_wgpu icons",
|
name: "iced_wgpu icons",
|
||||||
@ -15,10 +16,10 @@ const FALLBACK_FONT: &[u8] = include_bytes!("../fonts/Lato-Regular.ttf");
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
draw_brush: RefCell<wgpu_glyph::GlyphBrush<'static, ()>>,
|
draw_brush: RefCell<wgpu_glyph::GlyphBrush<()>>,
|
||||||
draw_font_map: RefCell<HashMap<String, wgpu_glyph::FontId>>,
|
draw_font_map: RefCell<HashMap<String, wgpu_glyph::FontId>>,
|
||||||
|
|
||||||
measure_brush: RefCell<glyph_brush::GlyphBrush<'static, ()>>,
|
measure_brush: RefCell<glyph_brush::GlyphBrush<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pipeline {
|
impl Pipeline {
|
||||||
@ -37,29 +38,26 @@ impl Pipeline {
|
|||||||
.unwrap_or_else(|_| FALLBACK_FONT.to_vec())
|
.unwrap_or_else(|_| FALLBACK_FONT.to_vec())
|
||||||
});
|
});
|
||||||
|
|
||||||
let load_glyph_brush = |font: Vec<u8>| {
|
let font = ab_glyph::FontArc::try_from_vec(default_font)
|
||||||
let builder =
|
.unwrap_or_else(|_| {
|
||||||
wgpu_glyph::GlyphBrushBuilder::using_fonts_bytes(vec![
|
log::warn!(
|
||||||
font.clone()
|
"System font failed to load. Falling back to \
|
||||||
])?;
|
embedded font..."
|
||||||
|
);
|
||||||
|
|
||||||
Ok((
|
ab_glyph::FontArc::try_from_slice(FALLBACK_FONT)
|
||||||
builder,
|
.expect("Load fallback font")
|
||||||
glyph_brush::GlyphBrushBuilder::using_font_bytes(font).build(),
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
let (brush_builder, measure_brush) = load_glyph_brush(default_font)
|
|
||||||
.unwrap_or_else(|_: wgpu_glyph::rusttype::Error| {
|
|
||||||
log::warn!("System font failed to load. Falling back to embedded font...");
|
|
||||||
|
|
||||||
load_glyph_brush(FALLBACK_FONT.to_vec()).expect("Load fallback font")
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let draw_brush = brush_builder
|
let draw_brush =
|
||||||
|
wgpu_glyph::GlyphBrushBuilder::using_font(font.clone())
|
||||||
.initial_cache_size((2048, 2048))
|
.initial_cache_size((2048, 2048))
|
||||||
|
.draw_cache_multithread(false) // TODO: Expose as a configuration flag
|
||||||
.build(device, format);
|
.build(device, format);
|
||||||
|
|
||||||
|
let measure_brush =
|
||||||
|
glyph_brush::GlyphBrushBuilder::using_font(font).build();
|
||||||
|
|
||||||
Pipeline {
|
Pipeline {
|
||||||
draw_brush: RefCell::new(draw_brush),
|
draw_brush: RefCell::new(draw_brush),
|
||||||
draw_font_map: RefCell::new(HashMap::new()),
|
draw_font_map: RefCell::new(HashMap::new()),
|
||||||
@ -68,10 +66,6 @@ impl Pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn overlay_font(&self) -> wgpu_glyph::FontId {
|
|
||||||
wgpu_glyph::FontId(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn queue(&mut self, section: wgpu_glyph::Section<'_>) {
|
pub fn queue(&mut self, section: wgpu_glyph::Section<'_>) {
|
||||||
self.draw_brush.borrow_mut().queue(section);
|
self.draw_brush.borrow_mut().queue(section);
|
||||||
}
|
}
|
||||||
@ -108,10 +102,13 @@ impl Pipeline {
|
|||||||
let wgpu_glyph::FontId(font_id) = self.find_font(font);
|
let wgpu_glyph::FontId(font_id) = self.find_font(font);
|
||||||
|
|
||||||
let section = wgpu_glyph::Section {
|
let section = wgpu_glyph::Section {
|
||||||
text: content,
|
|
||||||
scale: wgpu_glyph::Scale { x: size, y: size },
|
|
||||||
bounds: (bounds.width, bounds.height),
|
bounds: (bounds.width, bounds.height),
|
||||||
|
text: vec![wgpu_glyph::Text {
|
||||||
|
text: content,
|
||||||
|
scale: size.into(),
|
||||||
font_id: wgpu_glyph::FontId(font_id),
|
font_id: wgpu_glyph::FontId(font_id),
|
||||||
|
extra: wgpu_glyph::Extra::default(),
|
||||||
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,20 +121,6 @@ impl Pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn space_width(&self, size: f32) -> f32 {
|
|
||||||
use wgpu_glyph::GlyphCruncher;
|
|
||||||
|
|
||||||
let glyph_brush = self.measure_brush.borrow();
|
|
||||||
|
|
||||||
// TODO: Select appropriate font
|
|
||||||
let font = &glyph_brush.fonts()[0];
|
|
||||||
|
|
||||||
font.glyph(' ')
|
|
||||||
.scaled(wgpu_glyph::Scale { x: size, y: size })
|
|
||||||
.h_metrics()
|
|
||||||
.advance_width
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_measurement_cache(&mut self) {
|
pub fn clear_measurement_cache(&mut self) {
|
||||||
// TODO: We should probably use a `GlyphCalculator` for this. However,
|
// TODO: We should probably use a `GlyphCalculator` for this. However,
|
||||||
// it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop.
|
// it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop.
|
||||||
@ -170,11 +153,12 @@ impl Pipeline {
|
|||||||
return *font_id;
|
return *font_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Find a way to share font data
|
let font = ab_glyph::FontArc::try_from_slice(bytes)
|
||||||
let _ = self.measure_brush.borrow_mut().add_font_bytes(bytes);
|
.expect("Load font");
|
||||||
|
|
||||||
let font_id =
|
let _ = self.measure_brush.borrow_mut().add_font(font.clone());
|
||||||
self.draw_brush.borrow_mut().add_font_bytes(bytes);
|
|
||||||
|
let font_id = self.draw_brush.borrow_mut().add_font(font);
|
||||||
|
|
||||||
let _ = self
|
let _ = self
|
||||||
.draw_font_map
|
.draw_font_map
|
||||||
|
Loading…
Reference in New Issue
Block a user