mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
using glium_glyph... things initially kind of work
This commit is contained in:
parent
ca00dda8be
commit
d9d89e93dd
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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) {
|
||||
|
@ -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(),
|
||||
|
@ -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,
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user