using glium_glyph... things initially kind of work

This commit is contained in:
Dustin Carlino 2019-01-23 10:30:06 -08:00
parent ca00dda8be
commit d9d89e93dd
6 changed files with 99 additions and 73 deletions

View File

@ -66,12 +66,13 @@
## Switch to OpenGL (for speed)
- get things running again
- arrows
- forking
- render text
- clean up text rendering... remove LINE_HEIGHT and MAX_CHAR_WIDTH constants
- arrows
- colors still seem off
- make polygon store points and indices efficiently
- change ezgui API to allow uploading geometry once
- undo the y inversion hacks at last!
- probably use f32, not f64 everywhere
- maybe use fancy glyph_brush layout and color changing

View File

@ -9,9 +9,9 @@ abstutil = { path = "../abstutil" }
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
geom = { path = "../geom" }
glium = "0.23.0"
glium-glyph = "0.3.0"
glutin = "0.19.0"
log = "0.4.5"
ordered-float = "1.0.1"
palette = "0.4"
serde = "1.0"
serde_derive = "1.0"

View File

@ -1,6 +1,7 @@
use crate::screen_geom::ScreenRectangle;
use crate::{text, GfxCtx, ScreenPt, Text, UserInput};
use geom::{Bounds, Pt2D};
use glium_glyph::GlyphBrush;
use std::cell::RefCell;
const ZOOM_SPEED: f64 = 0.1;
@ -22,7 +23,8 @@ pub struct Canvas {
pub window_width: f64,
pub window_height: f64,
//glyphs: RefCell<GlyphCache<'static>>,
// TODO Super gross, but we can't create this immediately.
pub(crate) glyphs: RefCell<Option<GlyphBrush<'static, 'static>>>,
// TODO Bit weird and hacky to mutate inside of draw() calls.
covered_areas: RefCell<Vec<ScreenRectangle>>,
@ -30,12 +32,6 @@ pub struct Canvas {
impl Canvas {
pub fn new(initial_width: u32, initial_height: u32) -> Canvas {
// TODO We could also preload everything and not need the RefCell.
/*let glyphs = RefCell::new(
GlyphCache::new("../data/assets/DejaVuSans.ttf", (), texture_settings)
.expect("Could not load font"),
);*/
Canvas {
cam_x: 0.0,
cam_y: 0.0,
@ -49,6 +45,7 @@ impl Canvas {
window_width: f64::from(initial_width),
window_height: f64::from(initial_height),
glyphs: RefCell::new(None),
covered_areas: RefCell::new(Vec::new()),
}
}
@ -97,38 +94,38 @@ impl Canvas {
}
pub fn draw_mouse_tooltip(&self, g: &mut GfxCtx, txt: Text) {
/*let glyphs = &mut self.glyphs.borrow_mut();
let (width, height) = txt.dims(glyphs);
let mut glyphs = self.glyphs.borrow_mut();
let (width, height) = txt.dims(glyphs.as_mut().unwrap());
let x1 = self.cursor_x - (width / 2.0);
let y1 = self.cursor_y - (height / 2.0);
// No need to cover the tooltip; this tooltip follows the mouse anyway.
text::draw_text_bubble(g, glyphs, ScreenPt::new(x1, y1), txt);*/
text::draw_text_bubble(g, glyphs.as_mut().unwrap(), ScreenPt::new(x1, y1), txt);
}
// TODO Rename these draw_nonblocking_text_*
pub fn draw_text_at(&self, g: &mut GfxCtx, txt: Text, map_pt: Pt2D) {
/*let glyphs = &mut self.glyphs.borrow_mut();
let (width, height) = txt.dims(glyphs);
let mut glyphs = self.glyphs.borrow_mut();
let (width, height) = txt.dims(glyphs.as_mut().unwrap());
let pt = self.map_to_screen(map_pt);
text::draw_text_bubble(
g,
glyphs,
glyphs.as_mut().unwrap(),
ScreenPt::new(pt.x - (width / 2.0), pt.y - (height / 2.0)),
txt,
);*/
);
}
pub fn draw_text_at_topleft(&self, g: &mut GfxCtx, txt: Text, pt: Pt2D) {
/*text::draw_text_bubble(
text::draw_text_bubble(
g,
&mut self.glyphs.borrow_mut(),
self.glyphs.borrow_mut().as_mut().unwrap(),
self.map_to_screen(pt),
txt,
);*/
);
}
pub fn draw_text_at_screenspace_topleft(&self, g: &mut GfxCtx, txt: Text, pt: ScreenPt) {
//text::draw_text_bubble(g, &mut self.glyphs.borrow_mut(), pt, txt);
text::draw_text_bubble(g, self.glyphs.borrow_mut().as_mut().unwrap(), pt, txt);
}
// The text box covers up what's beneath and eats the cursor (for get_cursor_in_map_space).
@ -138,11 +135,11 @@ impl Canvas {
txt: Text,
(horiz, vert): (HorizontalAlignment, VerticalAlignment),
) {
/*if txt.is_empty() {
if txt.is_empty() {
return;
}
let glyphs = &mut self.glyphs.borrow_mut();
let (width, height) = txt.dims(glyphs);
let mut glyphs = self.glyphs.borrow_mut();
let (width, height) = txt.dims(glyphs.as_mut().unwrap());
let x1 = match horiz {
HorizontalAlignment::Left => 0.0,
HorizontalAlignment::Center => (self.window_width - width) / 2.0,
@ -156,15 +153,14 @@ impl Canvas {
};
self.covered_areas.borrow_mut().push(text::draw_text_bubble(
g,
glyphs,
glyphs.as_mut().unwrap(),
ScreenPt::new(x1, y1),
txt,
));*/
));
}
pub fn text_dims(&self, txt: &Text) -> (f64, f64) {
//txt.dims(&mut self.glyphs.borrow_mut())
(10.0, 10.0)
txt.dims(self.glyphs.borrow_mut().as_mut().unwrap())
}
fn zoom_towards_mouse(&mut self, delta_zoom: f64) {

View File

@ -2,6 +2,9 @@ use crate::input::{ContextMenu, ModalMenuState};
use crate::{Canvas, Event, GfxCtx, ModalMenu, TopMenu, UserInput};
use abstutil::Timer;
use glium::glutin;
use glium_glyph::glyph_brush::rusttype::Font;
use glium_glyph::GlyphBrush;
use std::cell::RefCell;
use std::io::Write;
use std::time::{Duration, Instant};
use std::{env, fs, panic, process, thread};
@ -133,6 +136,14 @@ impl<T, G: GUI<T>> State<T, G> {
}
}
// Always draw text last?
self.gui
.get_mut_canvas()
.glyphs
.borrow_mut()
.as_mut()
.unwrap()
.draw_queued(display, &mut target);
target.finish().unwrap();
}
@ -262,6 +273,10 @@ pub fn run<T, G: GUI<T>>(mut gui: G, window_title: &str) {
)
.unwrap();
let dejavu: &[u8] = include_bytes!("DejaVuSans.ttf");
let fonts = vec![Font::from_bytes(dejavu).unwrap()];
gui.get_mut_canvas().glyphs = RefCell::new(Some(GlyphBrush::new(&display, fonts)));
let mut state = State {
context_menu: ContextMenu::Inactive,
top_menu: gui.top_menu(),

View File

@ -1,6 +1,10 @@
use crate::screen_geom::ScreenRectangle;
use crate::{Canvas, Color, GfxCtx, ScreenPt};
use ordered_float::NotNan;
use geom::{Polygon, Pt2D};
use glium_glyph::glyph_brush::rusttype::Scale;
use glium_glyph::glyph_brush::GlyphCruncher;
use glium_glyph::glyph_brush::Section;
use glium_glyph::GlyphBrush;
use textwrap;
const FG_COLOR: Color = Color::WHITE;
@ -10,7 +14,7 @@ pub const SELECTED_COLOR: Color = Color::RED;
pub const HOTKEY_COLOR: Color = Color::GREEN;
pub const INACTIVE_CHOICE_COLOR: Color = Color::grey(0.4);
const FONT_SIZE: u32 = 24;
const FONT_SIZE: f32 = 24.0;
// TODO These are dependent on FONT_SIZE, but hand-tuned. Glyphs all have 0 as their height, and
// they need adjustments to their positioning.
pub const LINE_HEIGHT: f64 = 32.0;
@ -120,41 +124,51 @@ impl Text {
self.lines.is_empty()
}
/*pub(crate) fn dims(&self, glyphs: &mut GlyphCache) -> (f64, f64) {
let width = self
.lines
.iter()
.map(|l| {
glyphs
.width(
FONT_SIZE,
&l.iter().fold(String::new(), |mut so_far, span| {
so_far.push_str(&span.text);
so_far
}),
)
.unwrap()
})
.max_by_key(|w| NotNan::new(*w).unwrap())
.unwrap();
let height = (self.lines.len() as f64) * LINE_HEIGHT;
(width, height)
}*/
pub(crate) fn dims(&self, glyphs: &mut GlyphBrush<'static, 'static>) -> (f64, f64) {
let mut widths: Vec<i32> = Vec::new();
let mut heights: Vec<i32> = Vec::new();
for l in &self.lines {
let full_line = l.iter().fold(String::new(), |mut so_far, span| {
so_far.push_str(&span.text);
so_far
});
let rect = glyphs
.pixel_bounds(Section {
text: &full_line,
scale: Scale::uniform(FONT_SIZE),
..Section::default()
})
.unwrap();
widths.push(rect.width());
heights.push(rect.height());
}
(
widths.into_iter().max().unwrap() as f64,
heights.into_iter().max().unwrap() as f64,
)
}
}
/*pub fn draw_text_bubble(
pub fn draw_text_bubble(
g: &mut GfxCtx,
glyphs: &mut GlyphCache,
glyphs: &mut GlyphBrush<'static, 'static>,
top_left: ScreenPt,
txt: Text,
) -> ScreenRectangle {
// TODO Is it expensive to constantly change uniforms and the shader program?
g.fork_screenspace();
let (total_width, total_height) = txt.dims(glyphs);
if let Some(c) = txt.bg_color {
Rectangle::new(c.0).draw(
[top_left.x, top_left.y, total_width, total_height],
&g.orig_ctx.draw_state,
g.orig_ctx.transform,
g.gfx,
g.draw_polygon(
c,
&Polygon::rectangle_topleft(
Pt2D::new(top_left.x, top_left.y),
total_width,
total_height,
),
);
}
@ -169,7 +183,15 @@ impl Text {
same_bg_color = false;
}
let span_width = glyphs.width(FONT_SIZE, &span.text).unwrap();
let section = Section {
text: &span.text,
color: span.fg_color.0,
scale: Scale::uniform(FONT_SIZE),
bounds: (1024.0, 768.0),
screen_position: (x as f32, (y - SHIFT_TEXT_UP) as f32),
..Section::default()
};
let span_width = glyphs.pixel_bounds(section).unwrap().width() as f64;
if let Some(color) = span.highlight_color {
// If this is the last span and all spans use the same background color, then
// extend the background over the entire width of the text box.
@ -178,32 +200,24 @@ impl Text {
} else {
span_width
};
Rectangle::new(color.0).draw(
[x, y - LINE_HEIGHT, width, LINE_HEIGHT],
&g.orig_ctx.draw_state,
g.orig_ctx.transform,
g.gfx,
g.draw_polygon(
color,
&Polygon::rectangle_topleft(Pt2D::new(x, y - LINE_HEIGHT), width, LINE_HEIGHT),
);
}
graphics::Text::new_color(span.fg_color.0, FONT_SIZE)
.draw(
&span.text,
glyphs,
&g.orig_ctx.draw_state,
g.orig_ctx.transform.trans(x, y - SHIFT_TEXT_UP),
g.gfx,
)
.unwrap();
glyphs.queue(section);
x += span_width;
}
y += LINE_HEIGHT;
}
g.unfork();
ScreenRectangle {
x1: top_left.x,
y1: top_left.y,
x2: top_left.x + total_width,
y2: top_left.y + total_height,
}
}*/
}