glyph_brush/glyph_brush/
builder.rs

1use crate::{DefaultSectionHasher, Font, FontId, GlyphBrush};
2use glyph_brush_draw_cache::*;
3use glyph_brush_layout::ab_glyph::*;
4use std::hash::BuildHasher;
5
6/// Builder for a [`GlyphBrush`].
7///
8/// # Example
9/// ```
10/// use glyph_brush::{ab_glyph::FontArc, GlyphBrush, GlyphBrushBuilder};
11/// # type Vertex = ();
12///
13/// let dejavu = FontArc::try_from_slice(include_bytes!("../../../fonts/DejaVuSans.ttf")).unwrap();
14/// let mut glyph_brush: GlyphBrush<Vertex> = GlyphBrushBuilder::using_font(dejavu).build();
15/// ```
16#[non_exhaustive]
17pub struct GlyphBrushBuilder<F = FontArc, H = DefaultSectionHasher> {
18    pub font_data: Vec<F>,
19    pub cache_glyph_positioning: bool,
20    pub cache_redraws: bool,
21    pub section_hasher: H,
22    pub draw_cache_builder: DrawCacheBuilder,
23}
24
25impl GlyphBrushBuilder<()> {
26    /// Create a new builder with multiple fonts.
27    pub fn using_fonts<F: Font>(fonts: Vec<F>) -> GlyphBrushBuilder<F> {
28        Self::without_fonts().replace_fonts(|_| fonts)
29    }
30
31    /// Create a new builder with multiple fonts.
32    #[inline]
33    pub fn using_font<F: Font>(font: F) -> GlyphBrushBuilder<F> {
34        Self::using_fonts(vec![font])
35    }
36
37    /// Create a new builder without any fonts.
38    pub fn without_fonts() -> GlyphBrushBuilder<()> {
39        GlyphBrushBuilder {
40            font_data: Vec::new(),
41            cache_glyph_positioning: true,
42            cache_redraws: true,
43            section_hasher: DefaultSectionHasher::default(),
44            draw_cache_builder: DrawCache::builder()
45                .dimensions(256, 256)
46                .scale_tolerance(0.5)
47                .position_tolerance(0.1)
48                .align_4x4(false),
49        }
50    }
51}
52
53impl<F, H> GlyphBrushBuilder<F, H> {
54    /// Consume all builder fonts a replace with new fonts returned by the input function.
55    ///
56    /// Generally only makes sense when wanting to change fonts after calling
57    /// [`GlyphBrush::to_builder`](struct.GlyphBrush.html#method.to_builder).
58    ///
59    /// # Example
60    /// ```
61    /// # use glyph_brush::{*, ab_glyph::*};
62    /// # type Vertex = ();
63    /// # let open_sans = FontArc::try_from_slice(&include_bytes!("../../../fonts/DejaVuSans.ttf")[..]).unwrap();
64    /// # let deja_vu_sans = open_sans.clone();
65    /// let two_font_brush: GlyphBrush<Vertex>
66    ///     = GlyphBrushBuilder::using_fonts(vec![open_sans, deja_vu_sans]).build();
67    ///
68    /// let one_font_brush: GlyphBrush<FontRef<'static>, Vertex> = two_font_brush
69    ///     .to_builder()
70    ///     .replace_fonts(|mut fonts| {
71    ///         // remove open_sans, leaving just deja_vu as FontId(0)
72    ///         fonts.remove(0);
73    ///         fonts
74    ///     })
75    ///     .build();
76    ///
77    /// assert_eq!(one_font_brush.fonts().len(), 1);
78    /// assert_eq!(two_font_brush.fonts().len(), 2);
79    /// ```
80    pub fn replace_fonts<F2: Font, V, NF>(self, font_fn: NF) -> GlyphBrushBuilder<F2, H>
81    where
82        V: Into<Vec<F2>>,
83        NF: FnOnce(Vec<F>) -> V,
84    {
85        let font_data = font_fn(self.font_data).into();
86        GlyphBrushBuilder {
87            font_data,
88            cache_glyph_positioning: self.cache_glyph_positioning,
89            cache_redraws: self.cache_redraws,
90            section_hasher: self.section_hasher,
91            draw_cache_builder: self.draw_cache_builder,
92        }
93    }
94}
95
96impl<F: Font, H: BuildHasher> GlyphBrushBuilder<F, H> {
97    /// Adds additional fonts to the one added in [`using_font`](#method.using_font).
98    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
99    pub fn add_font<I: Into<F>>(&mut self, font_data: I) -> FontId {
100        self.font_data.push(font_data.into());
101        FontId(self.font_data.len() - 1)
102    }
103
104    /// Initial size of 2D texture used as a gpu cache, pixels (width, height).
105    /// The GPU cache will dynamically quadruple in size whenever the current size
106    /// is insufficient.
107    ///
108    /// Defaults to `(256, 256)`
109    pub fn initial_cache_size(mut self, (w, h): (u32, u32)) -> Self {
110        self.draw_cache_builder = self.draw_cache_builder.dimensions(w, h);
111        self
112    }
113
114    /// Sets the maximum allowed difference in scale used for judging whether to reuse an
115    /// existing glyph in the GPU cache.
116    ///
117    /// Defaults to `0.5`
118    ///
119    /// See docs for `glyph_brush_draw_cache::DrawCache`
120    pub fn draw_cache_scale_tolerance(mut self, tolerance: f32) -> Self {
121        self.draw_cache_builder = self.draw_cache_builder.scale_tolerance(tolerance);
122        self
123    }
124
125    /// Sets the maximum allowed difference in subpixel position used for judging whether
126    /// to reuse an existing glyph in the GPU cache. Anything greater than or equal to
127    /// 1.0 means "don't care".
128    ///
129    /// Defaults to `0.1`
130    ///
131    /// See docs for `glyph_brush_draw_cache::DrawCache`
132    pub fn draw_cache_position_tolerance(mut self, tolerance: f32) -> Self {
133        self.draw_cache_builder = self.draw_cache_builder.position_tolerance(tolerance);
134        self
135    }
136
137    /// When multiple CPU cores are available spread draw-cache work across all cores.
138    ///
139    /// Defaults to `true`.
140    pub fn multithread(mut self, multithread: bool) -> Self {
141        self.draw_cache_builder = self.draw_cache_builder.multithread(multithread);
142        self
143    }
144
145    /// Align glyphs in texture cache to 4x4 texel boundaries.
146    ///
147    /// If your backend requires texture updates to be aligned to 4x4 texel
148    /// boundaries (e.g. WebGL), this should be set to `true`.
149    ///
150    /// Defaults to `false`
151    ///
152    /// See docs for `glyph_brush_draw_cache::DrawCache`
153    pub fn draw_cache_align_4x4(mut self, align: bool) -> Self {
154        self.draw_cache_builder = self.draw_cache_builder.align_4x4(align);
155        self
156    }
157
158    /// Sets whether perform the calculation of glyph positioning according to the layout
159    /// every time, or use a cached result if the input `Section` and `GlyphPositioner` are the
160    /// same hash as a previous call.
161    ///
162    /// Improves performance. Should only disable if using a custom GlyphPositioner that is
163    /// impure according to it's inputs, so caching a previous call is not desired. Disabling
164    /// also disables [`cache_redraws`](#method.cache_redraws).
165    ///
166    /// Defaults to `true`
167    pub fn cache_glyph_positioning(mut self, cache: bool) -> Self {
168        self.cache_glyph_positioning = cache;
169        self
170    }
171
172    /// Sets optimising vertex drawing by reusing the last draw requesting an identical draw queue.
173    /// Will result in the usage of [`BrushAction::ReDraw`](enum.BrushAction.html#variant.ReDraw).
174    ///
175    /// Improves performance. Is disabled if
176    /// [`cache_glyph_positioning`](#method.cache_glyph_positioning) is disabled.
177    ///
178    /// Defaults to `true`
179    pub fn cache_redraws(mut self, cache_redraws: bool) -> Self {
180        self.cache_redraws = cache_redraws;
181        self
182    }
183
184    /// Sets the section hasher. [`GlyphBrush`] cannot handle absolute section hash collisions
185    /// so use a good hash algorithm.
186    ///
187    /// This hasher is used to distinguish sections, rather than for hashmap internal use.
188    ///
189    /// Defaults to [xxHash](https://docs.rs/twox-hash).
190    ///
191    /// # Example
192    /// ```
193    /// # use glyph_brush::{ab_glyph::*, GlyphBrushBuilder};
194    /// # let some_font = FontArc::try_from_slice(include_bytes!("../../../fonts/DejaVuSans.ttf")).unwrap();
195    /// # type SomeOtherBuildHasher = glyph_brush::DefaultSectionHasher;
196    /// GlyphBrushBuilder::using_font(some_font)
197    ///     .section_hasher(SomeOtherBuildHasher::default())
198    ///     // ...
199    /// # ;
200    /// ```
201    pub fn section_hasher<T: BuildHasher>(self, section_hasher: T) -> GlyphBrushBuilder<F, T> {
202        GlyphBrushBuilder {
203            section_hasher,
204            font_data: self.font_data,
205            cache_glyph_positioning: self.cache_glyph_positioning,
206            cache_redraws: self.cache_redraws,
207            draw_cache_builder: self.draw_cache_builder,
208        }
209    }
210
211    /// Builds a [`GlyphBrush`].
212    ///
213    /// If type inference fails try declaring the types `V` & `X`.
214    /// See [`GlyphBrush` generic types](struct.GlyphBrush.html#generic-types).
215    /// ```
216    /// # use glyph_brush::{ab_glyph::*, GlyphBrushBuilder};
217    /// # let some_font = FontArc::try_from_slice(include_bytes!("../../../fonts/DejaVuSans.ttf")).unwrap();
218    /// # type SomeOtherBuildHasher = glyph_brush::DefaultSectionHasher;
219    /// # type Vertex = ();
220    /// let glyph_brush = GlyphBrushBuilder::using_font(some_font)
221    ///     .build::<Vertex, glyph_brush::Extra>();
222    /// ```
223    pub fn build<V, X>(self) -> GlyphBrush<V, X, F, H> {
224        GlyphBrush {
225            fonts: self.font_data,
226            texture_cache: self.draw_cache_builder.build(),
227
228            last_draw: <_>::default(),
229            section_buffer: <_>::default(),
230            calculate_glyph_cache: <_>::default(),
231
232            last_frame_seq_id_sections: <_>::default(),
233            frame_seq_id_sections: <_>::default(),
234
235            keep_in_cache: <_>::default(),
236
237            cache_glyph_positioning: self.cache_glyph_positioning,
238            cache_redraws: self.cache_redraws && self.cache_glyph_positioning,
239
240            section_hasher: self.section_hasher,
241
242            last_pre_positioned: <_>::default(),
243            pre_positioned: <_>::default(),
244        }
245    }
246
247    /// Rebuilds an existing [`GlyphBrush`] with this builder's properties. This will clear all
248    /// caches and queues.
249    ///
250    /// # Example
251    /// ```
252    /// # use glyph_brush::{*, ab_glyph::*};
253    /// # let sans = FontArc::try_from_slice(include_bytes!("../../../fonts/DejaVuSans.ttf")).unwrap();
254    /// # type Vertex = ();
255    /// let mut glyph_brush: GlyphBrush<Vertex> = GlyphBrushBuilder::using_font(sans).build();
256    /// assert_eq!(glyph_brush.texture_dimensions(), (256, 256));
257    ///
258    /// // Use a new builder to rebuild the brush with a smaller initial cache size
259    /// glyph_brush.to_builder().initial_cache_size((64, 64)).rebuild(&mut glyph_brush);
260    /// assert_eq!(glyph_brush.texture_dimensions(), (64, 64));
261    /// ```
262    pub fn rebuild<V, X>(self, brush: &mut GlyphBrush<V, X, F, H>) {
263        *brush = self.build();
264    }
265}
266
267/// Macro to delegate builder methods to an inner `glyph_brush::GlyphBrushBuilder`
268///
269/// Implements:
270/// * `add_font_bytes`
271/// * `add_font`
272/// * `initial_cache_size`
273/// * `draw_cache_scale_tolerance`
274/// * `draw_cache_position_tolerance`
275/// * `draw_cache_align_4x4`
276/// * `cache_glyph_positioning`
277/// * `cache_redraws`
278///
279/// # Example
280/// ```
281/// use glyph_brush::{ab_glyph::*, *};
282/// use std::hash::BuildHasher;
283///
284/// # pub struct DownstreamGlyphBrush;
285/// pub struct DownstreamGlyphBrushBuilder<F, H> {
286///     inner: glyph_brush::GlyphBrushBuilder<F, H>,
287///     some_config: bool,
288/// }
289///
290/// impl<F: Font, H: BuildHasher> DownstreamGlyphBrushBuilder<F, H> {
291///     delegate_glyph_brush_builder_fns!(inner);
292///
293///     /// Sets some downstream configuration
294///     pub fn some_config(mut self, some_config: bool) -> Self {
295///         self.some_config = some_config;
296///         self
297///     }
298///
299///     // Must be manually delegated
300///     pub fn section_hasher<T: BuildHasher>(
301///         self,
302///         section_hasher: T,
303///     ) -> DownstreamGlyphBrushBuilder<F, T> {
304///         DownstreamGlyphBrushBuilder {
305///             inner: self.inner.section_hasher(section_hasher),
306///             some_config: self.some_config,
307///         }
308///     }
309///
310///     pub fn build(self) -> DownstreamGlyphBrush {
311///         // ...
312///         # DownstreamGlyphBrush
313///     }
314/// }
315/// # fn main() {}
316/// ```
317#[macro_export]
318macro_rules! delegate_glyph_brush_builder_fns {
319    ($inner:ident) => {
320        /// Adds additional fonts to the one added in [`using_font`](#method.using_font).
321        /// Returns a [`FontId`](struct.FontId.html) to reference this font.
322        pub fn add_font(&mut self, font_data: F) -> $crate::FontId {
323            self.$inner.add_font(font_data)
324        }
325
326        /// Initial size of 2D texture used as a gpu cache, pixels (width, height).
327        /// The GPU cache will dynamically quadruple in size whenever the current size
328        /// is insufficient.
329        ///
330        /// Defaults to `(256, 256)`
331        pub fn initial_cache_size(mut self, size: (u32, u32)) -> Self {
332            self.$inner = self.$inner.initial_cache_size(size);
333            self
334        }
335
336        /// Sets the maximum allowed difference in scale used for judging whether to reuse an
337        /// existing glyph in the GPU cache.
338        ///
339        /// Defaults to `0.5`
340        ///
341        /// See docs for `glyph_brush_draw_cache::DrawCache`
342        pub fn draw_cache_scale_tolerance(mut self, tolerance: f32) -> Self {
343            self.$inner = self.$inner.draw_cache_scale_tolerance(tolerance);
344            self
345        }
346
347        /// Sets the maximum allowed difference in subpixel position used for judging whether
348        /// to reuse an existing glyph in the GPU cache. Anything greater than or equal to
349        /// 1.0 means "don't care".
350        ///
351        /// Defaults to `0.1`
352        ///
353        /// See docs for `glyph_brush_draw_cache::DrawCache`
354        pub fn draw_cache_position_tolerance(mut self, tolerance: f32) -> Self {
355            self.$inner = self.$inner.draw_cache_position_tolerance(tolerance);
356            self
357        }
358
359        /// Align glyphs in texture cache to 4x4 texel boundaries.
360        ///
361        /// If your backend requires texture updates to be aligned to 4x4 texel
362        /// boundaries (e.g. WebGL), this should be set to `true`.
363        ///
364        /// Defaults to `false`
365        ///
366        /// See docs for `glyph_brush_draw_cache::DrawCache`
367        pub fn draw_cache_align_4x4(mut self, b: bool) -> Self {
368            self.$inner = self.$inner.draw_cache_align_4x4(b);
369            self
370        }
371
372        /// Sets whether perform the calculation of glyph positioning according to the layout
373        /// every time, or use a cached result if the input `Section` and `GlyphPositioner` are the
374        /// same hash as a previous call.
375        ///
376        /// Improves performance. Should only disable if using a custom GlyphPositioner that is
377        /// impure according to it's inputs, so caching a previous call is not desired. Disabling
378        /// also disables [`cache_redraws`](#method.cache_redraws).
379        ///
380        /// Defaults to `true`
381        pub fn cache_glyph_positioning(mut self, cache: bool) -> Self {
382            self.$inner = self.$inner.cache_glyph_positioning(cache);
383            self
384        }
385
386        /// Sets optimising drawing by reusing the last draw requesting an identical draw queue.
387        ///
388        /// Improves performance. Is disabled if
389        /// [`cache_glyph_positioning`](#method.cache_glyph_positioning) is disabled.
390        ///
391        /// Defaults to `true`
392        pub fn cache_redraws(mut self, cache: bool) -> Self {
393            self.$inner = self.$inner.cache_redraws(cache);
394            self
395        }
396    };
397}