Update `glyph_brush` to `0.7` 🎉
This commit is contained in:
parent
7d5021ca82
commit
2e39948843
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "glow_glyph"
|
name = "glow_glyph"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "A fast text renderer for glow, powered by glyph_brush"
|
description = "A fast text renderer for glow, powered by glyph_brush"
|
||||||
|
@ -12,7 +12,7 @@ readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
glow = "0.4"
|
glow = "0.4"
|
||||||
glyph_brush = "0.6"
|
glyph_brush = "0.7"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
bytemuck = "1.2"
|
bytemuck = "1.2"
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use glow::HasContext;
|
use glow::HasContext;
|
||||||
use glow_glyph::{GlyphBrushBuilder, Region, Scale, Section};
|
use glow_glyph::{ab_glyph, GlyphBrushBuilder, Region, Section, Text};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
// Open window and create a surface
|
// Open window and create a surface
|
||||||
|
@ -26,10 +27,11 @@ fn main() -> Result<(), String> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prepare glyph_brush
|
// Prepare glyph_brush
|
||||||
let inconsolata: &[u8] = include_bytes!("Inconsolata-Regular.ttf");
|
let inconsolata = ab_glyph::FontArc::try_from_slice(include_bytes!(
|
||||||
let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(inconsolata)
|
"Inconsolata-Regular.ttf"
|
||||||
.expect("Load fonts")
|
))?;
|
||||||
.build(&gl);
|
|
||||||
|
let mut glyph_brush = GlyphBrushBuilder::using_font(inconsolata).build(&gl);
|
||||||
|
|
||||||
// Render loop
|
// Render loop
|
||||||
context.window().request_redraw();
|
context.window().request_redraw();
|
||||||
|
@ -66,11 +68,12 @@ fn main() -> Result<(), String> {
|
||||||
unsafe { gl.clear(glow::COLOR_BUFFER_BIT) }
|
unsafe { gl.clear(glow::COLOR_BUFFER_BIT) }
|
||||||
|
|
||||||
glyph_brush.queue(Section {
|
glyph_brush.queue(Section {
|
||||||
text: "Hello glow_glyph!",
|
|
||||||
screen_position: (30.0, 30.0),
|
screen_position: (30.0, 30.0),
|
||||||
color: [0.0, 0.0, 0.0, 1.0],
|
|
||||||
scale: Scale { x: 40.0, y: 40.0 },
|
|
||||||
bounds: (size.width as f32, size.height as f32),
|
bounds: (size.width as f32, size.height as f32),
|
||||||
|
text: vec![Text::default()
|
||||||
|
.with_text("Hello wgpu_glyph!")
|
||||||
|
.with_color([0.0, 0.0, 0.0, 1.0])
|
||||||
|
.with_scale(40.0)],
|
||||||
..Section::default()
|
..Section::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -79,11 +82,12 @@ fn main() -> Result<(), String> {
|
||||||
.expect("Draw queued");
|
.expect("Draw queued");
|
||||||
|
|
||||||
glyph_brush.queue(Section {
|
glyph_brush.queue(Section {
|
||||||
text: "Hello glow_glyph!",
|
|
||||||
screen_position: (30.0, 90.0),
|
screen_position: (30.0, 90.0),
|
||||||
color: [1.0, 1.0, 1.0, 1.0],
|
|
||||||
scale: Scale { x: 40.0, y: 40.0 },
|
|
||||||
bounds: (size.width as f32, size.height as f32),
|
bounds: (size.width as f32, size.height as f32),
|
||||||
|
text: vec![Text::default()
|
||||||
|
.with_text("Hello wgpu_glyph!")
|
||||||
|
.with_color([1.0, 1.0, 1.0, 1.0])
|
||||||
|
.with_scale(40.0)],
|
||||||
..Section::default()
|
..Section::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use glow::HasContext;
|
use glow::HasContext;
|
||||||
use glow_glyph::{GlyphBrushBuilder, Scale, Section};
|
use glow_glyph::{ab_glyph, GlyphBrushBuilder, Section, Text};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
// Open window and create a surface
|
// Open window and create a surface
|
||||||
|
@ -26,10 +27,11 @@ fn main() -> Result<(), String> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prepare glyph_brush
|
// Prepare glyph_brush
|
||||||
let inconsolata: &[u8] = include_bytes!("Inconsolata-Regular.ttf");
|
let inconsolata = ab_glyph::FontArc::try_from_slice(include_bytes!(
|
||||||
let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(inconsolata)
|
"Inconsolata-Regular.ttf"
|
||||||
.expect("Load fonts")
|
))?;
|
||||||
.build(&gl);
|
|
||||||
|
let mut glyph_brush = GlyphBrushBuilder::using_font(inconsolata).build(&gl);
|
||||||
|
|
||||||
// Render loop
|
// Render loop
|
||||||
context.window().request_redraw();
|
context.window().request_redraw();
|
||||||
|
@ -72,20 +74,22 @@ fn main() -> Result<(), String> {
|
||||||
unsafe { gl.clear(glow::COLOR_BUFFER_BIT) }
|
unsafe { gl.clear(glow::COLOR_BUFFER_BIT) }
|
||||||
|
|
||||||
glyph_brush.queue(Section {
|
glyph_brush.queue(Section {
|
||||||
text: "Hello glow_glyph!",
|
|
||||||
screen_position: (30.0, 30.0),
|
screen_position: (30.0, 30.0),
|
||||||
color: [0.0, 0.0, 0.0, 1.0],
|
|
||||||
scale: Scale { x: 40.0, y: 40.0 },
|
|
||||||
bounds: (size.width as f32, size.height as f32),
|
bounds: (size.width as f32, size.height as f32),
|
||||||
|
text: vec![Text::default()
|
||||||
|
.with_text("Hello wgpu_glyph!")
|
||||||
|
.with_color([0.0, 0.0, 0.0, 1.0])
|
||||||
|
.with_scale(40.0)],
|
||||||
..Section::default()
|
..Section::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
glyph_brush.queue(Section {
|
glyph_brush.queue(Section {
|
||||||
text: "Hello glow_glyph!",
|
|
||||||
screen_position: (30.0, 90.0),
|
screen_position: (30.0, 90.0),
|
||||||
color: [1.0, 1.0, 1.0, 1.0],
|
|
||||||
scale: Scale { x: 40.0, y: 40.0 },
|
|
||||||
bounds: (size.width as f32, size.height as f32),
|
bounds: (size.width as f32, size.height as f32),
|
||||||
|
text: vec![Text::default()
|
||||||
|
.with_text("Hello wgpu_glyph!")
|
||||||
|
.with_color([1.0, 1.0, 1.0, 1.0])
|
||||||
|
.with_scale(40.0)],
|
||||||
..Section::default()
|
..Section::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,67 +1,57 @@
|
||||||
use core::hash::BuildHasher;
|
use core::hash::BuildHasher;
|
||||||
|
|
||||||
|
use glyph_brush::ab_glyph::Font;
|
||||||
use glyph_brush::delegate_glyph_brush_builder_fns;
|
use glyph_brush::delegate_glyph_brush_builder_fns;
|
||||||
use glyph_brush::{rusttype, DefaultSectionHasher};
|
use glyph_brush::DefaultSectionHasher;
|
||||||
use rusttype::{Error, Font, SharedBytes};
|
|
||||||
|
|
||||||
use super::GlyphBrush;
|
use super::GlyphBrush;
|
||||||
|
|
||||||
/// Builder for a [`GlyphBrush`](struct.GlyphBrush.html).
|
/// Builder for a [`GlyphBrush`](struct.GlyphBrush.html).
|
||||||
pub struct GlyphBrushBuilder<'a, H = DefaultSectionHasher> {
|
pub struct GlyphBrushBuilder<F, H = DefaultSectionHasher> {
|
||||||
inner: glyph_brush::GlyphBrushBuilder<'a, H>,
|
inner: glyph_brush::GlyphBrushBuilder<F, H>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H> From<glyph_brush::GlyphBrushBuilder<'a, H>>
|
impl<F, H> From<glyph_brush::GlyphBrushBuilder<F, H>>
|
||||||
for GlyphBrushBuilder<'a, H>
|
for GlyphBrushBuilder<F, H>
|
||||||
{
|
{
|
||||||
fn from(inner: glyph_brush::GlyphBrushBuilder<'a, H>) -> Self {
|
fn from(inner: glyph_brush::GlyphBrushBuilder<F, H>) -> Self {
|
||||||
GlyphBrushBuilder { inner }
|
GlyphBrushBuilder { inner }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> GlyphBrushBuilder<'a> {
|
|
||||||
/// Specifies the default font data used to render glyphs.
|
|
||||||
/// Referenced with `FontId(0)`, which is default.
|
|
||||||
#[inline]
|
|
||||||
pub fn using_font_bytes<B: Into<SharedBytes<'a>>>(
|
|
||||||
font_0_data: B,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let font = Font::from_bytes(font_0_data)?;
|
|
||||||
|
|
||||||
Ok(Self::using_font(font))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn using_fonts_bytes<B, V>(font_data: V) -> Result<Self, Error>
|
|
||||||
where
|
|
||||||
B: Into<SharedBytes<'a>>,
|
|
||||||
V: Into<Vec<B>>,
|
|
||||||
{
|
|
||||||
let fonts = font_data
|
|
||||||
.into()
|
|
||||||
.into_iter()
|
|
||||||
.map(Font::from_bytes)
|
|
||||||
.collect::<Result<Vec<Font>, Error>>()?;
|
|
||||||
|
|
||||||
Ok(Self::using_fonts(fonts))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
impl GlyphBrushBuilder<()> {
|
||||||
/// Specifies the default font used to render glyphs.
|
/// Specifies the default font used to render glyphs.
|
||||||
/// Referenced with `FontId(0)`, which is default.
|
/// Referenced with `FontId(0)`, which is default.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn using_font(font_0: Font<'a>) -> Self {
|
pub fn using_font<F: Font>(font: F) -> GlyphBrushBuilder<F> {
|
||||||
Self::using_fonts(vec![font_0])
|
Self::using_fonts(vec![font])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn using_fonts<V: Into<Vec<Font<'a>>>>(fonts: V) -> Self {
|
pub fn using_fonts<F: Font>(fonts: Vec<F>) -> GlyphBrushBuilder<F> {
|
||||||
GlyphBrushBuilder {
|
GlyphBrushBuilder {
|
||||||
inner: glyph_brush::GlyphBrushBuilder::using_fonts(fonts),
|
inner: glyph_brush::GlyphBrushBuilder::using_fonts(fonts),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H: BuildHasher> GlyphBrushBuilder<'a, H> {
|
impl<F: Font, H: BuildHasher> GlyphBrushBuilder<F, H> {
|
||||||
delegate_glyph_brush_builder_fns!(inner);
|
delegate_glyph_brush_builder_fns!(inner);
|
||||||
|
|
||||||
|
/// When multiple CPU cores are available spread rasterization work across
|
||||||
|
/// all cores.
|
||||||
|
///
|
||||||
|
/// Significantly reduces worst case latency in multicore environments.
|
||||||
|
///
|
||||||
|
/// # Platform-specific behaviour
|
||||||
|
///
|
||||||
|
/// This option has no effect on wasm32.
|
||||||
|
pub fn draw_cache_multithread(mut self, multithread: bool) -> Self {
|
||||||
|
self.inner.draw_cache_builder =
|
||||||
|
self.inner.draw_cache_builder.multithread(multithread);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the section hasher. `GlyphBrush` cannot handle absolute section
|
/// Sets the section hasher. `GlyphBrush` cannot handle absolute section
|
||||||
/// hash collisions so use a good hash algorithm.
|
/// hash collisions so use a good hash algorithm.
|
||||||
///
|
///
|
||||||
|
@ -72,14 +62,14 @@ impl<'a, H: BuildHasher> GlyphBrushBuilder<'a, H> {
|
||||||
pub fn section_hasher<T: BuildHasher>(
|
pub fn section_hasher<T: BuildHasher>(
|
||||||
self,
|
self,
|
||||||
section_hasher: T,
|
section_hasher: T,
|
||||||
) -> GlyphBrushBuilder<'a, T> {
|
) -> GlyphBrushBuilder<F, T> {
|
||||||
GlyphBrushBuilder {
|
GlyphBrushBuilder {
|
||||||
inner: self.inner.section_hasher(section_hasher),
|
inner: self.inner.section_hasher(section_hasher),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a `GlyphBrush` in the given `glow::Context`.
|
/// Builds a `GlyphBrush` in the given `glow::Context`.
|
||||||
pub fn build(self, gl: &glow::Context) -> GlyphBrush<'a, H> {
|
pub fn build(self, gl: &glow::Context) -> GlyphBrush<F, H> {
|
||||||
GlyphBrush::<H>::new(gl, self.inner)
|
GlyphBrush::<F, H>::new(gl, self.inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
238
src/lib.rs
238
src/lib.rs
|
@ -12,30 +12,31 @@ pub use region::Region;
|
||||||
use pipeline::{Instance, Pipeline};
|
use pipeline::{Instance, Pipeline};
|
||||||
|
|
||||||
pub use builder::GlyphBrushBuilder;
|
pub use builder::GlyphBrushBuilder;
|
||||||
|
pub use glyph_brush::ab_glyph;
|
||||||
pub use glyph_brush::{
|
pub use glyph_brush::{
|
||||||
rusttype::{self, Font, Point, PositionedGlyph, Rect, Scale, SharedBytes},
|
BuiltInLineBreaker, Extra, FontId, GlyphCruncher, GlyphPositioner,
|
||||||
BuiltInLineBreaker, FontId, FontMap, GlyphCruncher, GlyphPositioner,
|
HorizontalAlign, Layout, LineBreak, LineBreaker, Section, SectionGeometry,
|
||||||
HorizontalAlign, Layout, LineBreak, LineBreaker, OwnedSectionText,
|
SectionGlyph, SectionGlyphIter, SectionText, Text, VerticalAlign,
|
||||||
OwnedVariedSection, PositionedGlyphIter, Section, SectionGeometry,
|
|
||||||
SectionText, VariedSection, VerticalAlign,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use ab_glyph::{Font, FontArc, Rect};
|
||||||
|
|
||||||
use core::hash::BuildHasher;
|
use core::hash::BuildHasher;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use glyph_brush::{BrushAction, BrushError, Color, DefaultSectionHasher};
|
use glyph_brush::{BrushAction, BrushError, DefaultSectionHasher};
|
||||||
use log::{log_enabled, warn};
|
use log::{log_enabled, warn};
|
||||||
|
|
||||||
/// Object allowing glyph drawing, containing cache state. Manages glyph positioning cacheing,
|
/// Object allowing glyph drawing, containing cache state. Manages glyph positioning cacheing,
|
||||||
/// glyph draw caching & efficient GPU texture cache updating and re-sizing on demand.
|
/// glyph draw caching & efficient GPU texture cache updating and re-sizing on demand.
|
||||||
///
|
///
|
||||||
/// Build using a [`GlyphBrushBuilder`](struct.GlyphBrushBuilder.html).
|
/// Build using a [`GlyphBrushBuilder`](struct.GlyphBrushBuilder.html).
|
||||||
pub struct GlyphBrush<'font, H = DefaultSectionHasher> {
|
pub struct GlyphBrush<F = FontArc, H = DefaultSectionHasher> {
|
||||||
pipeline: Pipeline,
|
pipeline: Pipeline,
|
||||||
glyph_brush: glyph_brush::GlyphBrush<'font, Instance, H>,
|
glyph_brush: glyph_brush::GlyphBrush<Instance, Extra, F, H>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'font, H: BuildHasher> GlyphBrush<'font, H> {
|
impl<F: Font, H: BuildHasher> GlyphBrush<F, H> {
|
||||||
/// Queues a section/layout to be drawn by the next call of
|
/// Queues a section/layout to be drawn by the next call of
|
||||||
/// [`draw_queued`](struct.GlyphBrush.html#method.draw_queued). Can be
|
/// [`draw_queued`](struct.GlyphBrush.html#method.draw_queued). Can be
|
||||||
/// called multiple times to queue multiple sections for drawing.
|
/// called multiple times to queue multiple sections for drawing.
|
||||||
|
@ -44,7 +45,7 @@ impl<'font, H: BuildHasher> GlyphBrush<'font, H> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn queue<'a, S>(&mut self, section: S)
|
pub fn queue<'a, S>(&mut self, section: S)
|
||||||
where
|
where
|
||||||
S: Into<Cow<'a, VariedSection<'a>>>,
|
S: Into<Cow<'a, Section<'a>>>,
|
||||||
{
|
{
|
||||||
self.glyph_brush.queue(section)
|
self.glyph_brush.queue(section)
|
||||||
}
|
}
|
||||||
|
@ -65,7 +66,7 @@ impl<'font, H: BuildHasher> GlyphBrush<'font, H> {
|
||||||
custom_layout: &G,
|
custom_layout: &G,
|
||||||
) where
|
) where
|
||||||
G: GlyphPositioner,
|
G: GlyphPositioner,
|
||||||
S: Into<Cow<'a, VariedSection<'a>>>,
|
S: Into<Cow<'a, Section<'a>>>,
|
||||||
{
|
{
|
||||||
self.glyph_brush.queue_custom_layout(section, custom_layout)
|
self.glyph_brush.queue_custom_layout(section, custom_layout)
|
||||||
}
|
}
|
||||||
|
@ -76,11 +77,11 @@ impl<'font, H: BuildHasher> GlyphBrush<'font, H> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn queue_pre_positioned(
|
pub fn queue_pre_positioned(
|
||||||
&mut self,
|
&mut self,
|
||||||
glyphs: Vec<(PositionedGlyph<'font>, Color, FontId)>,
|
glyphs: Vec<SectionGlyph>,
|
||||||
bounds: Rect<f32>,
|
extra: Vec<Extra>,
|
||||||
z: f32,
|
bounds: Rect,
|
||||||
) {
|
) {
|
||||||
self.glyph_brush.queue_pre_positioned(glyphs, bounds, z)
|
self.glyph_brush.queue_pre_positioned(glyphs, extra, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retains the section in the cache as if it had been used in the last
|
/// Retains the section in the cache as if it had been used in the last
|
||||||
|
@ -94,7 +95,7 @@ impl<'font, H: BuildHasher> GlyphBrush<'font, H> {
|
||||||
section: S,
|
section: S,
|
||||||
custom_layout: &G,
|
custom_layout: &G,
|
||||||
) where
|
) where
|
||||||
S: Into<Cow<'a, VariedSection<'a>>>,
|
S: Into<Cow<'a, Section<'a>>>,
|
||||||
G: GlyphPositioner,
|
G: GlyphPositioner,
|
||||||
{
|
{
|
||||||
self.glyph_brush
|
self.glyph_brush
|
||||||
|
@ -109,110 +110,28 @@ impl<'font, H: BuildHasher> GlyphBrush<'font, H> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn keep_cached<'a, S>(&mut self, section: S)
|
pub fn keep_cached<'a, S>(&mut self, section: S)
|
||||||
where
|
where
|
||||||
S: Into<Cow<'a, VariedSection<'a>>>,
|
S: Into<Cow<'a, Section<'a>>>,
|
||||||
{
|
{
|
||||||
self.glyph_brush.keep_cached(section)
|
self.glyph_brush.keep_cached(section)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_queued(&mut self, context: &glow::Context) {
|
|
||||||
let pipeline = &mut self.pipeline;
|
|
||||||
|
|
||||||
let mut brush_action;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
brush_action = self.glyph_brush.process_queued(
|
|
||||||
|rect, tex_data| {
|
|
||||||
let offset = [rect.min.x as u16, rect.min.y as u16];
|
|
||||||
let size = [rect.width() as u16, rect.height() as u16];
|
|
||||||
|
|
||||||
pipeline.update_cache(context, offset, size, tex_data);
|
|
||||||
},
|
|
||||||
Instance::from,
|
|
||||||
);
|
|
||||||
|
|
||||||
match brush_action {
|
|
||||||
Ok(_) => break,
|
|
||||||
Err(BrushError::TextureTooSmall { suggested }) => {
|
|
||||||
// TODO: Obtain max texture dimensions
|
|
||||||
let max_image_dimension = 2048;
|
|
||||||
|
|
||||||
let (new_width, new_height) = if (suggested.0
|
|
||||||
> max_image_dimension
|
|
||||||
|| suggested.1 > max_image_dimension)
|
|
||||||
&& (self.glyph_brush.texture_dimensions().0
|
|
||||||
< max_image_dimension
|
|
||||||
|| self.glyph_brush.texture_dimensions().1
|
|
||||||
< max_image_dimension)
|
|
||||||
{
|
|
||||||
(max_image_dimension, max_image_dimension)
|
|
||||||
} else {
|
|
||||||
suggested
|
|
||||||
};
|
|
||||||
|
|
||||||
if log_enabled!(log::Level::Warn) {
|
|
||||||
warn!(
|
|
||||||
"Increasing glyph texture size {old:?} -> {new:?}. \
|
|
||||||
Consider building with `.initial_cache_size({new:?})` to avoid \
|
|
||||||
resizing",
|
|
||||||
old = self.glyph_brush.texture_dimensions(),
|
|
||||||
new = (new_width, new_height),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline
|
|
||||||
.increase_cache_size(context, new_width, new_height);
|
|
||||||
self.glyph_brush.resize_texture(new_width, new_height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match brush_action.unwrap() {
|
|
||||||
BrushAction::Draw(verts) => {
|
|
||||||
self.pipeline.upload(context, &verts);
|
|
||||||
}
|
|
||||||
BrushAction::ReDraw => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the available fonts.
|
/// Returns the available fonts.
|
||||||
///
|
///
|
||||||
/// The `FontId` corresponds to the index of the font data.
|
/// The `FontId` corresponds to the index of the font data.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn fonts(&self) -> &[Font<'_>] {
|
pub fn fonts(&self) -> &[F] {
|
||||||
self.glyph_brush.fonts()
|
self.glyph_brush.fonts()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an additional font to the one(s) initially added on build.
|
/// Adds an additional font to the one(s) initially added on build.
|
||||||
///
|
///
|
||||||
/// Returns a new [`FontId`](struct.FontId.html) to reference this font.
|
/// Returns a new [`FontId`](struct.FontId.html) to reference this font.
|
||||||
pub fn add_font_bytes<'a: 'font, B: Into<SharedBytes<'a>>>(
|
pub fn add_font(&mut self, font: F) -> FontId {
|
||||||
&mut self,
|
self.glyph_brush.add_font(font)
|
||||||
font_data: B,
|
|
||||||
) -> FontId {
|
|
||||||
self.glyph_brush.add_font_bytes(font_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds an additional font to the one(s) initially added on build.
|
|
||||||
///
|
|
||||||
/// Returns a new [`FontId`](struct.FontId.html) to reference this font.
|
|
||||||
pub fn add_font<'a: 'font>(&mut self, font_data: Font<'a>) -> FontId {
|
|
||||||
self.glyph_brush.add_font(font_data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'font, H: BuildHasher> GlyphBrush<'font, H> {
|
impl<F: Font + Sync, H: BuildHasher> GlyphBrush<F, H> {
|
||||||
fn new(
|
|
||||||
gl: &glow::Context,
|
|
||||||
raw_builder: glyph_brush::GlyphBrushBuilder<'font, H>,
|
|
||||||
) -> Self {
|
|
||||||
let glyph_brush = raw_builder.build();
|
|
||||||
let (cache_width, cache_height) = glyph_brush.texture_dimensions();
|
|
||||||
GlyphBrush {
|
|
||||||
pipeline: Pipeline::new(gl, cache_width, cache_height),
|
|
||||||
glyph_brush,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Draws all queued sections onto a render target.
|
/// Draws all queued sections onto a render target.
|
||||||
/// See [`queue`](struct.GlyphBrush.html#method.queue).
|
/// See [`queue`](struct.GlyphBrush.html#method.queue).
|
||||||
///
|
///
|
||||||
|
@ -276,6 +195,81 @@ impl<'font, H: BuildHasher> GlyphBrush<'font, H> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_queued(&mut self, context: &glow::Context) {
|
||||||
|
let pipeline = &mut self.pipeline;
|
||||||
|
|
||||||
|
let mut brush_action;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
brush_action = self.glyph_brush.process_queued(
|
||||||
|
|rect, tex_data| {
|
||||||
|
let offset = [rect.min[0] as u16, rect.min[1] as u16];
|
||||||
|
let size = [rect.width() as u16, rect.height() as u16];
|
||||||
|
|
||||||
|
pipeline.update_cache(context, offset, size, tex_data);
|
||||||
|
},
|
||||||
|
Instance::from_vertex,
|
||||||
|
);
|
||||||
|
|
||||||
|
match brush_action {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(BrushError::TextureTooSmall { suggested }) => {
|
||||||
|
// TODO: Obtain max texture dimensions
|
||||||
|
let max_image_dimension = 2048;
|
||||||
|
|
||||||
|
let (new_width, new_height) = if (suggested.0
|
||||||
|
> max_image_dimension
|
||||||
|
|| suggested.1 > max_image_dimension)
|
||||||
|
&& (self.glyph_brush.texture_dimensions().0
|
||||||
|
< max_image_dimension
|
||||||
|
|| self.glyph_brush.texture_dimensions().1
|
||||||
|
< max_image_dimension)
|
||||||
|
{
|
||||||
|
(max_image_dimension, max_image_dimension)
|
||||||
|
} else {
|
||||||
|
suggested
|
||||||
|
};
|
||||||
|
|
||||||
|
if log_enabled!(log::Level::Warn) {
|
||||||
|
warn!(
|
||||||
|
"Increasing glyph texture size {old:?} -> {new:?}. \
|
||||||
|
Consider building with `.initial_cache_size({new:?})` to avoid \
|
||||||
|
resizing",
|
||||||
|
old = self.glyph_brush.texture_dimensions(),
|
||||||
|
new = (new_width, new_height),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline
|
||||||
|
.increase_cache_size(context, new_width, new_height);
|
||||||
|
self.glyph_brush.resize_texture(new_width, new_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match brush_action.unwrap() {
|
||||||
|
BrushAction::Draw(verts) => {
|
||||||
|
self.pipeline.upload(context, &verts);
|
||||||
|
}
|
||||||
|
BrushAction::ReDraw => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Font, H: BuildHasher> GlyphBrush<F, H> {
|
||||||
|
fn new(
|
||||||
|
gl: &glow::Context,
|
||||||
|
raw_builder: glyph_brush::GlyphBrushBuilder<F, H>,
|
||||||
|
) -> Self {
|
||||||
|
let glyph_brush = raw_builder.build();
|
||||||
|
let (cache_width, cache_height) = glyph_brush.texture_dimensions();
|
||||||
|
|
||||||
|
GlyphBrush {
|
||||||
|
pipeline: Pipeline::new(gl, cache_width, cache_height),
|
||||||
|
glyph_brush,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to generate a generate a transform matrix.
|
/// Helper function to generate a generate a transform matrix.
|
||||||
|
@ -289,42 +283,42 @@ pub fn orthographic_projection(width: u32, height: u32) -> [f32; 16] {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'font, H: BuildHasher> GlyphCruncher<'font> for GlyphBrush<'font, H> {
|
impl<F: Font, H: BuildHasher> GlyphCruncher<F> for GlyphBrush<F, H> {
|
||||||
#[inline]
|
|
||||||
fn pixel_bounds_custom_layout<'a, S, L>(
|
|
||||||
&mut self,
|
|
||||||
section: S,
|
|
||||||
custom_layout: &L,
|
|
||||||
) -> Option<Rect<i32>>
|
|
||||||
where
|
|
||||||
L: GlyphPositioner + std::hash::Hash,
|
|
||||||
S: Into<Cow<'a, VariedSection<'a>>>,
|
|
||||||
{
|
|
||||||
self.glyph_brush
|
|
||||||
.pixel_bounds_custom_layout(section, custom_layout)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn glyphs_custom_layout<'a, 'b, S, L>(
|
fn glyphs_custom_layout<'a, 'b, S, L>(
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
section: S,
|
section: S,
|
||||||
custom_layout: &L,
|
custom_layout: &L,
|
||||||
) -> PositionedGlyphIter<'b, 'font>
|
) -> SectionGlyphIter<'b>
|
||||||
where
|
where
|
||||||
L: GlyphPositioner + std::hash::Hash,
|
L: GlyphPositioner + std::hash::Hash,
|
||||||
S: Into<Cow<'a, VariedSection<'a>>>,
|
S: Into<Cow<'a, Section<'a>>>,
|
||||||
{
|
{
|
||||||
self.glyph_brush
|
self.glyph_brush
|
||||||
.glyphs_custom_layout(section, custom_layout)
|
.glyphs_custom_layout(section, custom_layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fonts(&self) -> &[Font<'font>] {
|
fn glyph_bounds_custom_layout<'a, S, L>(
|
||||||
|
&mut self,
|
||||||
|
section: S,
|
||||||
|
custom_layout: &L,
|
||||||
|
) -> Option<Rect>
|
||||||
|
where
|
||||||
|
L: GlyphPositioner + std::hash::Hash,
|
||||||
|
S: Into<Cow<'a, Section<'a>>>,
|
||||||
|
{
|
||||||
|
self.glyph_brush
|
||||||
|
.glyph_bounds_custom_layout(section, custom_layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fonts(&self) -> &[F] {
|
||||||
self.glyph_brush.fonts()
|
self.glyph_brush.fonts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H> std::fmt::Debug for GlyphBrush<'_, H> {
|
impl<F, H> std::fmt::Debug for GlyphBrush<F, H> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "GlyphBrush")
|
write!(f, "GlyphBrush")
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
mod cache;
|
mod cache;
|
||||||
|
|
||||||
|
use crate::ab_glyph::{point, Rect};
|
||||||
use crate::Region;
|
use crate::Region;
|
||||||
use cache::Cache;
|
use cache::Cache;
|
||||||
|
|
||||||
use glow::HasContext;
|
use glow::HasContext;
|
||||||
use glyph_brush::rusttype::{point, Rect};
|
|
||||||
|
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
program: <glow::Context as HasContext>::Program,
|
program: <glow::Context as HasContext>::Program,
|
||||||
|
@ -212,19 +212,15 @@ unsafe impl bytemuck::Pod for Instance {}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
const INITIAL_AMOUNT: usize = 50_000;
|
const INITIAL_AMOUNT: usize = 50_000;
|
||||||
}
|
|
||||||
|
|
||||||
impl From<glyph_brush::GlyphVertex> for Instance {
|
pub fn from_vertex(
|
||||||
#[inline]
|
glyph_brush::GlyphVertex {
|
||||||
fn from(vertex: glyph_brush::GlyphVertex) -> Instance {
|
|
||||||
let glyph_brush::GlyphVertex {
|
|
||||||
mut tex_coords,
|
mut tex_coords,
|
||||||
pixel_coords,
|
pixel_coords,
|
||||||
bounds,
|
bounds,
|
||||||
color,
|
extra,
|
||||||
z,
|
}: glyph_brush::GlyphVertex,
|
||||||
} = vertex;
|
) -> Instance {
|
||||||
|
|
||||||
let gl_bounds = bounds;
|
let gl_bounds = bounds;
|
||||||
|
|
||||||
let mut gl_rect = Rect {
|
let mut gl_rect = Rect {
|
||||||
|
@ -262,11 +258,11 @@ impl From<glyph_brush::GlyphVertex> for Instance {
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance {
|
Instance {
|
||||||
left_top: [gl_rect.min.x, gl_rect.max.y, z],
|
left_top: [gl_rect.min.x, gl_rect.max.y, extra.z],
|
||||||
right_bottom: [gl_rect.max.x, gl_rect.min.y],
|
right_bottom: [gl_rect.max.x, gl_rect.min.y],
|
||||||
tex_left_top: [tex_coords.min.x, tex_coords.max.y],
|
tex_left_top: [tex_coords.min.x, tex_coords.max.y],
|
||||||
tex_right_bottom: [tex_coords.max.x, tex_coords.min.y],
|
tex_right_bottom: [tex_coords.max.x, tex_coords.min.y],
|
||||||
color,
|
color: extra.color,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue