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
use gfx_device_gl as gl;
use gfx_glyph::GlyphCruncher;

use crate::graphics::gpu::{TargetView, Transformation};
use crate::graphics::{HorizontalAlignment, Text, Vector, VerticalAlignment};

pub struct Font {
    glyphs: gfx_glyph::GlyphBrush<'static, gl::Resources, gl::Factory>,
}

impl Font {
    pub fn from_bytes(factory: &mut gl::Factory, bytes: &'static [u8]) -> Font {
        Font {
            glyphs: gfx_glyph::GlyphBrushBuilder::using_font_bytes(bytes)
                .depth_test(gfx::preset::depth::PASS_TEST)
                .texture_filter_method(gfx::texture::FilterMethod::Scale)
                .build(factory.clone()),
        }
    }

    pub fn add(&mut self, text: Text<'_>) {
        let section: gfx_glyph::Section<'_> = text.into();
        self.glyphs.queue(section);
    }

    pub fn measure(&mut self, text: Text<'_>) -> (f32, f32) {
        let section: gfx_glyph::Section<'_> = text.into();
        let bounds = self.glyphs.glyph_bounds(section);

        match bounds {
            Some(bounds) => (bounds.width(), bounds.height()),
            None => (0.0, 0.0),
        }
    }

    pub fn draw(
        &mut self,
        encoder: &mut gfx::Encoder<gl::Resources, gl::CommandBuffer>,
        target: &TargetView,
        transformation: Transformation,
    ) {
        let typed_target: gfx::handle::RenderTargetView<
            gl::Resources,
            gfx::format::Srgba8,
        > = gfx::memory::Typed::new(target.clone());

        self.glyphs
            .use_queue()
            .transform(
                Transformation::nonuniform_scale(Vector::new(1.0, -1.0))
                    * transformation,
            )
            .draw(encoder, &typed_target)
            .expect("Font draw");
    }
}

impl<'a> From<Text<'a>> for gfx_glyph::Section<'a> {
    fn from(text: Text<'a>) -> gfx_glyph::Section<'a> {
        let x = match text.horizontal_alignment {
            HorizontalAlignment::Left => text.position.x,
            HorizontalAlignment::Center => {
                text.position.x + text.bounds.0 / 2.0
            }
            HorizontalAlignment::Right => text.position.x + text.bounds.0,
        };

        let y = match text.vertical_alignment {
            VerticalAlignment::Top => text.position.y,
            VerticalAlignment::Center => text.position.y + text.bounds.1 / 2.0,
            VerticalAlignment::Bottom => text.position.y + text.bounds.1,
        };

        gfx_glyph::Section {
            text: &text.content,
            screen_position: (x, y),
            scale: gfx_glyph::Scale {
                x: text.size,
                y: text.size,
            },
            color: text.color.into_linear(),
            bounds: text.bounds,
            layout: gfx_glyph::Layout::default()
                .h_align(text.horizontal_alignment.into())
                .v_align(text.vertical_alignment.into()),
            ..Default::default()
        }
    }
}

impl From<HorizontalAlignment> for gfx_glyph::HorizontalAlign {
    fn from(alignment: HorizontalAlignment) -> gfx_glyph::HorizontalAlign {
        match alignment {
            HorizontalAlignment::Left => gfx_glyph::HorizontalAlign::Left,
            HorizontalAlignment::Center => gfx_glyph::HorizontalAlign::Center,
            HorizontalAlignment::Right => gfx_glyph::HorizontalAlign::Right,
        }
    }
}

impl From<VerticalAlignment> for gfx_glyph::VerticalAlign {
    fn from(alignment: VerticalAlignment) -> gfx_glyph::VerticalAlign {
        match alignment {
            VerticalAlignment::Top => gfx_glyph::VerticalAlign::Top,
            VerticalAlignment::Center => gfx_glyph::VerticalAlign::Center,
            VerticalAlignment::Bottom => gfx_glyph::VerticalAlign::Bottom,
        }
    }
}