summaryrefslogtreecommitdiffstats
path: root/wgpu/src/text.rs
blob: d6565195d94071d5897f50cb00d260a3ee25e6f1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
mod font;

use crate::Transformation;
use std::cell::RefCell;

pub struct Pipeline {
    draw_brush: wgpu_glyph::GlyphBrush<'static, ()>,
    measure_brush: RefCell<glyph_brush::GlyphBrush<'static, ()>>,
}

impl Pipeline {
    pub fn new(device: &mut wgpu::Device) -> Self {
        // TODO: Font customization
        let font_source = font::Source::new();

        let default_font = font_source
            .load(&[font::Family::SansSerif, font::Family::Serif])
            .expect("Find sans-serif or serif font");

        let mono_font = font_source
            .load(&[font::Family::Monospace])
            .expect("Find monospace font");

        let draw_brush =
            wgpu_glyph::GlyphBrushBuilder::using_fonts_bytes(vec![
                default_font.clone(),
                mono_font,
            ])
            .initial_cache_size((2048, 2048))
            .build(device, wgpu::TextureFormat::Bgra8UnormSrgb);

        let measure_brush =
            glyph_brush::GlyphBrushBuilder::using_font_bytes(default_font)
                .build();

        Pipeline {
            draw_brush,
            measure_brush: RefCell::new(measure_brush),
        }
    }

    pub fn overlay_font(&self) -> wgpu_glyph::FontId {
        wgpu_glyph::FontId(1)
    }

    pub fn queue(&mut self, section: wgpu_glyph::Section) {
        self.draw_brush.queue(section);
    }

    pub fn draw_queued(
        &mut self,
        device: &mut wgpu::Device,
        encoder: &mut wgpu::CommandEncoder,
        target: &wgpu::TextureView,
        transformation: Transformation,
        region: wgpu_glyph::Region,
    ) {
        self.draw_brush
            .draw_queued_with_transform_and_scissoring(
                device,
                encoder,
                target,
                transformation.into(),
                region,
            )
            .expect("Draw text");
    }

    pub fn measure(&self, section: &wgpu_glyph::Section<'_>) -> (f32, f32) {
        use wgpu_glyph::GlyphCruncher;

        if let Some(bounds) =
            self.measure_brush.borrow_mut().glyph_bounds(section)
        {
            (bounds.width().ceil(), bounds.height().ceil())
        } else {
            (0.0, 0.0)
        }
    }

    pub fn space_width(&self, size: f32) -> f32 {
        use wgpu_glyph::GlyphCruncher;

        let glyph_brush = self.measure_brush.borrow();

        // TODO: Select appropriate font
        let font = &glyph_brush.fonts()[0];

        font.glyph(' ')
            .scaled(wgpu_glyph::Scale { x: size, y: size })
            .h_metrics()
            .advance_width
    }

    pub fn clear_measurement_cache(&mut self) {
        // Trim measurements cache
        // TODO: We should probably use a `GlyphCalculator` for this. However,
        // it uses a lifetimed `GlyphCalculatorGuard` with side-effects on drop.
        // This makes stuff quite inconvenient. A manual method for trimming the
        // cache would make our lives easier.
        self.measure_brush
            .borrow_mut()
            .process_queued(|_, _| {}, |_| {})
            .expect("Trim text measurements");
    }
}