Text rendering for iced with glyph_brush works now

This commit is contained in:
Imbris 2020-05-18 02:13:13 -04:00
parent fa1cd17a71
commit 0053299b14
13 changed files with 119 additions and 158 deletions

View File

@ -191,7 +191,7 @@ struct IcedState {
pub type Message = Event; pub type Message = Event;
impl IcedState { impl IcedState {
pub fn view(&mut self) -> Element<Message> { pub fn view(&mut self) -> Element<Message> {
use iced::{Align, Column, Container, Length, Row, Space}; use iced::{Align, Column, Container, Length, Row, Space, Text};
use ui::ice::{ use ui::ice::{
compound_graphic::{CompoundGraphic, Graphic}, compound_graphic::{CompoundGraphic, Graphic},
BackgroundContainer, Image, Padding, BackgroundContainer, Image, Padding,
@ -201,7 +201,12 @@ impl IcedState {
let buttons = Column::with_children(vec![ let buttons = Column::with_children(vec![
Image::new(self.imgs.button).fix_aspect_ratio().into(), Image::new(self.imgs.button).fix_aspect_ratio().into(),
Image::new(self.imgs.button).fix_aspect_ratio().into(), Image::new(self.imgs.button).fix_aspect_ratio().into(),
Image::new(self.imgs.button).fix_aspect_ratio().into(), /* BackgroundContainer::new(
Image::new(self.imgs.button).fix_aspect_ratio(),
Text::new("Quit"),
)
.into(), */
Text::new("Quit").size(20).into(),
]) ])
.width(Length::Fill) .width(Length::Fill)
.max_width(200) .max_width(200)

View File

@ -1,15 +1,10 @@
use super::{ use super::graphic::{Graphic, GraphicCache, Id as GraphicId};
graphic::{Graphic, GraphicCache, Id as GraphicId},
renderer::{IcedRenderer, Primitive},
};
use crate::{ use crate::{
render::{Renderer, Texture}, render::{Renderer, Texture},
Error, Error,
}; };
use glyph_brush::{ use glyph_brush::GlyphBrushBuilder;
GlyphBrushBuilder, GlyphCalculator, GlyphCalculatorBuilder, GlyphCalculatorGuard, use std::cell::{RefCell, RefMut};
};
use std::cell::RefCell;
use vek::*; use vek::*;
// Multiplied by current window size // Multiplied by current window size
@ -23,7 +18,7 @@ type GlyphBrush = glyph_brush::GlyphBrush<'static, (Aabr<f32>, Aabr<f32>)>;
pub type Font = glyph_brush::rusttype::Font<'static>; pub type Font = glyph_brush::rusttype::Font<'static>;
pub struct Cache { pub struct Cache {
glyph_cache: GlyphBrush, glyph_brush: RefCell<GlyphBrush>,
glyph_cache_tex: Texture, glyph_cache_tex: Texture,
graphic_cache: GraphicCache, graphic_cache: GraphicCache,
} }
@ -38,12 +33,14 @@ impl Cache {
let glyph_cache_dims = let glyph_cache_dims =
Vec2::new(w, h).map(|e| (e * GLYPH_CACHE_SIZE).min(max_texture_size as u16).max(512)); Vec2::new(w, h).map(|e| (e * GLYPH_CACHE_SIZE).min(max_texture_size as u16).max(512));
Ok(Self { let glyph_brush = GlyphBrushBuilder::using_font(default_font)
glyph_cache: GlyphBrushBuilder::using_font(default_font)
.initial_cache_size((glyph_cache_dims.x as u32, glyph_cache_dims.y as u32)) .initial_cache_size((glyph_cache_dims.x as u32, glyph_cache_dims.y as u32))
.gpu_cache_scale_tolerance(SCALE_TOLERANCE) .gpu_cache_scale_tolerance(SCALE_TOLERANCE)
.gpu_cache_position_tolerance(POSITION_TOLERANCE) .gpu_cache_position_tolerance(POSITION_TOLERANCE)
.build(), .build();
Ok(Self {
glyph_brush: RefCell::new(glyph_brush),
glyph_cache_tex: renderer.create_dynamic_texture(glyph_cache_dims.map(|e| e as u16))?, glyph_cache_tex: renderer.create_dynamic_texture(glyph_cache_dims.map(|e| e as u16))?,
graphic_cache: GraphicCache::new(renderer), graphic_cache: GraphicCache::new(renderer),
}) })
@ -52,10 +49,12 @@ impl Cache {
pub fn glyph_cache_tex(&self) -> &Texture { &self.glyph_cache_tex } pub fn glyph_cache_tex(&self) -> &Texture { &self.glyph_cache_tex }
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphBrush, &Texture) { pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphBrush, &Texture) {
(&mut self.glyph_cache, &self.glyph_cache_tex) (self.glyph_brush.get_mut(), &self.glyph_cache_tex)
} }
pub fn glyph_cache_mut(&mut self) -> &mut GlyphBrush { &mut self.glyph_cache } pub fn glyph_cache_mut(&mut self) -> &mut GlyphBrush { self.glyph_brush.get_mut() }
pub fn glyph_calculator(&self) -> RefMut<GlyphBrush> { self.glyph_brush.borrow_mut() }
// TODO: add font fn // TODO: add font fn
@ -82,72 +81,13 @@ impl Cache {
let cache_dims = renderer let cache_dims = renderer
.get_resolution() .get_resolution()
.map(|e| (e * GLYPH_CACHE_SIZE).min(max_texture_size as u16).max(512)); .map(|e| (e * GLYPH_CACHE_SIZE).min(max_texture_size as u16).max(512));
self.glyph_cache = self let glyph_brush = self.glyph_brush.get_mut();
.glyph_cache *glyph_brush = glyph_brush
.to_builder() .to_builder()
.initial_cache_size((cache_dims.x as u32, cache_dims.y as u32)) .initial_cache_size((cache_dims.x as u32, cache_dims.y as u32))
.build(); .build();
self.glyph_cache_tex = renderer.create_dynamic_texture(cache_dims.map(|e| e as u16))?; self.glyph_cache_tex = renderer.create_dynamic_texture(cache_dims.map(|e| e as u16))?;
Ok(()) Ok(())
} }
} }
pub struct GlyphCalcCache {
// Hold one of these for adding new fonts
builder: GlyphCalculatorBuilder<'static>,
calculator: GlyphCalculator<'static>,
}
impl GlyphCalcCache {
pub fn new(default_font: Font) -> Self {
// Multiple copies of the font in memory :/ (using Arc<[u8]> might help)
let builder = GlyphCalculatorBuilder::using_font(default_font);
let calculator = builder.clone().build();
Self {
builder,
calculator,
}
}
pub fn frame_guard<'a>(&'a self) -> GlyphCalculatorGuard<'a, 'static> {
self.calculator.cache_scope()
}
// add new font fn
}
pub struct FrameRenderer<'a> {
pub renderer: &'a mut IcedRenderer,
pub glyph_calc: RefCell<GlyphCalculatorGuard<'a, 'static>>,
}
impl<'a> FrameRenderer<'a> {
pub fn new(renderer: &'a mut IcedRenderer, glyph_calc_cache: &'a mut GlyphCalcCache) -> Self {
Self {
renderer,
glyph_calc: RefCell::new(glyph_calc_cache.frame_guard()),
}
}
}
impl iced::Renderer for FrameRenderer<'_> {
// Default styling
type Defaults = ();
// TODO: use graph of primitives to enable diffing???
type Output = (Primitive, iced::mouse::Interaction);
fn layout<'a, M>(
&mut self,
element: &iced::Element<'a, M, Self>,
limits: &iced::layout::Limits,
) -> iced::layout::Node {
let node = element.layout(self, limits);
// Trim text measurements cache?
node
}
}
// TODO: impl Debugger

View File

@ -21,16 +21,17 @@ use super::{
scale::{Scale, ScaleMode}, scale::{Scale, ScaleMode},
}; };
use crate::{render::Renderer, window::Window, Error}; use crate::{render::Renderer, window::Window, Error};
use cache::{FrameRenderer, GlyphCalcCache};
use clipboard::Clipboard; use clipboard::Clipboard;
use iced::{mouse, Cache, Size, UserInterface}; use iced::{mouse, Cache, Size, UserInterface};
use vek::*; use vek::*;
pub type Element<'a, 'b, M> = iced::Element<'a, M, FrameRenderer<'b>>; pub type Element<'a, M> = iced::Element<'a, M, IcedRenderer>;
#[derive(Clone, Copy, Default)]
pub struct FontId(glyph_brush::FontId);
pub struct IcedUi { pub struct IcedUi {
renderer: IcedRenderer, renderer: IcedRenderer,
glyph_calc_cache: GlyphCalcCache,
cache: Option<Cache>, cache: Option<Cache>,
events: Vec<Event>, events: Vec<Event>,
clipboard: Clipboard, clipboard: Clipboard,
@ -47,8 +48,7 @@ impl IcedUi {
// TODO: examine how much mem fonts take up and reduce clones if significant // TODO: examine how much mem fonts take up and reduce clones if significant
Ok(Self { Ok(Self {
renderer: IcedRenderer::new(renderer, scaled_dims, default_font.clone())?, renderer: IcedRenderer::new(renderer, scaled_dims, default_font)?,
glyph_calc_cache: GlyphCalcCache::new(default_font),
cache: Some(Cache::new()), cache: Some(Cache::new()),
events: Vec::new(), events: Vec::new(),
// TODO: handle None // TODO: handle None
@ -99,8 +99,9 @@ impl IcedUi {
} }
// TODO: produce root internally??? // TODO: produce root internally???
// TODO: see if this lifetime soup can be simplified // TODO: closure/trait for sending messages back? (take a look at higher level
pub fn maintain<'a, M, E: for<'b> Into<iced::Element<'a, M, FrameRenderer<'b>>>>( // iced libs)
pub fn maintain<'a, M, E: Into<Element<'a, M>>>(
&mut self, &mut self,
root: E, root: E,
renderer: &mut Renderer, renderer: &mut Renderer,
@ -133,22 +134,20 @@ impl IcedUi {
// TODO: convert to f32 at source // TODO: convert to f32 at source
let window_size = self.scale.scaled_window_size().map(|e| e as f32); let window_size = self.scale.scaled_window_size().map(|e| e as f32);
let mut frame_renderer = FrameRenderer::new(&mut self.renderer, &mut self.glyph_calc_cache);
let mut user_interface = UserInterface::build( let mut user_interface = UserInterface::build(
root, root,
Size::new(window_size.x, window_size.y), Size::new(window_size.x, window_size.y),
self.cache.take().unwrap(), self.cache.take().unwrap(),
&mut frame_renderer, &mut self.renderer,
); );
let messages = user_interface.update( let messages = user_interface.update(
self.events.drain(..), self.events.drain(..),
Some(&self.clipboard), Some(&self.clipboard),
&frame_renderer, &mut self.renderer,
); );
let (primitive, mouse_interaction) = user_interface.draw(&mut frame_renderer); let (primitive, mouse_interaction) = user_interface.draw(&mut self.renderer);
self.cache = Some(user_interface.into_cache()); self.cache = Some(user_interface.into_cache());

View File

@ -5,6 +5,7 @@ mod container;
mod image; mod image;
mod row; mod row;
mod space; mod space;
mod text;
use super::{ use super::{
super::graphic::{self, Graphic, TexId}, super::graphic::{self, Graphic, TexId},
@ -189,8 +190,8 @@ impl IcedRenderer {
// Draw glyph cache (use for debugging). // Draw glyph cache (use for debugging).
/*self.draw_commands /*self.draw_commands
.push(DrawCommand::Scissor(default_scissor(renderer))); .push(DrawCommand::Scissor(default_scissor(renderer)));
start = mesh.vertices().len(); self.start = self.mesh.vertices().len();
mesh.push_quad(create_ui_quad( self.mesh.push_quad(create_ui_quad(
Aabr { Aabr {
min: (-1.0, -1.0).into(), min: (-1.0, -1.0).into(),
max: (1.0, 1.0).into(), max: (1.0, 1.0).into(),
@ -199,11 +200,11 @@ impl IcedRenderer {
min: (0.0, 1.0).into(), min: (0.0, 1.0).into(),
max: (1.0, 0.0).into(), max: (1.0, 0.0).into(),
}, },
Rgba::new(1.0, 1.0, 1.0, 0.8), Rgba::new(1.0, 1.0, 1.0, 0.3),
UiMode::Text, UiMode::Text,
)); ));
self.draw_commands self.draw_commands
.push(DrawCommand::plain(start..mesh.vertices().len()));*/ .push(DrawCommand::plain(self.start..self.mesh.vertices().len()));*/
// Fill in placeholder glyph quads // Fill in placeholder glyph quads
let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex(); let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex();
@ -234,11 +235,11 @@ impl IcedRenderer {
let rect = Aabr { let rect = Aabr {
min: Vec2::new( min: Vec2::new(
pixel_coords.min.x as f32 / half_res.x - 1.0, pixel_coords.min.x as f32 / half_res.x - 1.0,
pixel_coords.min.y as f32 / half_res.y - 1.0, 1.0 - pixel_coords.max.y as f32 / half_res.y,
), ),
max: Vec2::new( max: Vec2::new(
pixel_coords.max.x as f32 / half_res.x - 1.0, pixel_coords.max.x as f32 / half_res.x - 1.0,
pixel_coords.max.y as f32 / half_res.y - 1.0, 1.0 - pixel_coords.min.y as f32 / half_res.y,
), ),
}; };
(uv, rect) (uv, rect)
@ -483,12 +484,13 @@ impl IcedRenderer {
// seems redundant... // seems redundant...
glyph_brush::rusttype::Rect { glyph_brush::rusttype::Rect {
min: glyph_brush::rusttype::Point { min: glyph_brush::rusttype::Point {
x: bounds.x, x: bounds.x * self.p_scale,
y: bounds.y, //y: (self.win_dims.y - bounds.y) * self.p_scale,
y: bounds.y * self.p_scale,
}, },
max: glyph_brush::rusttype::Point { max: glyph_brush::rusttype::Point {
x: bounds.x + bounds.width, x: (bounds.x + bounds.width) * self.p_scale,
y: bounds.y + bounds.height, y: (bounds.y + bounds.height) * self.p_scale,
}, },
}, },
0.0, // z (we don't use this) 0.0, // z (we don't use this)
@ -579,3 +581,24 @@ fn default_scissor(renderer: &Renderer) -> Aabr<u16> {
}, },
} }
} }
impl iced::Renderer for IcedRenderer {
// Default styling
type Defaults = ();
// TODO: use graph of primitives to enable diffing???
type Output = (Primitive, iced::mouse::Interaction);
fn layout<'a, M>(
&mut self,
element: &iced::Element<'a, M, Self>,
limits: &iced::layout::Limits,
) -> iced::layout::Node {
let node = element.layout(self, limits);
// Trim text measurements cache?
node
}
}
// TODO: impl Debugger

View File

@ -1,10 +1,7 @@
use super::{ use super::{super::widget::background_container, IcedRenderer, Primitive};
super::{cache::FrameRenderer, widget::background_container},
Primitive,
};
use iced::{Element, Layout, Point}; use iced::{Element, Layout, Point};
impl background_container::Renderer for FrameRenderer<'_> { impl background_container::Renderer for IcedRenderer {
fn draw<M, B>( fn draw<M, B>(
&mut self, &mut self,
defaults: &Self::Defaults, defaults: &Self::Defaults,

View File

@ -1,7 +1,7 @@
use super::{super::cache::FrameRenderer, Primitive}; use super::{IcedRenderer, Primitive};
use iced::{column, mouse, Element, Layout, Point}; use iced::{column, mouse, Element, Layout, Point};
impl column::Renderer for FrameRenderer<'_> { impl column::Renderer for IcedRenderer {
fn draw<M>( fn draw<M>(
&mut self, &mut self,
defaults: &Self::Defaults, defaults: &Self::Defaults,

View File

@ -1,11 +1,11 @@
use super::{ use super::{
super::{cache::FrameRenderer, widget::compound_graphic, Rotation}, super::{widget::compound_graphic, Rotation},
Primitive, IcedRenderer, Primitive,
}; };
use compound_graphic::GraphicKind; use compound_graphic::GraphicKind;
use iced::{mouse, Rectangle}; use iced::{mouse, Rectangle};
impl compound_graphic::Renderer for FrameRenderer<'_> { impl compound_graphic::Renderer for IcedRenderer {
fn draw<I>( fn draw<I>(
&mut self, &mut self,
graphics: I, graphics: I,

View File

@ -1,7 +1,7 @@
use super::super::cache::FrameRenderer; use super::IcedRenderer;
use iced::{container, Element, Layout, Point, Rectangle}; use iced::{container, Element, Layout, Point, Rectangle};
impl container::Renderer for FrameRenderer<'_> { impl container::Renderer for IcedRenderer {
type Style = (); type Style = ();
fn draw<M>( fn draw<M>(

View File

@ -1,13 +1,13 @@
use super::{ use super::{
super::{cache::FrameRenderer, widget::image, Rotation}, super::{widget::image, Rotation},
Primitive, IcedRenderer, Primitive,
}; };
use iced::mouse; use iced::mouse;
use vek::Rgba; use vek::Rgba;
impl image::Renderer for FrameRenderer<'_> { impl image::Renderer for IcedRenderer {
fn dimensions(&self, handle: image::Handle) -> (u32, u32) { fn dimensions(&self, handle: image::Handle) -> (u32, u32) {
self.renderer self
.cache .cache
.graphic_cache() .graphic_cache()
.get_graphic_dims((handle, Rotation::None)) .get_graphic_dims((handle, Rotation::None))

View File

@ -1,7 +1,7 @@
use super::{super::cache::FrameRenderer, Primitive}; use super::{IcedRenderer, Primitive};
use iced::{mouse, row, Element, Layout, Point}; use iced::{mouse, row, Element, Layout, Point};
impl row::Renderer for FrameRenderer<'_> { impl row::Renderer for IcedRenderer {
fn draw<M>( fn draw<M>(
&mut self, &mut self,
defaults: &Self::Defaults, defaults: &Self::Defaults,

View File

@ -1,7 +1,7 @@
use super::{super::cache::FrameRenderer, Primitive}; use super::{IcedRenderer, Primitive};
use iced::{mouse, space, Rectangle}; use iced::{mouse, space, Rectangle};
impl space::Renderer for FrameRenderer<'_> { impl space::Renderer for IcedRenderer {
fn draw(&mut self, _bounds: Rectangle) -> Self::Output { fn draw(&mut self, _bounds: Rectangle) -> Self::Output {
(Primitive::Nothing, mouse::Interaction::default()) (Primitive::Nothing, mouse::Interaction::default())
} }

View File

@ -1,10 +1,7 @@
use super::{ use super::{super::widget::stack, IcedRenderer, Primitive};
super::{cache::FrameRenderer, widget::stack},
Primitive,
};
use iced::{mouse, Element, Layout, Point}; use iced::{mouse, Element, Layout, Point};
impl stack::Renderer for FrameRenderer<'_> { impl stack::Renderer for IcedRenderer {
fn draw<M>( fn draw<M>(
&mut self, &mut self,
defaults: &Self::Defaults, defaults: &Self::Defaults,

View File

@ -1,21 +1,13 @@
use iced::{ use super::{super::FontId, IcedRenderer, Primitive};
text, Color, Font, HorizontalAlignment, mouse, Rectangle, Size, VerticalAlignment, use glyph_brush::GlyphCruncher;
}; use iced::{mouse, text, Color, HorizontalAlignment, Rectangle, Size, VerticalAlignment};
use super::{super::cache::FrameRenderer, Primitive}:
struct FontId(glyph_brush::FontId); impl text::Renderer for IcedRenderer {
impl text::Renderer for FrameRenderer<'_> {
type Font = FontId; type Font = FontId;
const DEFAULT_SIZE: u16 = 20; const DEFAULT_SIZE: u16 = 20;
fn measure( fn measure(&self, content: &str, size: u16, font: Self::Font, bounds: Size) -> (f32, f32) {
&self,
content: &str,
size: u16,
font: Self::Font,
bounds: Size,
) -> (f32, f32) {
// Using the physical scale might make these cached info usable below? // Using the physical scale might make these cached info usable below?
// Although we also have a position of the screen so this could be useless // Although we also have a position of the screen so this could be useless
let p_scale = self.p_scale; let p_scale = self.p_scale;
@ -24,17 +16,19 @@ impl text::Renderer for FrameRenderer<'_> {
text: content, text: content,
scale: glyph_brush::rusttype::Scale::uniform(size as f32 * p_scale), scale: glyph_brush::rusttype::Scale::uniform(size as f32 * p_scale),
font_id: font.0, font_id: font.0,
bounds: (size.width, size.height), bounds: (bounds.width * p_scale, bounds.height * p_scale),
..Default::default() ..Default::default()
}; };
let maybe_rect = self.glyph_calc.borrow_mut().glyph_bounds(section); let maybe_rect = self.cache.glyph_calculator().glyph_bounds(section);
maybe_rect.map_or((0.0, 0.0), |rect| (rect.width() / p_scale, rect.height() / p_scale)) maybe_rect.map_or((0.0, 0.0), |rect| {
(rect.width() / p_scale, rect.height() / p_scale)
})
} }
fn draw( fn draw(
&mut self, &mut self,
defaults: &Self::Defaults, _defaults: &Self::Defaults,
bounds: Rectangle, bounds: Rectangle,
content: &str, content: &str,
size: u16, size: u16,
@ -61,6 +55,7 @@ impl text::Renderer for FrameRenderer<'_> {
let section = glyph_brush::Section { let section = glyph_brush::Section {
text: content, text: content,
// TODO: do snap to pixel thing here IF it is being done down the line // TODO: do snap to pixel thing here IF it is being done down the line
//screen_position: (bounds.x * p_scale, (self.win_dims.y - bounds.y) * p_scale),
screen_position: (bounds.x * p_scale, bounds.y * p_scale), screen_position: (bounds.x * p_scale, bounds.y * p_scale),
bounds: (bounds.width * p_scale, bounds.height * p_scale), bounds: (bounds.width * p_scale, bounds.height * p_scale),
scale: glyph_brush::rusttype::Scale::uniform(size as f32 * p_scale), scale: glyph_brush::rusttype::Scale::uniform(size as f32 * p_scale),
@ -73,25 +68,30 @@ impl text::Renderer for FrameRenderer<'_> {
..Default::default() ..Default::default()
}; };
let glyphs = self.glyph_calc.borrow_mut().glyphs(section).map(|positioned_glyph| let glyphs = self
.cache
.glyph_cache_mut()
.glyphs(section)
.map(|positioned_glyph| {
( (
positioned_glyph, positioned_glyph.clone(), // :/
[0.0, 0.0, 0.0, 1.0], // Color [0.0, 0.0, 0.0, 1.0], // Color
font.0, font.0,
) )
).collect(); })
.collect::<Vec<_>>();
( (
Primitive::Text { Primitive::Text {
glyphs, glyphs,
//size: size as f32, //size: size as f32,
bounds, bounds,
color: color.unwrap_or(Color::BLACK).into_linear().into(), linear_color: color.unwrap_or(Color::BLACK).into_linear().into(),
//font, /*font,
//horizontal_alignment, *horizontal_alignment,
//vertical_alignment, *vertical_alignment, */
}, },
mouse::Interaction::default, mouse::Interaction::default(),
) )
} }
} }