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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! This crate provides integration of `vulkano` with the font caching feature of `rusttype`, and
//! a basic pipeline for drawing text to the screen.

mod cache;
mod draw;
mod error;

pub use self::cache::GpuCache;
pub use self::error::{Error, ErrorKind, Result};

use std::ops::Range;
use std::sync::Arc;

use rusttype::PositionedGlyph;
use vulkano::command_buffer::{
    AutoCommandBuffer, AutoCommandBufferBuilder, CommandBufferExecFuture, DynamicState,
};
use vulkano::device::Device;
use vulkano::device::Queue;
use vulkano::framebuffer::{RenderPassAbstract, Subpass};
use vulkano::sync::NowFuture;

use crate::draw::Draw;

/// A unique identifier representing a font. Assigning each `Font` a `FontId`
/// is left to the user.
pub type FontId = usize;

/// Object responsible for drawing text to the screen.
pub struct GlyphBrush<'font> {
    glyphs: Vec<PositionedGlyph<'font>>,
    cache: GpuCache<'font>,
    draw: Draw,
}

/// An index for a range of glyphs with the same colour and font.
#[derive(Clone, Debug)]
pub struct Section {
    font: FontId,
    color: [f32; 4],
    range: Range<usize>,
}

impl<'font> GlyphBrush<'font> {
    /// Create a new `GlyphBrush` for use in the given subpass.
    pub fn new(
        device: &Arc<Device>,
        subpass: Subpass<Arc<dyn RenderPassAbstract + Send + Sync>>,
    ) -> Result<Self> {
        let draw = Draw::new(device, subpass)?;
        let cache = GpuCache::new(device)?;
        Ok(GlyphBrush {
            draw,
            cache,
            glyphs: Vec::new(),
        })
    }

    /// Queue some glyphs for later drawing. The `Section` returned is valid until a later call
    /// to `GlyphBrush::clear`.
    pub fn queue_glyphs<I>(&mut self, glyphs: I, font: FontId, color: [f32; 4]) -> Section
    where
        I: IntoIterator<Item = PositionedGlyph<'font>>,
    {
        let old_len = self.glyphs.len();
        self.glyphs.extend(glyphs);
        let range = old_len..self.glyphs.len();
        Section { range, font, color }
    }

    /// Cache some sections of text. If a future is returned, it should be executed before
    /// drawing those sections. This may overwrite cached sections from previous calls to this
    /// function.
    pub fn cache_sections<'a, I>(
        &mut self,
        queue: &Arc<Queue>,
        sections: I,
    ) -> Result<Option<CommandBufferExecFuture<NowFuture, AutoCommandBuffer>>>
    where
        I: IntoIterator<Item = &'a Section>,
    {
        let glyphs = &self.glyphs;
        self.cache.cache(
            queue,
            sections.into_iter().flat_map(|section| {
                glyphs[section.range.clone()]
                    .iter()
                    .map(move |gly| (section.font, gly.clone()))
            }),
        )
    }

    /// Draw a section of text to the screen. The section should have been previously cached
    /// using `GlyphBrush::cache_sections`.
    pub fn draw<'a, I>(
        &mut self,
        cmd: AutoCommandBufferBuilder,
        sections: I,
        state: &DynamicState,
        transform: [[f32; 4]; 4],
        dims: [f32; 2],
    ) -> Result<AutoCommandBufferBuilder>
    where
        I: IntoIterator<Item = &'a Section>,
    {
        self.draw.draw(
            cmd,
            &self.glyphs,
            sections,
            &self.cache,
            state,
            transform,
            dims,
        )
    }

    /// Clear the internal glyph buffer. This invalidates all `Section` objects created by this
    /// `GlyphBrush`.
    pub fn clear(&mut self) {
        self.glyphs.clear();
    }
}