diff --git a/Cargo.toml b/Cargo.toml index 04de150..a1fba94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] wgpu = "0.5" -glyph_brush = "0.6" +glyph_brush = "0.7" log = "0.4" zerocopy = "0.3" diff --git a/examples/clipping.rs b/examples/clipping.rs index 528d847..cc6b921 100644 --- a/examples/clipping.rs +++ b/examples/clipping.rs @@ -1,6 +1,7 @@ -use wgpu_glyph::{GlyphBrushBuilder, Region, Scale, Section}; +use std::error::Error; +use wgpu_glyph::{ab_glyph, GlyphBrushBuilder, Region, Section, Text}; -fn main() -> Result<(), String> { +fn main() -> Result<(), Box> { env_logger::init(); // Open window and create a surface @@ -51,9 +52,11 @@ fn main() -> Result<(), String> { ); // Prepare glyph_brush - let inconsolata: &[u8] = include_bytes!("Inconsolata-Regular.ttf"); - let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(inconsolata) - .expect("Load font") + let inconsolata = ab_glyph::FontArc::try_from_slice(include_bytes!( + "Inconsolata-Regular.ttf" + ))?; + + let mut glyph_brush = GlyphBrushBuilder::using_font(inconsolata) .build(&device, render_format); // Render loop @@ -118,11 +121,12 @@ fn main() -> Result<(), String> { } glyph_brush.queue(Section { - text: "Hello wgpu_glyph!", 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), + 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() }); @@ -138,11 +142,12 @@ fn main() -> Result<(), String> { .expect("Draw queued"); glyph_brush.queue(Section { - text: "Hello wgpu_glyph!", 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), + 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() }); diff --git a/examples/depth.rs b/examples/depth.rs index ed1e4cc..8368402 100644 --- a/examples/depth.rs +++ b/examples/depth.rs @@ -1,8 +1,9 @@ -use wgpu_glyph::{GlyphBrushBuilder, Scale, Section}; +use std::error::Error; +use wgpu_glyph::{ab_glyph, GlyphBrushBuilder, Section, Text}; const FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8UnormSrgb; -fn main() -> Result<(), String> { +fn main() -> Result<(), Box> { env_logger::init(); // Open window and create a surface @@ -52,10 +53,11 @@ fn main() -> Result<(), String> { create_frame_views(&device, &surface, size); // Prepare glyph_brush - let inconsolata: &[u8] = include_bytes!("Inconsolata-Regular.ttf"); + let inconsolata = ab_glyph::FontArc::try_from_slice(include_bytes!( + "Inconsolata-Regular.ttf" + ))?; - let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(inconsolata) - .expect("Load fonts") + let mut glyph_brush = GlyphBrushBuilder::using_font(inconsolata) .depth_stencil_state(wgpu::DepthStencilStateDescriptor { format: wgpu::TextureFormat::Depth32Float, depth_write_enabled: true, @@ -130,10 +132,11 @@ fn main() -> Result<(), String> { // Depth buffer will make it appear on top. glyph_brush.queue(Section { screen_position: (30.0, 30.0), - text: "On top", - scale: Scale::uniform(95.0), - color: [0.8, 0.8, 0.8, 1.0], - z: 0.9, + text: vec![Text::default() + .with_text("On top") + .with_scale(95.0) + .with_color([0.8, 0.8, 0.8, 1.0]) + .with_z(0.9)], ..Section::default() }); @@ -142,12 +145,15 @@ fn main() -> Result<(), String> { // previous queued text. glyph_brush.queue(Section { bounds: (size.width as f32, size.height as f32), - text: &include_str!("lipsum.txt") - .replace("\n\n", "") - .repeat(10), - scale: Scale::uniform(30.0), - color: [0.05, 0.05, 0.1, 1.0], - z: 0.2, + text: vec![Text::default() + .with_text( + &include_str!("lipsum.txt") + .replace("\n\n", "") + .repeat(10), + ) + .with_scale(30.0) + .with_color([0.05, 0.05, 0.1, 1.0]) + .with_z(0.2)], ..Section::default() }); diff --git a/examples/hello.rs b/examples/hello.rs index 4de7ed4..aa20426 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,6 +1,7 @@ -use wgpu_glyph::{GlyphBrushBuilder, Scale, Section}; +use std::error::Error; +use wgpu_glyph::{ab_glyph, GlyphBrushBuilder, Section, Text}; -fn main() -> Result<(), String> { +fn main() -> Result<(), Box> { env_logger::init(); // Open window and create a surface @@ -51,9 +52,11 @@ fn main() -> Result<(), String> { ); // Prepare glyph_brush - let inconsolata: &[u8] = include_bytes!("Inconsolata-Regular.ttf"); - let mut glyph_brush = GlyphBrushBuilder::using_font_bytes(inconsolata) - .expect("Load fonts") + let inconsolata = ab_glyph::FontArc::try_from_slice(include_bytes!( + "Inconsolata-Regular.ttf" + ))?; + + let mut glyph_brush = GlyphBrushBuilder::using_font(inconsolata) .build(&device, render_format); // Render loop @@ -118,20 +121,22 @@ fn main() -> Result<(), String> { } glyph_brush.queue(Section { - text: "Hello wgpu_glyph!", 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), + 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() }); glyph_brush.queue(Section { - text: "Hello wgpu_glyph!", 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), + 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() }); diff --git a/src/builder.rs b/src/builder.rs index 937a3ca..d694fbd 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,22 +1,22 @@ use core::hash::BuildHasher; +use glyph_brush::ab_glyph::Font; use glyph_brush::delegate_glyph_brush_builder_fns; -use glyph_brush::{rusttype, DefaultSectionHasher}; -use rusttype::{Error, Font, SharedBytes}; +use glyph_brush::DefaultSectionHasher; use super::GlyphBrush; /// Builder for a [`GlyphBrush`](struct.GlyphBrush.html). -pub struct GlyphBrushBuilder<'a, D, H = DefaultSectionHasher> { - inner: glyph_brush::GlyphBrushBuilder<'a, H>, +pub struct GlyphBrushBuilder { + inner: glyph_brush::GlyphBrushBuilder, texture_filter_method: wgpu::FilterMode, depth: D, } -impl<'a, H> From> - for GlyphBrushBuilder<'a, (), H> +impl From> + for GlyphBrushBuilder<(), F, H> { - fn from(inner: glyph_brush::GlyphBrushBuilder<'a, H>) -> Self { + fn from(inner: glyph_brush::GlyphBrushBuilder) -> Self { GlyphBrushBuilder { inner, texture_filter_method: wgpu::FilterMode::Linear, @@ -25,41 +25,15 @@ impl<'a, H> From> } } -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>>( - font_0_data: B, - ) -> Result { - let font = Font::from_bytes(font_0_data)?; - - Ok(Self::using_font(font)) - } - - #[inline] - pub fn using_fonts_bytes(font_data: V) -> Result - where - B: Into>, - V: Into>, - { - let fonts = font_data - .into() - .into_iter() - .map(Font::from_bytes) - .collect::, Error>>()?; - - Ok(Self::using_fonts(fonts)) - } - +impl GlyphBrushBuilder<(), ()> { /// Specifies the default font used to render glyphs. /// Referenced with `FontId(0)`, which is default. #[inline] - pub fn using_font(font_0: Font<'a>) -> Self { - Self::using_fonts(vec![font_0]) + pub fn using_font(font: F) -> GlyphBrushBuilder<(), F> { + Self::using_fonts(vec![font]) } - pub fn using_fonts>>>(fonts: V) -> Self { + pub fn using_fonts(fonts: Vec) -> GlyphBrushBuilder<(), F> { GlyphBrushBuilder { inner: glyph_brush::GlyphBrushBuilder::using_fonts(fonts), texture_filter_method: wgpu::FilterMode::Linear, @@ -68,9 +42,26 @@ impl<'a> GlyphBrushBuilder<'a, ()> { } } -impl<'a, D, H: BuildHasher> GlyphBrushBuilder<'a, D, H> { +impl GlyphBrushBuilder { 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. + /// + /// By default, this feature is __enabled__. + /// + /// # 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 texture filtering method. pub fn texture_filter_method( mut self, @@ -90,7 +81,7 @@ impl<'a, D, H: BuildHasher> GlyphBrushBuilder<'a, D, H> { pub fn section_hasher( self, section_hasher: T, - ) -> GlyphBrushBuilder<'a, D, T> { + ) -> GlyphBrushBuilder { GlyphBrushBuilder { inner: self.inner.section_hasher(section_hasher), texture_filter_method: self.texture_filter_method, @@ -102,7 +93,7 @@ impl<'a, D, H: BuildHasher> GlyphBrushBuilder<'a, D, H> { pub fn depth_stencil_state( self, depth_stencil_state: wgpu::DepthStencilStateDescriptor, - ) -> GlyphBrushBuilder<'a, wgpu::DepthStencilStateDescriptor, H> { + ) -> GlyphBrushBuilder { GlyphBrushBuilder { inner: self.inner, texture_filter_method: self.texture_filter_method, @@ -111,15 +102,15 @@ impl<'a, D, H: BuildHasher> GlyphBrushBuilder<'a, D, H> { } } -impl<'a, H: BuildHasher> GlyphBrushBuilder<'a, (), H> { +impl GlyphBrushBuilder<(), F, H> { /// Builds a `GlyphBrush` using the given `wgpu::Device` that can render /// text for texture views with the given `render_format`. pub fn build( self, device: &wgpu::Device, render_format: wgpu::TextureFormat, - ) -> GlyphBrush<'a, (), H> { - GlyphBrush::<(), H>::new( + ) -> GlyphBrush<(), F, H> { + GlyphBrush::<(), F, H>::new( device, self.texture_filter_method, render_format, @@ -128,8 +119,8 @@ impl<'a, H: BuildHasher> GlyphBrushBuilder<'a, (), H> { } } -impl<'a, H: BuildHasher> - GlyphBrushBuilder<'a, wgpu::DepthStencilStateDescriptor, H> +impl + GlyphBrushBuilder { /// Builds a `GlyphBrush` using the given `wgpu::Device` that can render /// text for texture views with the given `render_format`. @@ -137,8 +128,8 @@ impl<'a, H: BuildHasher> self, device: &wgpu::Device, render_format: wgpu::TextureFormat, - ) -> GlyphBrush<'a, wgpu::DepthStencilStateDescriptor, H> { - GlyphBrush::::new( + ) -> GlyphBrush { + GlyphBrush::::new( device, self.texture_filter_method, render_format, diff --git a/src/lib.rs b/src/lib.rs index e8a8407..d2914e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,30 +12,30 @@ pub use region::Region; use pipeline::{Instance, Pipeline}; pub use builder::GlyphBrushBuilder; +pub use glyph_brush::ab_glyph; pub use glyph_brush::{ - rusttype::{self, Font, Point, PositionedGlyph, Rect, Scale, SharedBytes}, - BuiltInLineBreaker, FontId, FontMap, GlyphCruncher, GlyphPositioner, - HorizontalAlign, Layout, LineBreak, LineBreaker, OwnedSectionText, - OwnedVariedSection, PositionedGlyphIter, Section, SectionGeometry, - SectionText, VariedSection, VerticalAlign, + BuiltInLineBreaker, Extra, FontId, GlyphCruncher, GlyphPositioner, + HorizontalAlign, Layout, LineBreak, LineBreaker, Section, SectionGeometry, + SectionGlyph, SectionGlyphIter, SectionText, Text, VerticalAlign, }; +use ab_glyph::{Font, Rect}; use core::hash::BuildHasher; use std::borrow::Cow; -use glyph_brush::{BrushAction, BrushError, Color, DefaultSectionHasher}; +use glyph_brush::{BrushAction, BrushError, DefaultSectionHasher}; use log::{log_enabled, warn}; /// Object allowing glyph drawing, containing cache state. Manages glyph positioning cacheing, /// glyph draw caching & efficient GPU texture cache updating and re-sizing on demand. /// /// Build using a [`GlyphBrushBuilder`](struct.GlyphBrushBuilder.html). -pub struct GlyphBrush<'font, Depth, H = DefaultSectionHasher> { +pub struct GlyphBrush { pipeline: Pipeline, - glyph_brush: glyph_brush::GlyphBrush<'font, Instance, H>, + glyph_brush: glyph_brush::GlyphBrush, } -impl<'font, Depth, H: BuildHasher> GlyphBrush<'font, Depth, H> { +impl GlyphBrush { /// Queues a section/layout to be drawn by the next call of /// [`draw_queued`](struct.GlyphBrush.html#method.draw_queued). Can be /// called multiple times to queue multiple sections for drawing. @@ -44,7 +44,7 @@ impl<'font, Depth, H: BuildHasher> GlyphBrush<'font, Depth, H> { #[inline] pub fn queue<'a, S>(&mut self, section: S) where - S: Into>>, + S: Into>>, { self.glyph_brush.queue(section) } @@ -65,7 +65,7 @@ impl<'font, Depth, H: BuildHasher> GlyphBrush<'font, Depth, H> { custom_layout: &G, ) where G: GlyphPositioner, - S: Into>>, + S: Into>>, { self.glyph_brush.queue_custom_layout(section, custom_layout) } @@ -76,11 +76,11 @@ impl<'font, Depth, H: BuildHasher> GlyphBrush<'font, Depth, H> { #[inline] pub fn queue_pre_positioned( &mut self, - glyphs: Vec<(PositionedGlyph<'font>, Color, FontId)>, - bounds: Rect, - z: f32, + glyphs: Vec, + extra: Vec, + 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 @@ -94,7 +94,7 @@ impl<'font, Depth, H: BuildHasher> GlyphBrush<'font, Depth, H> { section: S, custom_layout: &G, ) where - S: Into>>, + S: Into>>, G: GlyphPositioner, { self.glyph_brush @@ -109,11 +109,32 @@ impl<'font, Depth, H: BuildHasher> GlyphBrush<'font, Depth, H> { #[inline] pub fn keep_cached<'a, S>(&mut self, section: S) where - S: Into>>, + S: Into>>, { self.glyph_brush.keep_cached(section) } + /// Returns the available fonts. + /// + /// The `FontId` corresponds to the index of the font data. + #[inline] + pub fn fonts(&self) -> &[F] { + self.glyph_brush.fonts() + } + + /// 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(&mut self, font: F) -> FontId { + self.glyph_brush.add_font(font) + } +} + +impl GlyphBrush +where + F: Font + Sync, + H: BuildHasher, +{ fn process_queued( &mut self, device: &wgpu::Device, @@ -126,13 +147,13 @@ impl<'font, Depth, H: BuildHasher> GlyphBrush<'font, Depth, H> { loop { brush_action = self.glyph_brush.process_queued( |rect, tex_data| { - let offset = [rect.min.x as u16, rect.min.y as u16]; + 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(device, encoder, offset, size, tex_data); }, - Instance::from, + Instance::from_vertex, ); match brush_action { @@ -178,39 +199,14 @@ impl<'font, Depth, H: BuildHasher> GlyphBrush<'font, Depth, H> { BrushAction::ReDraw => {} }; } - - /// Returns the available fonts. - /// - /// The `FontId` corresponds to the index of the font data. - #[inline] - pub fn fonts(&self) -> &[Font<'_>] { - self.glyph_brush.fonts() - } - - /// 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_bytes<'a: 'font, B: Into>>( - &mut self, - 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 GlyphBrush<(), F, H> { fn new( device: &wgpu::Device, filter_mode: wgpu::FilterMode, render_format: wgpu::TextureFormat, - raw_builder: glyph_brush::GlyphBrushBuilder<'font, H>, + raw_builder: glyph_brush::GlyphBrushBuilder, ) -> Self { let glyph_brush = raw_builder.build(); let (cache_width, cache_height) = glyph_brush.texture_dimensions(); @@ -306,15 +302,15 @@ impl<'font, H: BuildHasher> GlyphBrush<'font, (), H> { } } -impl<'font, H: BuildHasher> - GlyphBrush<'font, wgpu::DepthStencilStateDescriptor, H> +impl + GlyphBrush { fn new( device: &wgpu::Device, filter_mode: wgpu::FilterMode, render_format: wgpu::TextureFormat, depth_stencil_state: wgpu::DepthStencilStateDescriptor, - raw_builder: glyph_brush::GlyphBrushBuilder<'font, H>, + raw_builder: glyph_brush::GlyphBrushBuilder, ) -> Self { let glyph_brush = raw_builder.build(); let (cache_width, cache_height) = glyph_brush.texture_dimensions(); @@ -440,44 +436,42 @@ pub fn orthographic_projection(width: u32, height: u32) -> [f32; 16] { ] } -impl<'font, D, H: BuildHasher> GlyphCruncher<'font> - for GlyphBrush<'font, D, H> -{ +impl GlyphCruncher for GlyphBrush { #[inline] - fn pixel_bounds_custom_layout<'a, S, L>( - &mut self, + fn glyphs_custom_layout<'a, 'b, S, L>( + &'b mut self, section: S, custom_layout: &L, - ) -> Option> + ) -> SectionGlyphIter<'b> where L: GlyphPositioner + std::hash::Hash, - S: Into>>, + S: Into>>, { self.glyph_brush - .pixel_bounds_custom_layout(section, custom_layout) + .glyphs_custom_layout(section, custom_layout) } #[inline] - fn glyphs_custom_layout<'a, 'b, S, L>( - &'b mut self, + fn fonts(&self) -> &[F] { + self.glyph_brush.fonts() + } + + #[inline] + fn glyph_bounds_custom_layout<'a, S, L>( + &mut self, section: S, custom_layout: &L, - ) -> PositionedGlyphIter<'b, 'font> + ) -> Option where L: GlyphPositioner + std::hash::Hash, - S: Into>>, + S: Into>>, { self.glyph_brush - .glyphs_custom_layout(section, custom_layout) - } - - #[inline] - fn fonts(&self) -> &[Font<'font>] { - self.glyph_brush.fonts() + .glyph_bounds_custom_layout(section, custom_layout) } } -impl std::fmt::Debug for GlyphBrush<'_, H> { +impl std::fmt::Debug for GlyphBrush { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "GlyphBrush") diff --git a/src/pipeline.rs b/src/pipeline.rs index 443def2..a912a05 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -3,7 +3,7 @@ mod cache; use crate::Region; use cache::Cache; -use glyph_brush::rusttype::{point, Rect}; +use glyph_brush::ab_glyph::{point, Rect}; use std::marker::PhantomData; use std::mem; use zerocopy::AsBytes; @@ -442,19 +442,15 @@ pub struct Instance { impl Instance { const INITIAL_AMOUNT: usize = 50_000; -} -impl From for Instance { - #[inline] - fn from(vertex: glyph_brush::GlyphVertex) -> Instance { - let glyph_brush::GlyphVertex { + pub fn from_vertex( + glyph_brush::GlyphVertex { mut tex_coords, pixel_coords, bounds, - color, - z, - } = vertex; - + extra, + }: glyph_brush::GlyphVertex, + ) -> Instance { let gl_bounds = bounds; let mut gl_rect = Rect { @@ -492,11 +488,11 @@ impl From for 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], tex_left_top: [tex_coords.min.x, tex_coords.max.y], tex_right_bottom: [tex_coords.max.x, tex_coords.min.y], - color, + color: extra.color, } } }