mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 03:41:09 +03:00
remove piston stuff, cut over to glutin in some basic way. nothing
displays now. :D
This commit is contained in:
parent
974b04e74d
commit
af7596f9a5
@ -65,7 +65,10 @@
|
||||
|
||||
## Switch to OpenGL (for speed)
|
||||
|
||||
- switch ezgui (could make it generic and have piston or glium support, but maybe not worth it)
|
||||
- render text
|
||||
- get playground_gui running
|
||||
- cant see anything
|
||||
- render text
|
||||
- calling draw way too frequently
|
||||
|
||||
- change ezgui API to allow uploading geometry once
|
||||
- undo the y inversion hacks at last!
|
||||
|
@ -13,10 +13,6 @@ glutin = "0.19.0"
|
||||
log = "0.4.5"
|
||||
ordered-float = "1.0.1"
|
||||
palette = "0.4"
|
||||
piston = "0.39.0"
|
||||
piston2d-graphics = "0.28.0"
|
||||
piston2d-opengl_graphics = "0.57.0"
|
||||
pistoncore-glutin_window = "0.51.1"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
textwrap = "0.11"
|
||||
|
@ -1,8 +1,6 @@
|
||||
use crate::screen_geom::ScreenRectangle;
|
||||
use crate::{text, GfxCtx, ScreenPt, Text, UserInput};
|
||||
use geom::{Bounds, Pt2D};
|
||||
use graphics::Transformed;
|
||||
use opengl_graphics::{Filter, GlyphCache, TextureSettings};
|
||||
use std::cell::RefCell;
|
||||
|
||||
const ZOOM_SPEED: f64 = 0.1;
|
||||
@ -24,7 +22,7 @@ pub struct Canvas {
|
||||
pub window_width: f64,
|
||||
pub window_height: f64,
|
||||
|
||||
glyphs: RefCell<GlyphCache<'static>>,
|
||||
//glyphs: RefCell<GlyphCache<'static>>,
|
||||
|
||||
// TODO Bit weird and hacky to mutate inside of draw() calls.
|
||||
covered_areas: RefCell<Vec<ScreenRectangle>>,
|
||||
@ -32,12 +30,11 @@ pub struct Canvas {
|
||||
|
||||
impl Canvas {
|
||||
pub fn new(initial_width: u32, initial_height: u32) -> Canvas {
|
||||
let texture_settings = TextureSettings::new().filter(Filter::Nearest);
|
||||
// TODO We could also preload everything and not need the RefCell.
|
||||
let glyphs = RefCell::new(
|
||||
/*let glyphs = RefCell::new(
|
||||
GlyphCache::new("../data/assets/DejaVuSans.ttf", (), texture_settings)
|
||||
.expect("Could not load font"),
|
||||
);
|
||||
);*/
|
||||
|
||||
Canvas {
|
||||
cam_x: 0.0,
|
||||
@ -52,8 +49,6 @@ impl Canvas {
|
||||
window_width: f64::from(initial_width),
|
||||
window_height: f64::from(initial_height),
|
||||
|
||||
glyphs,
|
||||
|
||||
covered_areas: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
@ -93,11 +88,7 @@ impl Canvas {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn start_drawing(&self, g: &mut GfxCtx) {
|
||||
g.ctx = g
|
||||
.orig_ctx
|
||||
.trans(-self.cam_x, -self.cam_y)
|
||||
.zoom(self.cam_zoom);
|
||||
pub(crate) fn start_drawing(&self) {
|
||||
self.covered_areas.borrow_mut().clear();
|
||||
}
|
||||
|
||||
@ -106,17 +97,17 @@ impl Canvas {
|
||||
}
|
||||
|
||||
pub fn draw_mouse_tooltip(&self, g: &mut GfxCtx, txt: Text) {
|
||||
let glyphs = &mut self.glyphs.borrow_mut();
|
||||
/*let glyphs = &mut self.glyphs.borrow_mut();
|
||||
let (width, height) = txt.dims(glyphs);
|
||||
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, 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 glyphs = &mut self.glyphs.borrow_mut();
|
||||
let (width, height) = txt.dims(glyphs);
|
||||
let pt = self.map_to_screen(map_pt);
|
||||
text::draw_text_bubble(
|
||||
@ -124,20 +115,20 @@ impl Canvas {
|
||||
glyphs,
|
||||
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.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, &mut self.glyphs.borrow_mut(), pt, txt);
|
||||
}
|
||||
|
||||
// The text box covers up what's beneath and eats the cursor (for get_cursor_in_map_space).
|
||||
@ -147,7 +138,7 @@ impl Canvas {
|
||||
txt: Text,
|
||||
(horiz, vert): (HorizontalAlignment, VerticalAlignment),
|
||||
) {
|
||||
if txt.is_empty() {
|
||||
/*if txt.is_empty() {
|
||||
return;
|
||||
}
|
||||
let glyphs = &mut self.glyphs.borrow_mut();
|
||||
@ -168,11 +159,12 @@ impl Canvas {
|
||||
glyphs,
|
||||
ScreenPt::new(x1, y1),
|
||||
txt,
|
||||
));
|
||||
));*/
|
||||
}
|
||||
|
||||
pub fn text_dims(&self, txt: &Text) -> (f64, f64) {
|
||||
txt.dims(&mut self.glyphs.borrow_mut())
|
||||
//txt.dims(&mut self.glyphs.borrow_mut())
|
||||
(10.0, 10.0)
|
||||
}
|
||||
|
||||
fn zoom_towards_mouse(&mut self, delta_zoom: f64) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::ScreenPt;
|
||||
use glium::glutin;
|
||||
use piston::input as pi;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum Event {
|
||||
@ -68,70 +67,6 @@ impl Event {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_piston_event(ev: pi::Event) -> Event {
|
||||
use piston::input::{
|
||||
ButtonEvent, CursorEvent, MouseCursorEvent, MouseScrollEvent, PressEvent, ReleaseEvent,
|
||||
ResizeEvent, TouchEvent, UpdateEvent,
|
||||
};
|
||||
|
||||
if let Some(pi::Button::Mouse(button)) = ev.press_args() {
|
||||
if button == pi::MouseButton::Left {
|
||||
return Event::LeftMouseButtonDown;
|
||||
}
|
||||
if button == pi::MouseButton::Right {
|
||||
return Event::RightMouseButtonDown;
|
||||
}
|
||||
}
|
||||
if let Some(pi::Button::Mouse(button)) = ev.release_args() {
|
||||
if button == pi::MouseButton::Left {
|
||||
return Event::LeftMouseButtonUp;
|
||||
}
|
||||
if button == pi::MouseButton::Right {
|
||||
return Event::RightMouseButtonUp;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(pi::Button::Keyboard(key)) = ev.press_args() {
|
||||
if let Some(key) = Key::from_piston_key(key, ev.button_args()) {
|
||||
return Event::KeyPress(key);
|
||||
}
|
||||
return Event::Unknown;
|
||||
}
|
||||
if let Some(pi::Button::Keyboard(key)) = ev.release_args() {
|
||||
if let Some(key) = Key::from_piston_key(key, ev.button_args()) {
|
||||
return Event::KeyRelease(key);
|
||||
}
|
||||
return Event::Unknown;
|
||||
}
|
||||
|
||||
if ev.update_args().is_some() {
|
||||
return Event::Update;
|
||||
}
|
||||
if let Some(pair) = ev.mouse_cursor_args() {
|
||||
return Event::MouseMovedTo(ScreenPt::new(pair[0], pair[1]));
|
||||
}
|
||||
if let Some(args) = ev.touch_args() {
|
||||
// The docs say these are normalized [0, 1] coordinates, but... they're not. :D
|
||||
return Event::MouseMovedTo(ScreenPt::new(args.x, args.y));
|
||||
}
|
||||
if let Some(pair) = ev.mouse_scroll_args() {
|
||||
return Event::MouseWheelScroll(pair[1]);
|
||||
}
|
||||
if let Some(pair) = ev.resize_args() {
|
||||
return Event::WindowResized(pair[0], pair[1]);
|
||||
}
|
||||
if let Some(has) = ev.cursor_args() {
|
||||
if has {
|
||||
return Event::WindowGainedCursor;
|
||||
} else {
|
||||
// TODO Sometimes this doesn't happen! :(
|
||||
return Event::WindowLostCursor;
|
||||
}
|
||||
}
|
||||
|
||||
panic!("Unknown piston event {:?}", ev);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
@ -314,86 +249,6 @@ impl Key {
|
||||
}
|
||||
}
|
||||
|
||||
fn from_piston_key(key: pi::Key, args: Option<pi::ButtonArgs>) -> Option<Key> {
|
||||
if let Some(a) = args {
|
||||
if a.scancode == Some(39) {
|
||||
return Some(Key::Semicolon);
|
||||
}
|
||||
}
|
||||
|
||||
Some(match key {
|
||||
pi::Key::A => Key::A,
|
||||
pi::Key::B => Key::B,
|
||||
pi::Key::C => Key::C,
|
||||
pi::Key::D => Key::D,
|
||||
pi::Key::E => Key::E,
|
||||
pi::Key::F => Key::F,
|
||||
pi::Key::G => Key::G,
|
||||
pi::Key::H => Key::H,
|
||||
pi::Key::I => Key::I,
|
||||
pi::Key::J => Key::J,
|
||||
pi::Key::K => Key::K,
|
||||
pi::Key::L => Key::L,
|
||||
pi::Key::M => Key::M,
|
||||
pi::Key::N => Key::N,
|
||||
pi::Key::O => Key::O,
|
||||
pi::Key::P => Key::P,
|
||||
pi::Key::Q => Key::Q,
|
||||
pi::Key::R => Key::R,
|
||||
pi::Key::S => Key::S,
|
||||
pi::Key::T => Key::T,
|
||||
pi::Key::U => Key::U,
|
||||
pi::Key::V => Key::V,
|
||||
pi::Key::W => Key::W,
|
||||
pi::Key::X => Key::X,
|
||||
pi::Key::Y => Key::Y,
|
||||
pi::Key::Z => Key::Z,
|
||||
pi::Key::D1 => Key::Num1,
|
||||
pi::Key::D2 => Key::Num2,
|
||||
pi::Key::D3 => Key::Num3,
|
||||
pi::Key::D4 => Key::Num4,
|
||||
pi::Key::D5 => Key::Num5,
|
||||
pi::Key::D6 => Key::Num6,
|
||||
pi::Key::D7 => Key::Num7,
|
||||
pi::Key::D8 => Key::Num8,
|
||||
pi::Key::D9 => Key::Num9,
|
||||
pi::Key::D0 => Key::Num0,
|
||||
pi::Key::LeftBracket => Key::LeftBracket,
|
||||
pi::Key::RightBracket => Key::RightBracket,
|
||||
pi::Key::Space => Key::Space,
|
||||
pi::Key::Slash => Key::Slash,
|
||||
pi::Key::Period => Key::Dot,
|
||||
pi::Key::Comma => Key::Comma,
|
||||
pi::Key::Escape => Key::Escape,
|
||||
pi::Key::Return => Key::Enter,
|
||||
pi::Key::Tab => Key::Tab,
|
||||
pi::Key::Backspace => Key::Backspace,
|
||||
pi::Key::LShift => Key::LeftShift,
|
||||
pi::Key::LCtrl => Key::LeftControl,
|
||||
pi::Key::LAlt => Key::LeftAlt,
|
||||
pi::Key::Left => Key::LeftArrow,
|
||||
pi::Key::Right => Key::RightArrow,
|
||||
pi::Key::Up => Key::UpArrow,
|
||||
pi::Key::Down => Key::DownArrow,
|
||||
pi::Key::F1 => Key::F1,
|
||||
pi::Key::F2 => Key::F2,
|
||||
pi::Key::F3 => Key::F3,
|
||||
pi::Key::F4 => Key::F4,
|
||||
pi::Key::F5 => Key::F5,
|
||||
pi::Key::F6 => Key::F6,
|
||||
pi::Key::F7 => Key::F7,
|
||||
pi::Key::F8 => Key::F8,
|
||||
pi::Key::F9 => Key::F9,
|
||||
pi::Key::F10 => Key::F10,
|
||||
pi::Key::F11 => Key::F11,
|
||||
pi::Key::F12 => Key::F12,
|
||||
_ => {
|
||||
println!("Unknown piston key {:?}", key);
|
||||
return None;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn from_glutin_key(input: glutin::KeyboardInput) -> Option<Key> {
|
||||
let key = input.virtual_keycode?;
|
||||
Some(match key {
|
||||
|
155
ezgui/src/lib.rs
155
ezgui/src/lib.rs
@ -28,143 +28,11 @@ pub use crate::top_menu::{Folder, TopMenu};
|
||||
pub use crate::wizard::{Wizard, WrappedWizard};
|
||||
use geom::Pt2D;
|
||||
use glium::{implement_vertex, uniform, Surface};
|
||||
use graphics::Transformed;
|
||||
use opengl_graphics::GlGraphics;
|
||||
use std::mem;
|
||||
|
||||
// TODO Not super happy about exposing this; fork_screenspace for external callers should be
|
||||
// smarter.
|
||||
pub const TOP_MENU_HEIGHT: f64 = text::LINE_HEIGHT;
|
||||
|
||||
pub struct GfxCtx<'a> {
|
||||
orig_ctx: graphics::Context,
|
||||
ctx: graphics::Context,
|
||||
gfx: &'a mut GlGraphics,
|
||||
}
|
||||
|
||||
impl<'a> GfxCtx<'a> {
|
||||
pub fn new(g: &'a mut GlGraphics, c: graphics::Context) -> GfxCtx<'a> {
|
||||
GfxCtx {
|
||||
gfx: g,
|
||||
orig_ctx: c,
|
||||
ctx: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Up to the caller to call unfork()!
|
||||
// TODO Canvas doesn't understand this change, so things like text drawing that use
|
||||
// map_to_screen will just be confusing.
|
||||
pub fn fork(&mut self, top_left: Pt2D, zoom: f64) -> graphics::Context {
|
||||
mem::replace(
|
||||
&mut self.ctx,
|
||||
self.orig_ctx
|
||||
.trans(-zoom * top_left.x(), -zoom * top_left.y())
|
||||
.zoom(zoom),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn fork_screenspace(&mut self) -> graphics::Context {
|
||||
self.fork(Pt2D::new(0.0, 0.0), 1.0)
|
||||
}
|
||||
|
||||
pub fn unfork(&mut self, old_ctx: graphics::Context) {
|
||||
self.ctx = old_ctx;
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, color: Color) {
|
||||
graphics::clear(color.0, self.gfx);
|
||||
}
|
||||
|
||||
// Use graphics::Line internally for now, but make it easy to switch to something else by
|
||||
// picking this API now.
|
||||
pub fn draw_line(&mut self, color: Color, thickness: f64, line: &geom::Line) {
|
||||
self.draw_polygon(color, &line.to_polyline().make_polygons(thickness));
|
||||
}
|
||||
|
||||
pub fn draw_rounded_line(&mut self, color: Color, thickness: f64, line: &geom::Line) {
|
||||
self.draw_line(color, thickness, line);
|
||||
self.draw_circle(color, &geom::Circle::new(line.pt1(), thickness / 2.0));
|
||||
self.draw_circle(color, &geom::Circle::new(line.pt2(), thickness / 2.0));
|
||||
}
|
||||
|
||||
pub fn draw_arrow(&mut self, color: Color, thickness: f64, line: &geom::Line) {
|
||||
// TODO Raw method doesn't work yet in all cases...
|
||||
graphics::Line::new_round(color.0, thickness).draw_arrow(
|
||||
[
|
||||
line.pt1().x(),
|
||||
line.pt1().y(),
|
||||
line.pt2().x(),
|
||||
line.pt2().y(),
|
||||
],
|
||||
2.0 * thickness,
|
||||
&self.ctx.draw_state,
|
||||
self.ctx.transform,
|
||||
self.gfx,
|
||||
);
|
||||
|
||||
/*use dimensioned::si;
|
||||
let head_size = 2.0 * thickness;
|
||||
let angle = line.angle();
|
||||
let triangle_height = (head_size / 2.0).sqrt() * si::M;
|
||||
self.draw_polygon(
|
||||
color,
|
||||
&geom::Polygon::new(&vec![
|
||||
//line.pt2(),
|
||||
//line.pt2().project_away(head_size, angle.rotate_degs(-135.0)),
|
||||
line.reverse()
|
||||
.dist_along(triangle_height)
|
||||
.project_away(thickness / 2.0, angle.rotate_degs(90.0)),
|
||||
line.pt1()
|
||||
.project_away(thickness / 2.0, angle.rotate_degs(90.0)),
|
||||
line.pt1()
|
||||
.project_away(thickness / 2.0, angle.rotate_degs(-90.0)),
|
||||
line.reverse()
|
||||
.dist_along(triangle_height)
|
||||
.project_away(thickness / 2.0, angle.rotate_degs(-90.0)),
|
||||
//line.pt2().project_away(head_size, angle.rotate_degs(135.0)),
|
||||
]),
|
||||
);
|
||||
self.draw_polygon(
|
||||
color,
|
||||
&geom::Polygon::new(&vec![
|
||||
line.pt2(),
|
||||
line.pt2()
|
||||
.project_away(head_size, angle.rotate_degs(-135.0)),
|
||||
line.pt2().project_away(head_size, angle.rotate_degs(135.0)),
|
||||
]),
|
||||
);*/
|
||||
}
|
||||
|
||||
pub fn draw_polygon(&mut self, color: Color, poly: &geom::Polygon) {
|
||||
for tri in &poly.triangles {
|
||||
graphics::Polygon::new(color.0).draw(
|
||||
&[
|
||||
[tri.pt1.x(), tri.pt1.y()],
|
||||
[tri.pt2.x(), tri.pt2.y()],
|
||||
[tri.pt3.x(), tri.pt3.y()],
|
||||
],
|
||||
&self.ctx.draw_state,
|
||||
self.ctx.transform,
|
||||
self.gfx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_circle(&mut self, color: Color, circle: &geom::Circle) {
|
||||
graphics::Ellipse::new(color.0).draw(
|
||||
[
|
||||
circle.center.x() - circle.radius,
|
||||
circle.center.y() - circle.radius,
|
||||
2.0 * circle.radius,
|
||||
2.0 * circle.radius,
|
||||
],
|
||||
&self.ctx.draw_state,
|
||||
self.ctx.transform,
|
||||
self.gfx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ToggleableLayer {
|
||||
layer_name: String,
|
||||
// If None, never automatically enable at a certain zoom level.
|
||||
@ -231,7 +99,7 @@ type Uniforms<'a> = glium::uniforms::UniformsStorage<
|
||||
glium::uniforms::UniformsStorage<'a, [[f32; 4]; 4], glium::uniforms::EmptyUniforms>,
|
||||
>;
|
||||
|
||||
pub struct NewGfxCtx<'a> {
|
||||
pub struct GfxCtx<'a> {
|
||||
display: &'a glium::Display,
|
||||
target: &'a mut glium::Frame,
|
||||
program: &'a glium::Program,
|
||||
@ -239,12 +107,13 @@ pub struct NewGfxCtx<'a> {
|
||||
params: glium::DrawParameters<'a>,
|
||||
}
|
||||
|
||||
impl<'a> NewGfxCtx<'a> {
|
||||
impl<'a> GfxCtx<'a> {
|
||||
pub fn new(
|
||||
canvas: &Canvas,
|
||||
display: &'a glium::Display,
|
||||
target: &'a mut glium::Frame,
|
||||
program: &'a glium::Program,
|
||||
) -> NewGfxCtx<'a> {
|
||||
) -> GfxCtx<'a> {
|
||||
let params = glium::DrawParameters {
|
||||
depth: glium::Depth {
|
||||
test: glium::DepthTest::IfLess,
|
||||
@ -261,7 +130,7 @@ impl<'a> NewGfxCtx<'a> {
|
||||
view_matrix: camera.get_view(),
|
||||
};
|
||||
|
||||
NewGfxCtx {
|
||||
GfxCtx {
|
||||
display,
|
||||
target,
|
||||
program,
|
||||
@ -273,25 +142,21 @@ impl<'a> NewGfxCtx<'a> {
|
||||
// Up to the caller to call unfork()!
|
||||
// TODO Canvas doesn't understand this change, so things like text drawing that use
|
||||
// map_to_screen will just be confusing.
|
||||
pub fn fork(&mut self, top_left: Pt2D, zoom: f64) -> Uniforms {
|
||||
pub fn fork(&mut self, top_left: Pt2D, zoom: f64) {
|
||||
let mut camera = CameraState::new();
|
||||
// TODO setup camera based on values above
|
||||
let mut uniforms = uniform! {
|
||||
self.uniforms = uniform! {
|
||||
persp_matrix: camera.get_perspective(),
|
||||
view_matrix: camera.get_view(),
|
||||
};
|
||||
|
||||
mem::swap(&mut self.uniforms, &mut uniforms);
|
||||
uniforms
|
||||
}
|
||||
|
||||
pub fn fork_screenspace(&mut self) -> Uniforms {
|
||||
pub fn fork_screenspace(&mut self) {
|
||||
self.fork(Pt2D::new(0.0, 0.0), 1.0)
|
||||
}
|
||||
|
||||
pub fn unfork(&mut self, old_uniforms: Uniforms<'a>) {
|
||||
// TODO What do we need to do to re-upload?
|
||||
self.uniforms = old_uniforms;
|
||||
pub fn unfork(&mut self) {
|
||||
// TODO Reset to canvas?
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, color: Color) {
|
||||
|
@ -1,11 +1,7 @@
|
||||
use crate::input::{ContextMenu, ModalMenuState};
|
||||
use crate::{Canvas, Event, GfxCtx, ModalMenu, NewGfxCtx, TopMenu, UserInput};
|
||||
use crate::{Canvas, Event, GfxCtx, ModalMenu, TopMenu, UserInput};
|
||||
use abstutil::Timer;
|
||||
use glium::glutin;
|
||||
use glutin_window::GlutinWindow;
|
||||
use opengl_graphics::{GlGraphics, OpenGL};
|
||||
use piston::event_loop::{EventLoop, EventSettings, Events};
|
||||
use piston::window::WindowSettings;
|
||||
use std::io::Write;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{env, fs, panic, process, thread};
|
||||
@ -40,75 +36,8 @@ pub enum EventLoopMode {
|
||||
ScreenCaptureEverything { zoom: f64, max_x: f64, max_y: f64 },
|
||||
}
|
||||
|
||||
pub fn run<T, G: GUI<T>>(mut gui: G, window_title: &str) {
|
||||
// DPI is broken on my system; force the old behavior.
|
||||
env::set_var("WINIT_HIDPI_FACTOR", "1.0");
|
||||
|
||||
let opengl = OpenGL::V3_2;
|
||||
let settings = WindowSettings::new(
|
||||
window_title,
|
||||
[
|
||||
gui.get_mut_canvas().window_width as u32,
|
||||
gui.get_mut_canvas().window_height as u32,
|
||||
],
|
||||
)
|
||||
.opengl(opengl)
|
||||
.exit_on_esc(false)
|
||||
// TODO it'd be cool to dynamically tweak antialiasing settings as we zoom in
|
||||
.samples(2)
|
||||
.srgb(false);
|
||||
let mut window: GlutinWindow = settings.build().expect("Could not create window");
|
||||
let mut events = Events::new(EventSettings::new().lazy(true));
|
||||
let mut gl = GlGraphics::new(opengl);
|
||||
|
||||
let mut state = State {
|
||||
last_event_mode: EventLoopMode::InputOnly,
|
||||
context_menu: ContextMenu::Inactive,
|
||||
top_menu: gui.top_menu(),
|
||||
modal_state: ModalMenuState::new(G::modal_menus()),
|
||||
last_data: None,
|
||||
screen_cap: None,
|
||||
gui,
|
||||
};
|
||||
|
||||
while let Some(ev) = events.next(&mut window) {
|
||||
use piston::input::{CloseEvent, RenderEvent};
|
||||
if let Some(args) = ev.render_args() {
|
||||
gl.draw(args.viewport(), |c, g| {
|
||||
state.draw(&mut GfxCtx::new(g, c));
|
||||
});
|
||||
} else if ev.close_args().is_some() {
|
||||
state.gui.before_quit();
|
||||
process::exit(0);
|
||||
} else {
|
||||
// Skip some events.
|
||||
use piston::input::{
|
||||
AfterRenderEvent, FocusEvent, IdleEvent, MouseRelativeEvent, TextEvent,
|
||||
};
|
||||
if ev.after_render_args().is_some() {
|
||||
state.after_render();
|
||||
continue;
|
||||
}
|
||||
if state.screen_cap.is_some() {
|
||||
continue;
|
||||
}
|
||||
if ev.after_render_args().is_some()
|
||||
|| ev.focus_args().is_some()
|
||||
|| ev.idle_args().is_some()
|
||||
|| ev.mouse_relative_args().is_some()
|
||||
|| ev.text_args().is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
state = state.event(ev, &mut events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct State<T, G: GUI<T>> {
|
||||
gui: G,
|
||||
last_event_mode: EventLoopMode,
|
||||
context_menu: ContextMenu,
|
||||
top_menu: Option<TopMenu>,
|
||||
modal_state: ModalMenuState,
|
||||
@ -117,18 +46,18 @@ struct State<T, G: GUI<T>> {
|
||||
}
|
||||
|
||||
impl<T, G: GUI<T>> State<T, G> {
|
||||
fn event(mut self, ev: piston::input::Event, events: &mut Events) -> State<T, G> {
|
||||
fn event(mut self, ev: Event) -> (State<T, G>, EventLoopMode) {
|
||||
// It's impossible / very unlikey we'll grab the cursor in map space before the very first
|
||||
// start_drawing call.
|
||||
let mut input = UserInput::new(
|
||||
Event::from_piston_event(ev),
|
||||
ev,
|
||||
self.context_menu,
|
||||
self.top_menu,
|
||||
self.modal_state,
|
||||
self.gui.get_mut_canvas(),
|
||||
);
|
||||
let mut gui = self.gui;
|
||||
let (new_event_mode, data) =
|
||||
let (event_mode, data) =
|
||||
match panic::catch_unwind(panic::AssertUnwindSafe(|| gui.event(&mut input))) {
|
||||
Ok(pair) => pair,
|
||||
Err(err) => {
|
||||
@ -156,38 +85,28 @@ impl<T, G: GUI<T>> State<T, G> {
|
||||
self.modal_state.active = still_active;
|
||||
|
||||
// Don't constantly reset the events struct -- only when laziness changes.
|
||||
if new_event_mode != self.last_event_mode {
|
||||
events.set_lazy(new_event_mode == EventLoopMode::InputOnly);
|
||||
self.last_event_mode = new_event_mode;
|
||||
|
||||
if let EventLoopMode::ScreenCaptureEverything { zoom, max_x, max_y } = new_event_mode {
|
||||
self.screen_cap = Some(ScreenCaptureState::new(
|
||||
self.gui.get_mut_canvas(),
|
||||
zoom,
|
||||
max_x,
|
||||
max_y,
|
||||
));
|
||||
events.set_lazy(false);
|
||||
}
|
||||
if let EventLoopMode::ScreenCaptureEverything { zoom, max_x, max_y } = event_mode {
|
||||
self.screen_cap = Some(ScreenCaptureState::new(
|
||||
self.gui.get_mut_canvas(),
|
||||
zoom,
|
||||
max_x,
|
||||
max_y,
|
||||
));
|
||||
}
|
||||
|
||||
self
|
||||
(self, event_mode)
|
||||
}
|
||||
|
||||
fn new_draw(&mut self, display: &glium::Display, program: &glium::Program) {
|
||||
fn draw(&mut self, display: &glium::Display, program: &glium::Program) {
|
||||
let mut target = display.draw();
|
||||
// TODO call draw
|
||||
NewGfxCtx::new(&display, &mut target, program);
|
||||
target.finish().unwrap();
|
||||
}
|
||||
let mut g = GfxCtx::new(self.gui.get_mut_canvas(), &display, &mut target, program);
|
||||
|
||||
fn draw(&mut self, g: &mut GfxCtx) {
|
||||
// If the very first event is render, then just wait.
|
||||
if let Some(ref data) = self.last_data {
|
||||
self.gui.get_mut_canvas().start_drawing(g);
|
||||
self.gui.get_mut_canvas().start_drawing();
|
||||
|
||||
match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
self.gui.new_draw(g, data, self.screen_cap.is_some())
|
||||
self.gui.new_draw(&mut g, data, self.screen_cap.is_some())
|
||||
})) {
|
||||
Ok(naming_hint) => {
|
||||
if let Some(ref mut cap) = self.screen_cap {
|
||||
@ -203,16 +122,18 @@ impl<T, G: GUI<T>> State<T, G> {
|
||||
if self.screen_cap.is_none() {
|
||||
// Always draw the menus last.
|
||||
if let Some(ref menu) = self.top_menu {
|
||||
menu.draw(g, self.gui.get_mut_canvas());
|
||||
menu.draw(&mut g, self.gui.get_mut_canvas());
|
||||
}
|
||||
for (_, ref menu) in &self.modal_state.active {
|
||||
menu.draw(g, self.gui.get_mut_canvas());
|
||||
menu.draw(&mut g, self.gui.get_mut_canvas());
|
||||
}
|
||||
if let ContextMenu::Displaying(ref menu) = self.context_menu {
|
||||
menu.draw(g, self.gui.get_mut_canvas());
|
||||
menu.draw(&mut g, self.gui.get_mut_canvas());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target.finish().unwrap();
|
||||
}
|
||||
|
||||
fn after_render(&mut self) {
|
||||
@ -319,7 +240,7 @@ impl ScreenCaptureState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_run<T, G: GUI<T>>(mut gui: G, window_title: &str) {
|
||||
pub fn run<T, G: GUI<T>>(mut gui: G, window_title: &str) {
|
||||
// DPI is broken on my system; force the old behavior.
|
||||
env::set_var("WINIT_HIDPI_FACTOR", "1.0");
|
||||
|
||||
@ -341,7 +262,6 @@ pub fn new_run<T, G: GUI<T>>(mut gui: G, window_title: &str) {
|
||||
.unwrap();
|
||||
|
||||
let mut state = State {
|
||||
last_event_mode: EventLoopMode::InputOnly,
|
||||
context_menu: ContextMenu::Inactive,
|
||||
top_menu: gui.top_menu(),
|
||||
modal_state: ModalMenuState::new(G::modal_menus()),
|
||||
@ -352,22 +272,30 @@ pub fn new_run<T, G: GUI<T>>(mut gui: G, window_title: &str) {
|
||||
|
||||
let mut accumulator = Duration::new(0, 0);
|
||||
let mut previous_clock = Instant::now();
|
||||
let mut send_update_events = false;
|
||||
loop {
|
||||
state.new_draw(&display, &program);
|
||||
state.draw(&display, &program);
|
||||
state.after_render();
|
||||
|
||||
let mut new_events: Vec<glutin::WindowEvent> = Vec::new();
|
||||
events_loop.poll_events(|event| {
|
||||
if let glutin::Event::WindowEvent { event, .. } = event {
|
||||
if event == glutin::WindowEvent::CloseRequested {
|
||||
state.gui.before_quit();
|
||||
process::exit(0);
|
||||
}
|
||||
if state.screen_cap.is_none() {
|
||||
// TODO manage laziness differently
|
||||
//state = state.event(event, &mut events);
|
||||
}
|
||||
new_events.push(event);
|
||||
}
|
||||
});
|
||||
for event in new_events {
|
||||
if event == glutin::WindowEvent::CloseRequested {
|
||||
state.gui.before_quit();
|
||||
process::exit(0);
|
||||
}
|
||||
if state.screen_cap.is_none() {
|
||||
if let Some(ev) = Event::from_glutin_event(event) {
|
||||
let (new_state, mode) = state.event(ev);
|
||||
state = new_state;
|
||||
send_update_events = mode == EventLoopMode::Animation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
accumulator += now - previous_clock;
|
||||
|
@ -1,9 +1,5 @@
|
||||
use crate::screen_geom::ScreenRectangle;
|
||||
use crate::{Canvas, Color, GfxCtx, ScreenPt};
|
||||
use graphics;
|
||||
use graphics::character::CharacterCache;
|
||||
use graphics::{Rectangle, Transformed};
|
||||
use opengl_graphics::GlyphCache;
|
||||
use ordered_float::NotNan;
|
||||
use textwrap;
|
||||
|
||||
@ -124,7 +120,7 @@ impl Text {
|
||||
self.lines.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn dims(&self, glyphs: &mut GlyphCache) -> (f64, f64) {
|
||||
/*pub(crate) fn dims(&self, glyphs: &mut GlyphCache) -> (f64, f64) {
|
||||
let width = self
|
||||
.lines
|
||||
.iter()
|
||||
@ -143,10 +139,10 @@ impl Text {
|
||||
.unwrap();
|
||||
let height = (self.lines.len() as f64) * LINE_HEIGHT;
|
||||
(width, height)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
pub fn draw_text_bubble(
|
||||
/*pub fn draw_text_bubble(
|
||||
g: &mut GfxCtx,
|
||||
glyphs: &mut GlyphCache,
|
||||
top_left: ScreenPt,
|
||||
@ -210,4 +206,4 @@ pub fn draw_text_bubble(
|
||||
x2: top_left.x + total_width,
|
||||
y2: top_left.y + total_height,
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
@ -135,7 +135,7 @@ impl TopMenu {
|
||||
y2: TOP_MENU_HEIGHT,
|
||||
});
|
||||
|
||||
let old_ctx = g.fork_screenspace();
|
||||
g.fork_screenspace();
|
||||
g.draw_polygon(
|
||||
text::BG_COLOR,
|
||||
&Polygon::rectangle_topleft(Pt2D::new(0.0, 0.0), canvas.window_width, TOP_MENU_HEIGHT),
|
||||
@ -148,7 +148,7 @@ impl TopMenu {
|
||||
&Polygon::rectangle_topleft(Pt2D::new(r.x1, r.y1), r.x2 - r.x1, r.y2 - r.y1),
|
||||
);
|
||||
}
|
||||
g.unfork(old_ctx);
|
||||
g.unfork();
|
||||
|
||||
canvas.draw_text_at_screenspace_topleft(g, self.txt.clone(), ScreenPt::new(0.0, 0.0));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user