add basic hatching support to fragment shader. use it to visualize map

edits when zoomed in
This commit is contained in:
Dustin Carlino 2019-05-12 16:40:52 -07:00
parent ba71d2d5e6
commit f4620c1951
7 changed files with 108 additions and 47 deletions

View File

@ -179,18 +179,9 @@ impl EditMode {
);
common.draw(g, &state.ui);
// TODO Similar to drawing areas with traffic or not -- would be convenient to just
// supply a set of things to highlight and have something else take care of drawing
// with detail or not.
let zoomed = g.canvas.cam_zoom >= MIN_ZOOM_FOR_DETAIL;
let color = if zoomed {
state
.ui
.cs
.get_def("zoomed map diffs", Color::RED.alpha(0.5))
} else {
state.ui.cs.get_def("unzoomed map diffs", Color::RED)
};
// More generally we might want to show the diff between two edits, but for now,
// just show diff relative to basemap.
let edits = state.ui.primary.map.get_edits();
let ctx = DrawCtx {
cs: &state.ui.cs,
@ -200,33 +191,55 @@ impl EditMode {
};
let mut opts = DrawOptions::new();
// More generally we might want to show the diff between two edits, but for now,
// just show diff relative to basemap.
let edits = state.ui.primary.map.get_edits();
for l in edits.lane_overrides.keys() {
if zoomed {
opts.override_colors.insert(ID::Lane(*l), color);
state.ui.primary.draw_map.get_l(*l).draw(g, &opts, &ctx);
} else {
g.draw_polygon(
color,
&state
.ui
.primary
.map
.get_parent(*l)
.get_thick_polygon()
.unwrap(),
);
// TODO Similar to drawing areas with traffic or not -- would be convenient to just
// supply a set of things to highlight and have something else take care of drawing
// with detail or not.
if g.canvas.cam_zoom >= MIN_ZOOM_FOR_DETAIL {
g.enable_hatching();
for l in edits.lane_overrides.keys() {
ctx.draw_map.get_l(*l).draw(g, &opts, &ctx);
}
for i in edits
.stop_sign_overrides
.keys()
.chain(edits.traffic_signal_overrides.keys())
{
ctx.draw_map.get_i(*i).draw(g, &opts, &ctx);
}
g.disable_hatching();
// The hatching covers up the selection outline, so redraw it.
match state.ui.primary.current_selection {
Some(ID::Lane(l)) => {
g.draw_polygon(
state.ui.cs.get("selected"),
&ctx.draw_map.get_l(l).get_outline(&ctx.map),
);
}
Some(ID::Intersection(i)) => {
g.draw_polygon(
state.ui.cs.get("selected"),
&ctx.draw_map.get_i(i).get_outline(&ctx.map),
);
}
_ => {}
}
} else {
let color = state.ui.cs.get_def("unzoomed map diffs", Color::RED);
for l in edits.lane_overrides.keys() {
g.draw_polygon(color, &ctx.map.get_parent(*l).get_thick_polygon().unwrap());
}
for i in edits
.stop_sign_overrides
.keys()
.chain(edits.traffic_signal_overrides.keys())
{
opts.override_colors.insert(ID::Intersection(*i), color);
ctx.draw_map.get_i(*i).draw(g, &opts, &ctx);
}
}
for i in edits
.stop_sign_overrides
.keys()
.chain(edits.traffic_signal_overrides.keys())
{
opts.override_colors.insert(ID::Intersection(*i), color);
state.ui.primary.draw_map.get_i(*i).draw(g, &opts, &ctx);
}
menu.draw(g);

View File

@ -1,7 +1,12 @@
#version 110
varying vec4 pass_color;
varying float pass_hatching;
void main() {
gl_FragColor = pass_color;
if (pass_hatching == 1.0 && mod(gl_FragCoord.x + gl_FragCoord.y, 20.0) <= 5.0) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}

View File

@ -1,8 +1,13 @@
#version 140
in vec4 pass_color;
in float pass_hatching;
out vec4 f_color;
void main() {
f_color = pass_color;
if (pass_hatching == 1.0 && mod(gl_FragCoord.x + gl_FragCoord.y, 20.0) <= 5.0) {
f_color = vec4(0.0, 0.0, 0.0, 1.0);
}
}

View File

@ -2,15 +2,17 @@
// (x offset, y offset, zoom)
uniform vec3 transform;
// (window width, window height)
uniform vec2 window;
// (window width, window height, hatching == 1.0)
uniform vec3 window;
attribute vec2 position;
attribute vec4 color;
varying vec4 pass_color;
varying float pass_hatching;
void main() {
pass_color = color / 255.0;
pass_hatching = window[2];
// This is map_to_screen
float screen_x = (position[0] * transform[2]) - transform[0];

View File

@ -2,15 +2,17 @@
// (x offset, y offset, zoom)
uniform vec3 transform;
// (window width, window height)
uniform vec2 window;
// (window width, window height, hatching == 1.0)
uniform vec3 window;
in vec2 position;
in vec4 color;
out vec4 pass_color;
out float pass_hatching;
void main() {
pass_color = color / 255.0;
pass_hatching = window[2];
// This is map_to_screen
float screen_x = (position[0] * transform[2]) - transform[0];

View File

@ -6,11 +6,16 @@ use crate::{
use geom::{Bounds, Circle, Distance, Line, Polygon, Pt2D};
use glium::{uniform, Surface};
// transform is (cam_x, cam_y, cam_zoom)
// window is (window_width, window_height, hatching == 1.0)
// Things are awkwardly grouped because passing uniforms is either broken or horribly documented.
type Uniforms<'a> = glium::uniforms::UniformsStorage<
'a,
[f32; 2],
[f32; 3],
glium::uniforms::UniformsStorage<'a, [f32; 3], glium::uniforms::EmptyUniforms>,
>;
const NO_HATCHING: f32 = 0.0;
const HATCHING: f32 = 1.0;
pub struct GfxCtx<'a> {
pub(crate) target: &'a mut glium::Frame,
@ -28,6 +33,7 @@ pub struct GfxCtx<'a> {
context_menu: &'a ContextMenu,
pub num_draw_calls: usize,
hatching: f32,
}
impl<'a> GfxCtx<'a> {
@ -47,7 +53,7 @@ impl<'a> GfxCtx<'a> {
let uniforms = uniform! {
transform: [canvas.cam_x as f32, canvas.cam_y as f32, canvas.cam_zoom as f32],
window: [canvas.window_width as f32, canvas.window_height as f32],
window: [canvas.window_width as f32, canvas.window_height as f32, NO_HATCHING],
};
GfxCtx {
@ -62,6 +68,7 @@ impl<'a> GfxCtx<'a> {
screencap_mode,
naming_hint: None,
context_menu,
hatching: NO_HATCHING,
}
}
@ -75,21 +82,21 @@ impl<'a> GfxCtx<'a> {
self.uniforms = uniform! {
transform: [cam_x as f32, cam_y as f32, zoom as f32],
window: [self.canvas.window_width as f32, self.canvas.window_height as f32],
window: [self.canvas.window_width as f32, self.canvas.window_height as f32, self.hatching],
};
}
pub fn fork_screenspace(&mut self) {
self.uniforms = uniform! {
transform: [0.0, 0.0, 1.0],
window: [self.canvas.window_width as f32, self.canvas.window_height as f32],
window: [self.canvas.window_width as f32, self.canvas.window_height as f32, self.hatching],
};
}
pub fn unfork(&mut self) {
self.uniforms = uniform! {
transform: [self.canvas.cam_x as f32, self.canvas.cam_y as f32, self.canvas.cam_zoom as f32],
window: [self.canvas.window_width as f32, self.canvas.window_height as f32],
window: [self.canvas.window_width as f32, self.canvas.window_height as f32, self.hatching],
};
}
@ -149,6 +156,18 @@ impl<'a> GfxCtx<'a> {
self.num_draw_calls += 1;
}
pub fn enable_hatching(&mut self) {
assert_eq!(self.hatching, NO_HATCHING);
self.hatching = HATCHING;
self.unfork();
}
pub fn disable_hatching(&mut self) {
assert_eq!(self.hatching, HATCHING);
self.hatching = NO_HATCHING;
self.unfork();
}
// Canvas stuff.
// The text box covers up what's beneath and eats the cursor (for get_cursor_in_map_space).

View File

@ -163,6 +163,21 @@ pub fn run<G: GUI, F: FnOnce(&mut EventCtx) -> G>(
);
};
// To quickly iterate on shaders without recompiling...
/*let mut vert = String::new();
let mut frag = String::new();
let (vertex_shader, fragment_shader) = {
use std::io::Read;
let mut f1 = std::fs::File:: open("../ezgui/src/assets/vertex_110.glsl").unwrap();
f1.read_to_string(&mut vert).unwrap();
let mut f2 = std::fs::File:: open("../ezgui/src/assets/fragment_110.glsl").unwrap();
f2.read_to_string(&mut frag).unwrap();
(&vert, &frag)
};*/
let program = glium::Program::new(
&display,
glium::program::ProgramCreationInput::SourceCode {