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}