mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
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
This commit is contained in:
parent
d7d8b472e5
commit
b2c92ab8f9
@ -6,6 +6,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bincode = "1.1.2"
|
bincode = "1.1.2"
|
||||||
|
instant = "0.1.2"
|
||||||
num_cpus = "1.10.0"
|
num_cpus = "1.10.0"
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
rand_xorshift = "0.2.0"
|
rand_xorshift = "0.2.0"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::time::{clear_current_line, prettyprint_time};
|
use crate::time::{clear_current_line, prettyprint_time};
|
||||||
use crate::{elapsed_seconds, prettyprint_usize, MultiMap, Timer, PROGRESS_FREQUENCY_SECONDS};
|
use crate::{elapsed_seconds, prettyprint_usize, MultiMap, Timer, PROGRESS_FREQUENCY_SECONDS};
|
||||||
use bincode;
|
use bincode;
|
||||||
|
use instant::Instant;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
@ -10,7 +11,6 @@ use std::collections::{BTreeMap, BTreeSet};
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdout, BufReader, BufWriter, Error, ErrorKind, Read, Write};
|
use std::io::{stdout, BufReader, BufWriter, Error, ErrorKind, Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub fn to_json<T: Serialize>(obj: &T) -> String {
|
pub fn to_json<T: Serialize>(obj: &T) -> String {
|
||||||
serde_json::to_string_pretty(obj).unwrap()
|
serde_json::to_string_pretty(obj).unwrap()
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::PROGRESS_FREQUENCY_SECONDS;
|
use crate::PROGRESS_FREQUENCY_SECONDS;
|
||||||
|
use instant::Instant;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdout, BufReader, Error, Read, Write};
|
use std::io::{stdout, BufReader, Error, Read, Write};
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub fn elapsed_seconds(since: Instant) -> f64 {
|
pub fn elapsed_seconds(since: Instant) -> f64 {
|
||||||
let dt = since.elapsed();
|
let dt = since.elapsed();
|
||||||
|
@ -6,8 +6,9 @@ edition = "2018"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["glium-backend"]
|
default = ["glium-backend"]
|
||||||
glium-backend = ["glium"]
|
glium-backend = ["glium", "glutin", "usvg/text"]
|
||||||
glow-backend = ["glow"]
|
glow-backend = ["glow", "glutin", "usvg/text"]
|
||||||
|
wasm-backend = ["glow/stdweb", "instant/stdweb", "stdweb", "webgl_stdweb", "winit/stdweb"]
|
||||||
profiler = ["cpuprofiler"]
|
profiler = ["cpuprofiler"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -16,17 +17,20 @@ abstutil = { path = "../abstutil" }
|
|||||||
cpuprofiler = { version = "0.0.3", optional = true }
|
cpuprofiler = { version = "0.0.3", optional = true }
|
||||||
geom = { path = "../geom" }
|
geom = { path = "../geom" }
|
||||||
glium = { version = "0.26.0", optional = true }
|
glium = { version = "0.26.0", optional = true }
|
||||||
glow = { version = "0.4.0", optional = true }
|
glow = { version = "0.4.0", optional = true, default-features=false }
|
||||||
glutin = "0.23.0"
|
glutin = { version = "0.23.0", optional = true }
|
||||||
htmlescape = "0.3.1"
|
htmlescape = "0.3.1"
|
||||||
image = "0.22.2"
|
image = "0.22.2"
|
||||||
|
instant = "0.1.2"
|
||||||
lru = "0.4.3"
|
lru = "0.4.3"
|
||||||
lyon = "0.14.2"
|
lyon = "0.14.2"
|
||||||
ordered-float = "1.0.1"
|
ordered-float = "1.0.1"
|
||||||
serde = "1.0.98"
|
serde = "1.0.98"
|
||||||
serde_derive = "1.0.98"
|
serde_derive = "1.0.98"
|
||||||
simsearch = "0.1.4"
|
simsearch = "0.1.4"
|
||||||
|
stdweb = { version = "0.4.20", optional = true }
|
||||||
stretch = "0.3.2"
|
stretch = "0.3.2"
|
||||||
textwrap = "0.11"
|
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"
|
winit = "0.21.0"
|
||||||
|
@ -31,6 +31,7 @@ impl Assets {
|
|||||||
a
|
a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn line_height(&self, font: Font, font_size: usize) -> f64 {
|
pub fn line_height(&self, font: Font, font_size: usize) -> f64 {
|
||||||
let key = (font, font_size);
|
let key = (font, font_size);
|
||||||
if let Some(height) = self.line_height_cache.borrow().get(&key) {
|
if let Some(height) = self.line_height_cache.borrow().get(&key) {
|
||||||
@ -54,6 +55,12 @@ impl Assets {
|
|||||||
height
|
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<GeomBatch> {
|
pub fn get_cached_text(&self, key: &String) -> Option<GeomBatch> {
|
||||||
self.text_cache.borrow_mut().get(key).cloned()
|
self.text_cache.borrow_mut().get(key).cloned()
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#version 330 core
|
#version 300 es
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
precision mediump sampler2DArray;
|
||||||
|
|
||||||
// (x offset, y offset, zoom)
|
// (x offset, y offset, zoom)
|
||||||
uniform vec3 transform;
|
uniform vec3 transform;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#version 330 core
|
#version 300 es
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
// (x offset, y offset, zoom)
|
// (x offset, y offset, zoom)
|
||||||
uniform vec3 transform;
|
uniform vec3 transform;
|
||||||
|
@ -7,7 +7,13 @@ use glium::Surface;
|
|||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
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 event_loop = winit::event_loop::EventLoop::new();
|
||||||
let window = winit::window::WindowBuilder::new()
|
let window = winit::window::WindowBuilder::new()
|
||||||
.with_title(window_title)
|
.with_title(window_title)
|
||||||
@ -66,6 +72,7 @@ pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventL
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let window_size = event_loop.primary_monitor().size();
|
||||||
(
|
(
|
||||||
PrerenderInnards {
|
PrerenderInnards {
|
||||||
display,
|
display,
|
||||||
@ -75,6 +82,7 @@ pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventL
|
|||||||
texture_lookups: RefCell::new(HashMap::new()),
|
texture_lookups: RefCell::new(HashMap::new()),
|
||||||
},
|
},
|
||||||
event_loop,
|
event_loop,
|
||||||
|
ScreenDims::new(window_size.width.into(), window_size.height.into()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,13 @@ use glow::HasContext;
|
|||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
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 event_loop = winit::event_loop::EventLoop::new();
|
||||||
let window = winit::window::WindowBuilder::new()
|
let window = winit::window::WindowBuilder::new()
|
||||||
.with_title(window_title)
|
.with_title(window_title)
|
||||||
@ -56,6 +62,7 @@ pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventL
|
|||||||
gl.enable(glow::SCISSOR_TEST);
|
gl.enable(glow::SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let window_size = event_loop.primary_monitor().size();
|
||||||
(
|
(
|
||||||
PrerenderInnards {
|
PrerenderInnards {
|
||||||
gl,
|
gl,
|
||||||
@ -65,6 +72,7 @@ pub fn setup(window_title: &str) -> (PrerenderInnards, winit::event_loop::EventL
|
|||||||
texture_lookups: RefCell::new(HashMap::new()),
|
texture_lookups: RefCell::new(HashMap::new()),
|
||||||
},
|
},
|
||||||
event_loop,
|
event_loop,
|
||||||
|
ScreenDims::new(window_size.width.into(), window_size.height.into()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
357
ezgui/src/backend_wasm.rs
Normal file
357
ezgui/src/backend_wasm.rs
Normal file
@ -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::<Vec<_>>();
|
||||||
|
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 <glow::Context as glow::HasContext>::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: <glow::Context as glow::HasContext>::Program,
|
||||||
|
|
||||||
|
// TODO Prerender doesn't know what things are temporary and permanent. Could make the API more
|
||||||
|
// detailed.
|
||||||
|
pub total_bytes_uploaded: Cell<usize>,
|
||||||
|
|
||||||
|
// Kind of a weird place for this, but ah well.
|
||||||
|
pub texture_lookups: RefCell<HashMap<String, Color>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<u32> = 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::<u8>().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::<u8>().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::<f32>() 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::<f32>() 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<u8>, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use abstutil::{elapsed_seconds, Timer, TimerSink};
|
use abstutil::{elapsed_seconds, Timer, TimerSink};
|
||||||
use geom::Polygon;
|
use geom::Polygon;
|
||||||
|
use instant::Instant;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct EventCtx<'a> {
|
pub struct EventCtx<'a> {
|
||||||
pub(crate) fake_mouseover: bool,
|
pub(crate) fake_mouseover: bool,
|
||||||
|
@ -3,6 +3,8 @@ mod assets;
|
|||||||
mod backend_glium;
|
mod backend_glium;
|
||||||
#[cfg(feature = "glow-backend")]
|
#[cfg(feature = "glow-backend")]
|
||||||
mod backend_glow;
|
mod backend_glow;
|
||||||
|
#[cfg(feature = "wasm-backend")]
|
||||||
|
mod backend_wasm;
|
||||||
mod canvas;
|
mod canvas;
|
||||||
mod color;
|
mod color;
|
||||||
mod drawing;
|
mod drawing;
|
||||||
@ -45,4 +47,7 @@ mod backend {
|
|||||||
|
|
||||||
#[cfg(feature = "glow-backend")]
|
#[cfg(feature = "glow-backend")]
|
||||||
pub use crate::backend_glow::*;
|
pub use crate::backend_glow::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "wasm-backend")]
|
||||||
|
pub use crate::backend_wasm::*;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::assets::Assets;
|
use crate::assets::Assets;
|
||||||
use crate::{widgets, Canvas, Event, EventCtx, GfxCtx, Key, Prerender, UserInput};
|
use crate::{widgets, Canvas, Event, EventCtx, GfxCtx, Key, Prerender, UserInput};
|
||||||
use geom::Duration;
|
use geom::Duration;
|
||||||
|
use instant::Instant;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::panic;
|
use std::panic;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
const UPDATE_FREQUENCY: std::time::Duration = std::time::Duration::from_millis(1000 / 30);
|
const UPDATE_FREQUENCY: std::time::Duration = std::time::Duration::from_millis(1000 / 30);
|
||||||
|
|
||||||
@ -159,10 +159,10 @@ impl Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<G: 'static + GUI, F: FnOnce(&mut EventCtx) -> G>(settings: Settings, make_gui: F) -> ! {
|
pub fn run<G: 'static + GUI, F: FnOnce(&mut EventCtx) -> 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, window_size.height);
|
||||||
let mut canvas = Canvas::new(window_size.width.into(), window_size.height.into());
|
|
||||||
prerender_innards.window_resized(canvas.window_width, canvas.window_height);
|
prerender_innards.window_resized(canvas.window_width, canvas.window_height);
|
||||||
let prerender = Prerender {
|
let prerender = Prerender {
|
||||||
assets: Assets::new(settings.default_font_size, settings.font_dir),
|
assets: Assets::new(settings.default_font_size, settings.font_dir),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{EventCtx, EventLoopMode};
|
use crate::{EventCtx, EventLoopMode};
|
||||||
use geom::{Line, Pt2D};
|
use geom::{Line, Pt2D};
|
||||||
use std::time::Instant;
|
use instant::Instant;
|
||||||
|
|
||||||
pub struct Warper {
|
pub struct Warper {
|
||||||
started: Instant,
|
started: Instant,
|
||||||
|
@ -14,6 +14,7 @@ downcast-rs = "1.0.4"
|
|||||||
ezgui = { path = "../ezgui" }
|
ezgui = { path = "../ezgui" }
|
||||||
#ezgui = { path = "../ezgui", default-features=false, features=["glow-backend"] }
|
#ezgui = { path = "../ezgui", default-features=false, features=["glow-backend"] }
|
||||||
geom = { path = "../geom" }
|
geom = { path = "../geom" }
|
||||||
|
instant = "0.1.2"
|
||||||
kml = { path = "../kml" }
|
kml = { path = "../kml" }
|
||||||
map_model = { path = "../map_model" }
|
map_model = { path = "../map_model" }
|
||||||
popdat = { path = "../popdat" }
|
popdat = { path = "../popdat" }
|
||||||
|
@ -11,10 +11,10 @@ use ezgui::{
|
|||||||
ManagedWidget, Text,
|
ManagedWidget, Text,
|
||||||
};
|
};
|
||||||
use geom::{Duration, Line, Pt2D, Speed};
|
use geom::{Duration, Line, Pt2D, Speed};
|
||||||
|
use instant::Instant;
|
||||||
use map_model::{Map, MapEdits};
|
use map_model::{Map, MapEdits};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
pub struct TitleScreen {
|
pub struct TitleScreen {
|
||||||
composite: WrappedComposite,
|
composite: WrappedComposite,
|
||||||
|
@ -7,7 +7,7 @@ use ezgui::{
|
|||||||
HorizontalAlignment, Key, Line, ManagedWidget, RewriteColor, Text, VerticalAlignment, Wizard,
|
HorizontalAlignment, Key, Line, ManagedWidget, RewriteColor, Text, VerticalAlignment, Wizard,
|
||||||
};
|
};
|
||||||
use geom::{Duration, Polygon, Time};
|
use geom::{Duration, Polygon, Time};
|
||||||
use std::time::Instant;
|
use instant::Instant;
|
||||||
|
|
||||||
pub struct SpeedControls {
|
pub struct SpeedControls {
|
||||||
pub composite: WrappedComposite,
|
pub composite: WrappedComposite,
|
||||||
|
@ -11,6 +11,7 @@ geo = "0.12.0"
|
|||||||
geo-booleanop = "0.2.0"
|
geo-booleanop = "0.2.0"
|
||||||
geo-offset = "0.1.0"
|
geo-offset = "0.1.0"
|
||||||
histogram = "0.6.9"
|
histogram = "0.6.9"
|
||||||
|
instant = "0.1.2"
|
||||||
ordered-float = "1.0.1"
|
ordered-float = "1.0.1"
|
||||||
polylabel = { git = "https://github.com/urschrei/polylabel-rs" }
|
polylabel = { git = "https://github.com/urschrei/polylabel-rs" }
|
||||||
serde = "1.0.98"
|
serde = "1.0.98"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{trim_f64, Distance, Speed};
|
use crate::{trim_f64, Distance, Speed};
|
||||||
use abstutil::elapsed_seconds;
|
use abstutil::elapsed_seconds;
|
||||||
|
use instant::Instant;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::time::Instant;
|
|
||||||
use std::{cmp, f64, ops};
|
use std::{cmp, f64, ops};
|
||||||
|
|
||||||
// In seconds. Can be negative.
|
// In seconds. Can be negative.
|
||||||
|
@ -8,6 +8,7 @@ edition = "2018"
|
|||||||
abstutil = { path = "../abstutil" }
|
abstutil = { path = "../abstutil" }
|
||||||
derivative = "1.0.0"
|
derivative = "1.0.0"
|
||||||
geom = { path = "../geom" }
|
geom = { path = "../geom" }
|
||||||
|
instant = "0.1.2"
|
||||||
map_model = { path = "../map_model" }
|
map_model = { path = "../map_model" }
|
||||||
rand = "0.7.0"
|
rand = "0.7.0"
|
||||||
rand_xorshift = "0.2.0"
|
rand_xorshift = "0.2.0"
|
||||||
|
@ -9,6 +9,7 @@ use crate::{
|
|||||||
use abstutil::Timer;
|
use abstutil::Timer;
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use geom::{Distance, Duration, PolyLine, Pt2D, Time};
|
use geom::{Distance, Duration, PolyLine, Pt2D, Time};
|
||||||
|
use instant::Instant;
|
||||||
use map_model::{
|
use map_model::{
|
||||||
BuildingID, BusRoute, BusRouteID, IntersectionID, LaneID, Map, Path, PathConstraints,
|
BuildingID, BusRoute, BusRouteID, IntersectionID, LaneID, Map, Path, PathConstraints,
|
||||||
PathRequest, PathStep, Traversable,
|
PathRequest, PathStep, Traversable,
|
||||||
@ -16,7 +17,6 @@ use map_model::{
|
|||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::collections::{BTreeMap, HashSet};
|
use std::collections::{BTreeMap, HashSet};
|
||||||
use std::panic;
|
use std::panic;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
// TODO Do something else.
|
// TODO Do something else.
|
||||||
const BLIND_RETRY_TO_SPAWN: Duration = Duration::const_seconds(5.0);
|
const BLIND_RETRY_TO_SPAWN: Duration = Duration::const_seconds(5.0);
|
||||||
|
Loading…
Reference in New Issue
Block a user