From b2c92ab8f9eae28fabc3a9b8de6c5ab61599e7db Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Fri, 14 Feb 2020 14:28:25 -0800 Subject: [PATCH] upstreaming some changes for wasm here - use instant crate - bring in the wasm ezgui backend and necessary setup tweaks - upgrade stdweb but no map editor build magic yet --- abstutil/Cargo.toml | 1 + abstutil/src/io.rs | 2 +- abstutil/src/time.rs | 2 +- ezgui/Cargo.toml | 14 +- ezgui/src/assets.rs | 7 + ezgui/src/assets/fragment_140.glsl | 5 +- ezgui/src/assets/vertex_140.glsl | 4 +- ezgui/src/backend_glium.rs | 10 +- ezgui/src/backend_glow.rs | 10 +- ezgui/src/backend_wasm.rs | 357 +++++++++++++++++++++++++++++ ezgui/src/event_ctx.rs | 2 +- ezgui/src/lib.rs | 5 + ezgui/src/runner.rs | 8 +- ezgui/src/widgets/warper.rs | 2 +- game/Cargo.toml | 1 + game/src/pregame.rs | 2 +- game/src/sandbox/speed.rs | 2 +- geom/Cargo.toml | 1 + geom/src/duration.rs | 2 +- sim/Cargo.toml | 1 + sim/src/sim.rs | 2 +- 21 files changed, 419 insertions(+), 21 deletions(-) create mode 100644 ezgui/src/backend_wasm.rs diff --git a/abstutil/Cargo.toml b/abstutil/Cargo.toml index 56f804de68..a17f831331 100644 --- a/abstutil/Cargo.toml +++ b/abstutil/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] bincode = "1.1.2" +instant = "0.1.2" num_cpus = "1.10.0" rand = "0.7.0" rand_xorshift = "0.2.0" diff --git a/abstutil/src/io.rs b/abstutil/src/io.rs index 36fa131fcd..2a829948ae 100644 --- a/abstutil/src/io.rs +++ b/abstutil/src/io.rs @@ -1,6 +1,7 @@ use crate::time::{clear_current_line, prettyprint_time}; use crate::{elapsed_seconds, prettyprint_usize, MultiMap, Timer, PROGRESS_FREQUENCY_SECONDS}; use bincode; +use instant::Instant; use serde::de::DeserializeOwned; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json; @@ -10,7 +11,6 @@ use std::collections::{BTreeMap, BTreeSet}; use std::fs::File; use std::io::{stdout, BufReader, BufWriter, Error, ErrorKind, Read, Write}; use std::path::Path; -use std::time::Instant; pub fn to_json(obj: &T) -> String { serde_json::to_string_pretty(obj).unwrap() diff --git a/abstutil/src/time.rs b/abstutil/src/time.rs index 7e2caebecf..fd0cd24ebc 100644 --- a/abstutil/src/time.rs +++ b/abstutil/src/time.rs @@ -1,8 +1,8 @@ use crate::PROGRESS_FREQUENCY_SECONDS; +use instant::Instant; use std::collections::HashMap; use std::fs::File; use std::io::{stdout, BufReader, Error, Read, Write}; -use std::time::Instant; pub fn elapsed_seconds(since: Instant) -> f64 { let dt = since.elapsed(); diff --git a/ezgui/Cargo.toml b/ezgui/Cargo.toml index 724f9a1b95..88349846cb 100644 --- a/ezgui/Cargo.toml +++ b/ezgui/Cargo.toml @@ -6,8 +6,9 @@ edition = "2018" [features] default = ["glium-backend"] -glium-backend = ["glium"] -glow-backend = ["glow"] +glium-backend = ["glium", "glutin", "usvg/text"] +glow-backend = ["glow", "glutin", "usvg/text"] +wasm-backend = ["glow/stdweb", "instant/stdweb", "stdweb", "webgl_stdweb", "winit/stdweb"] profiler = ["cpuprofiler"] [dependencies] @@ -16,17 +17,20 @@ abstutil = { path = "../abstutil" } cpuprofiler = { version = "0.0.3", optional = true } geom = { path = "../geom" } glium = { version = "0.26.0", optional = true } -glow = { version = "0.4.0", optional = true } -glutin = "0.23.0" +glow = { version = "0.4.0", optional = true, default-features=false } +glutin = { version = "0.23.0", optional = true } htmlescape = "0.3.1" image = "0.22.2" +instant = "0.1.2" lru = "0.4.3" lyon = "0.14.2" ordered-float = "1.0.1" serde = "1.0.98" serde_derive = "1.0.98" simsearch = "0.1.4" +stdweb = { version = "0.4.20", optional = true } stretch = "0.3.2" textwrap = "0.11" -usvg = { git = "https://github.com/dabreegster/resvg" } +usvg = { git = "https://github.com/dabreegster/resvg", default-features=false } +webgl_stdweb = { version = "0.3", optional = true } winit = "0.21.0" diff --git a/ezgui/src/assets.rs b/ezgui/src/assets.rs index 5023858325..df18e9b2e0 100644 --- a/ezgui/src/assets.rs +++ b/ezgui/src/assets.rs @@ -31,6 +31,7 @@ impl Assets { a } + #[cfg(not(target_arch = "wasm32"))] pub fn line_height(&self, font: Font, font_size: usize) -> f64 { let key = (font, font_size); if let Some(height) = self.line_height_cache.borrow().get(&key) { @@ -54,6 +55,12 @@ impl Assets { height } + // TODO No text in wasm yet + #[cfg(target_arch = "wasm32")] + pub fn line_height(&self, font: Font, font_size: usize) -> f64 { + text::SCALE_LINE_HEIGHT * 30.0 + } + pub fn get_cached_text(&self, key: &String) -> Option { self.text_cache.borrow_mut().get(key).cloned() } diff --git a/ezgui/src/assets/fragment_140.glsl b/ezgui/src/assets/fragment_140.glsl index e7a2e198d7..a00efa6260 100644 --- a/ezgui/src/assets/fragment_140.glsl +++ b/ezgui/src/assets/fragment_140.glsl @@ -1,4 +1,7 @@ -#version 330 core +#version 300 es + +precision mediump float; +precision mediump sampler2DArray; // (x offset, y offset, zoom) uniform vec3 transform; diff --git a/ezgui/src/assets/vertex_140.glsl b/ezgui/src/assets/vertex_140.glsl index fd21c2f1f4..75e74cf19b 100644 --- a/ezgui/src/assets/vertex_140.glsl +++ b/ezgui/src/assets/vertex_140.glsl @@ -1,4 +1,6 @@ -#version 330 core +#version 300 es + +precision mediump float; // (x offset, y offset, zoom) uniform vec3 transform; diff --git a/ezgui/src/backend_glium.rs b/ezgui/src/backend_glium.rs index 15b2cf73eb..12c05d82bc 100644 --- a/ezgui/src/backend_glium.rs +++ b/ezgui/src/backend_glium.rs @@ -7,7 +7,13 @@ use glium::Surface; use std::cell::{Cell, RefCell}; use std::collections::{BTreeMap, HashMap}; -pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventLoop<()>) { +pub fn setup( + window_title: &str, +) -> ( + PrerenderInnards, + winit::event_loop::EventLoop<()>, + ScreenDims, +) { let event_loop = winit::event_loop::EventLoop::new(); let window = winit::window::WindowBuilder::new() .with_title(window_title) @@ -66,6 +72,7 @@ pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventL ) .unwrap(); + let window_size = event_loop.primary_monitor().size(); ( PrerenderInnards { display, @@ -75,6 +82,7 @@ pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventL texture_lookups: RefCell::new(HashMap::new()), }, event_loop, + ScreenDims::new(window_size.width.into(), window_size.height.into()), ) } diff --git a/ezgui/src/backend_glow.rs b/ezgui/src/backend_glow.rs index ea4bf0b6ad..d1dabad2b5 100644 --- a/ezgui/src/backend_glow.rs +++ b/ezgui/src/backend_glow.rs @@ -5,7 +5,13 @@ use glow::HasContext; use std::cell::{Cell, RefCell}; use std::collections::{BTreeMap, HashMap}; -pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventLoop<()>) { +pub fn setup( + window_title: &str, +) -> ( + PrerenderInnards, + winit::event_loop::EventLoop<()>, + ScreenDims, +) { let event_loop = winit::event_loop::EventLoop::new(); let window = winit::window::WindowBuilder::new() .with_title(window_title) @@ -56,6 +62,7 @@ pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventL gl.enable(glow::SCISSOR_TEST); } + let window_size = event_loop.primary_monitor().size(); ( PrerenderInnards { gl, @@ -65,6 +72,7 @@ pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventL texture_lookups: RefCell::new(HashMap::new()), }, event_loop, + ScreenDims::new(window_size.width.into(), window_size.height.into()), ) } diff --git a/ezgui/src/backend_wasm.rs b/ezgui/src/backend_wasm.rs new file mode 100644 index 0000000000..5493aa67a6 --- /dev/null +++ b/ezgui/src/backend_wasm.rs @@ -0,0 +1,357 @@ +use crate::drawing::Uniforms; +use crate::{Canvas, Color, ScreenDims, ScreenRectangle, TextureType}; +use geom::{Angle, Polygon, Pt2D}; +use glow::HasContext; +use std::cell::{Cell, RefCell}; +use std::collections::{BTreeMap, HashMap}; +use stdweb::traits::INode; +use webgl_stdweb::WebGL2RenderingContext; +use winit::platform::web::WindowExtStdweb; + +pub fn setup( + window_title: &str, +) -> ( + PrerenderInnards, + winit::event_loop::EventLoop<()>, + ScreenDims, +) { + stdweb::console!(log, "Setting up ezgui"); + + // This doesn't seem to work for the shader panics here, but later it does work. Huh. + std::panic::set_hook(Box::new(|info| { + stdweb::console!(log, "panicked: %s", format!("{}", info)); + })); + + let event_loop = winit::event_loop::EventLoop::new(); + let window = winit::window::WindowBuilder::new() + .with_title(window_title) + .build(&event_loop) + .unwrap(); + let canvas = window.canvas(); + let document = stdweb::web::document(); + let body: stdweb::web::Node = document.body().expect("Get HTML body").into(); + body.append_child(&canvas); + + let webgl2_context: WebGL2RenderingContext = canvas.get_context().unwrap(); + let gl = glow::Context::from_webgl2_context(webgl2_context); + + let program = unsafe { gl.create_program().expect("Cannot create program") }; + + unsafe { + let shaders = [ + (glow::VERTEX_SHADER, include_str!("assets/vertex_140.glsl")), + ( + glow::FRAGMENT_SHADER, + include_str!("assets/fragment_140.glsl"), + ), + ] + .iter() + .map(|(shader_type, source)| { + let shader = gl + .create_shader(*shader_type) + .expect("Cannot create shader"); + gl.shader_source(shader, source); + gl.compile_shader(shader); + if !gl.get_shader_compile_status(shader) { + stdweb::console!(log, "Shader error: %s", gl.get_shader_info_log(shader)); + panic!(gl.get_shader_info_log(shader)); + } + gl.attach_shader(program, shader); + shader + }) + .collect::>(); + gl.link_program(program); + if !gl.get_program_link_status(program) { + stdweb::console!(log, "Linking error: %s", gl.get_program_info_log(program)); + panic!(gl.get_program_info_log(program)); + } + for shader in shaders { + gl.detach_shader(program, shader); + gl.delete_shader(shader); + } + gl.use_program(Some(program)); + + gl.enable(glow::SCISSOR_TEST); + } + + ( + PrerenderInnards { + gl, + program, + window, + total_bytes_uploaded: Cell::new(0), + texture_lookups: RefCell::new(HashMap::new()), + }, + event_loop, + ScreenDims::new(canvas.width().into(), canvas.height().into()), + ) +} + +// Represents one frame that's gonna be drawn +pub struct GfxCtxInnards<'a> { + gl: &'a glow::Context, + program: &'a ::Program, + + current_clip: Option<[i32; 4]>, +} + +impl<'a> GfxCtxInnards<'a> { + pub fn clear(&mut self, color: Color) { + match color { + Color::RGBA(r, g, b, a) => unsafe { + self.gl.clear_color(r, g, b, a); + self.gl.clear(glow::COLOR_BUFFER_BIT); + }, + _ => unreachable!(), + } + } + + pub fn redraw(&mut self, obj: &Drawable, uniforms: &Uniforms, _: &PrerenderInnards) { + unsafe { + let transform_loc = self + .gl + .get_uniform_location(*self.program, "transform") + .unwrap(); + self.gl + .uniform_3_f32_slice(Some(transform_loc), &uniforms.transform); + let window_loc = self + .gl + .get_uniform_location(*self.program, "window") + .unwrap(); + self.gl + .uniform_3_f32_slice(Some(window_loc), &uniforms.window); + + self.gl.bind_vertex_array(Some(obj.vert_array)); + self.gl + .draw_elements(glow::TRIANGLES, obj.num_indices, glow::UNSIGNED_INT, 0); + self.gl.bind_vertex_array(None); + } + } + + pub fn enable_clipping(&mut self, rect: ScreenRectangle, canvas: &Canvas) { + assert!(self.current_clip.is_none()); + // The scissor rectangle has to be in device coordinates, so you would think some transform + // by scale factor (previously called HiDPI factor) has to happen here. But actually, + // window dimensions and the rectangle passed in are already scaled up. So don't do + // anything here! + let left = rect.x1 as i32; + // Y-inversion + let bottom = (canvas.window_height - rect.y2) as i32; + let width = (rect.x2 - rect.x1) as i32; + let height = (rect.y2 - rect.y1) as i32; + unsafe { + self.gl.scissor(left, bottom, width, height); + } + self.current_clip = Some([left, bottom, width, height]); + } + + pub fn disable_clipping(&mut self, canvas: &Canvas) { + assert!(self.current_clip.is_some()); + self.current_clip = None; + unsafe { + self.gl.scissor( + 0, + 0, + canvas.window_width as i32, + canvas.window_height as i32, + ); + } + } + + pub fn take_clip(&mut self) -> Option<[i32; 4]> { + self.current_clip.take() + } + pub fn restore_clip(&mut self, clip: Option<[i32; 4]>) { + self.current_clip = clip; + if let Some(c) = clip { + unsafe { + self.gl.scissor(c[0], c[1], c[2], c[3]); + } + } + } + + pub fn finish(self) {} +} + +// Something that's been sent to the GPU already. +// TODO Implement Drop; have to keep a reference to gl. +pub struct Drawable { + _vert_buffer: glow::WebBufferKey, + vert_array: glow::WebVertexArrayKey, + _elem_buffer: glow::WebBufferKey, + num_indices: i32, +} + +pub struct PrerenderInnards { + gl: glow::Context, + window: winit::window::Window, + program: ::Program, + + // TODO Prerender doesn't know what things are temporary and permanent. Could make the API more + // detailed. + pub total_bytes_uploaded: Cell, + + // Kind of a weird place for this, but ah well. + pub texture_lookups: RefCell>, +} + +impl PrerenderInnards { + pub fn actually_upload(&self, permanent: bool, list: Vec<(Color, &Polygon)>) -> Drawable { + let mut vertices: Vec<[f32; 6]> = Vec::new(); + let mut indices: Vec = Vec::new(); + + for (color, poly) in list { + let idx_offset = vertices.len(); + let (pts, raw_indices) = poly.raw_for_rendering(); + for pt in pts { + // For the three texture cases, pass [U coordinate, V coordinate, texture group ID, + // 100 + texture offset ID] as the style. The last field is between 0 an 1 RGBA's + // alpha values, so bump by 100 to distinguish from that. + let style = match color { + Color::RGBA(r, g, b, a) => [r, g, b, a], + Color::TileTexture(id, tex_dims) => { + // The texture uses SamplerWrapFunction::Repeat, so don't clamp to [0, 1]. + // Also don't offset based on the polygon's bounds -- even if there are + // separate but adjacent polygons, we want seamless tiling. + let tx = pt.x() / tex_dims.width; + let ty = pt.y() / tex_dims.height; + [tx as f32, ty as f32, id.0, 100.0 + id.1] + } + Color::StretchTexture(id, _, angle) => { + // TODO Cache + let b = poly.get_bounds(); + let center = poly.center(); + let origin_pt = Pt2D::new(pt.x() - center.x(), pt.y() - center.y()); + let (sin, cos) = angle.invert_y().normalized_radians().sin_cos(); + let rot_pt = Pt2D::new( + center.x() + origin_pt.x() * cos - origin_pt.y() * sin, + center.y() + origin_pt.y() * cos + origin_pt.x() * sin, + ); + + let tx = (rot_pt.x() - b.min_x) / b.width(); + let ty = (rot_pt.y() - b.min_y) / b.height(); + [tx as f32, ty as f32, id.0, 100.0 + id.1] + } + // Two final special cases + Color::HatchingStyle1 => [100.0, 0.0, 0.0, 0.0], + Color::HatchingStyle2 => [101.0, 0.0, 0.0, 0.0], + }; + vertices.push([ + pt.x() as f32, + pt.y() as f32, + style[0], + style[1], + style[2], + style[3], + ]); + } + for idx in raw_indices { + indices.push((idx_offset + *idx) as u32); + } + } + + let (vert_buffer, vert_array, elem_buffer) = unsafe { + let vert_array = self.gl.create_vertex_array().unwrap(); + let vert_buffer = self.gl.create_buffer().unwrap(); + let elem_buffer = self.gl.create_buffer().unwrap(); + + self.gl.bind_vertex_array(Some(vert_array)); + + self.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vert_buffer)); + self.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + &vertices.align_to::().1, + // TODO Use permanent + glow::STATIC_DRAW, + ); + + self.gl + .bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(elem_buffer)); + self.gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + &indices.align_to::().1, + glow::STATIC_DRAW, + ); + + // TODO Can we have a single vertex array for everything, since there's an uber shader? + + let stride = 6 * std::mem::size_of::() as i32; + // position is vec2 + self.gl.enable_vertex_attrib_array(0); + self.gl + .vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, stride, 0); + // style is vec4 + self.gl.enable_vertex_attrib_array(1); + self.gl.vertex_attrib_pointer_f32( + 1, + 4, + glow::FLOAT, + false, + stride, + 2 * std::mem::size_of::() as i32, + ); + + // Safety? + self.gl.bind_vertex_array(None); + self.gl.bind_buffer(glow::ARRAY_BUFFER, None); + self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None); + + (vert_buffer, vert_array, elem_buffer) + }; + let num_indices = indices.len() as i32; + + if permanent { + /*self.total_bytes_uploaded.set( + self.total_bytes_uploaded.get() + + vertex_buffer.get_size() + + index_buffer.get_size(), + );*/ + } + + Drawable { + _vert_buffer: vert_buffer, + vert_array, + _elem_buffer: elem_buffer, + num_indices, + } + } + + pub fn request_redraw(&self) { + self.window.request_redraw(); + } + + pub fn draw_new_frame(&self) -> GfxCtxInnards { + GfxCtxInnards { + gl: &self.gl, + program: &self.program, + current_clip: None, + } + } + + pub fn upload_textures( + &self, + dims_to_textures: BTreeMap<(u32, u32), Vec<(String, Vec, TextureType)>>, + ) { + for (group_idx, (raw_dims, list)) in dims_to_textures.into_iter().enumerate() { + for (tex_idx, (filename, _, tex_type)) in list.into_iter().enumerate() { + let tex_id = (group_idx as f32, tex_idx as f32); + let dims = ScreenDims::new(f64::from(raw_dims.0), f64::from(raw_dims.1)); + self.texture_lookups.borrow_mut().insert( + filename, + match tex_type { + TextureType::Stretch => Color::StretchTexture(tex_id, dims, Angle::ZERO), + TextureType::Tile => Color::TileTexture(tex_id, dims), + }, + ); + } + } + } + + pub fn window_resized(&self, width: f64, height: f64) { + unsafe { + self.gl.viewport(0, 0, width as i32, height as i32); + // I think it's safe to assume there's not a clip right now. + self.gl.scissor(0, 0, width as i32, height as i32); + } + } +} diff --git a/ezgui/src/event_ctx.rs b/ezgui/src/event_ctx.rs index f01e2808cc..3459f7556f 100644 --- a/ezgui/src/event_ctx.rs +++ b/ezgui/src/event_ctx.rs @@ -4,9 +4,9 @@ use crate::{ }; use abstutil::{elapsed_seconds, Timer, TimerSink}; use geom::Polygon; +use instant::Instant; use std::collections::BTreeMap; use std::collections::VecDeque; -use std::time::Instant; pub struct EventCtx<'a> { pub(crate) fake_mouseover: bool, diff --git a/ezgui/src/lib.rs b/ezgui/src/lib.rs index c4908798cd..0b28562301 100644 --- a/ezgui/src/lib.rs +++ b/ezgui/src/lib.rs @@ -3,6 +3,8 @@ mod assets; mod backend_glium; #[cfg(feature = "glow-backend")] mod backend_glow; +#[cfg(feature = "wasm-backend")] +mod backend_wasm; mod canvas; mod color; mod drawing; @@ -45,4 +47,7 @@ mod backend { #[cfg(feature = "glow-backend")] pub use crate::backend_glow::*; + + #[cfg(feature = "wasm-backend")] + pub use crate::backend_wasm::*; } diff --git a/ezgui/src/runner.rs b/ezgui/src/runner.rs index 66e9b70fe6..486330871d 100644 --- a/ezgui/src/runner.rs +++ b/ezgui/src/runner.rs @@ -1,9 +1,9 @@ use crate::assets::Assets; use crate::{widgets, Canvas, Event, EventCtx, GfxCtx, Key, Prerender, UserInput}; use geom::Duration; +use instant::Instant; use std::cell::Cell; use std::panic; -use std::time::Instant; const UPDATE_FREQUENCY: std::time::Duration = std::time::Duration::from_millis(1000 / 30); @@ -159,10 +159,10 @@ impl Settings { } pub fn run G>(settings: Settings, make_gui: F) -> ! { - let (prerender_innards, event_loop) = crate::backend::setup(&settings.window_title); + let (prerender_innards, event_loop, window_size) = + crate::backend::setup(&settings.window_title); - let window_size = event_loop.primary_monitor().size(); - let mut canvas = Canvas::new(window_size.width.into(), window_size.height.into()); + let mut canvas = Canvas::new(window_size.width, window_size.height); prerender_innards.window_resized(canvas.window_width, canvas.window_height); let prerender = Prerender { assets: Assets::new(settings.default_font_size, settings.font_dir), diff --git a/ezgui/src/widgets/warper.rs b/ezgui/src/widgets/warper.rs index ec11be8410..4c7d3b89f4 100644 --- a/ezgui/src/widgets/warper.rs +++ b/ezgui/src/widgets/warper.rs @@ -1,6 +1,6 @@ use crate::{EventCtx, EventLoopMode}; use geom::{Line, Pt2D}; -use std::time::Instant; +use instant::Instant; pub struct Warper { started: Instant, diff --git a/game/Cargo.toml b/game/Cargo.toml index 567bf19cf2..ed03c31764 100644 --- a/game/Cargo.toml +++ b/game/Cargo.toml @@ -14,6 +14,7 @@ downcast-rs = "1.0.4" ezgui = { path = "../ezgui" } #ezgui = { path = "../ezgui", default-features=false, features=["glow-backend"] } geom = { path = "../geom" } +instant = "0.1.2" kml = { path = "../kml" } map_model = { path = "../map_model" } popdat = { path = "../popdat" } diff --git a/game/src/pregame.rs b/game/src/pregame.rs index a2da401205..7375fc4663 100644 --- a/game/src/pregame.rs +++ b/game/src/pregame.rs @@ -11,10 +11,10 @@ use ezgui::{ ManagedWidget, Text, }; use geom::{Duration, Line, Pt2D, Speed}; +use instant::Instant; use map_model::{Map, MapEdits}; use rand::Rng; use rand_xorshift::XorShiftRng; -use std::time::Instant; pub struct TitleScreen { composite: WrappedComposite, diff --git a/game/src/sandbox/speed.rs b/game/src/sandbox/speed.rs index 95182f4625..8fb09481cb 100644 --- a/game/src/sandbox/speed.rs +++ b/game/src/sandbox/speed.rs @@ -7,7 +7,7 @@ use ezgui::{ HorizontalAlignment, Key, Line, ManagedWidget, RewriteColor, Text, VerticalAlignment, Wizard, }; use geom::{Duration, Polygon, Time}; -use std::time::Instant; +use instant::Instant; pub struct SpeedControls { pub composite: WrappedComposite, diff --git a/geom/Cargo.toml b/geom/Cargo.toml index 74989aa35d..db0f55315f 100644 --- a/geom/Cargo.toml +++ b/geom/Cargo.toml @@ -11,6 +11,7 @@ geo = "0.12.0" geo-booleanop = "0.2.0" geo-offset = "0.1.0" histogram = "0.6.9" +instant = "0.1.2" ordered-float = "1.0.1" polylabel = { git = "https://github.com/urschrei/polylabel-rs" } serde = "1.0.98" diff --git a/geom/src/duration.rs b/geom/src/duration.rs index f90d351bbf..43e397254f 100644 --- a/geom/src/duration.rs +++ b/geom/src/duration.rs @@ -1,7 +1,7 @@ use crate::{trim_f64, Distance, Speed}; use abstutil::elapsed_seconds; +use instant::Instant; use serde_derive::{Deserialize, Serialize}; -use std::time::Instant; use std::{cmp, f64, ops}; // In seconds. Can be negative. diff --git a/sim/Cargo.toml b/sim/Cargo.toml index 6d48c93061..43de2a2c37 100644 --- a/sim/Cargo.toml +++ b/sim/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" abstutil = { path = "../abstutil" } derivative = "1.0.0" geom = { path = "../geom" } +instant = "0.1.2" map_model = { path = "../map_model" } rand = "0.7.0" rand_xorshift = "0.2.0" diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 86689fa512..fcc56f6bda 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -9,6 +9,7 @@ use crate::{ use abstutil::Timer; use derivative::Derivative; use geom::{Distance, Duration, PolyLine, Pt2D, Time}; +use instant::Instant; use map_model::{ BuildingID, BusRoute, BusRouteID, IntersectionID, LaneID, Map, Path, PathConstraints, PathRequest, PathStep, Traversable, @@ -16,7 +17,6 @@ use map_model::{ use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashSet}; use std::panic; -use std::time::Instant; // TODO Do something else. const BLIND_RETRY_TO_SPAWN: Duration = Duration::const_seconds(5.0);