simplify some render/ code by using GeomBatch

This commit is contained in:
Dustin Carlino 2019-05-17 12:49:50 -07:00
parent 222ddf6a96
commit de51b1c154
12 changed files with 163 additions and 192 deletions

View File

@ -1,6 +1,6 @@
use crate::helpers::{ColorScheme, ID}; use crate::helpers::{ColorScheme, ID};
use crate::render::{DrawCtx, DrawOptions, Renderable}; use crate::render::{DrawCtx, DrawOptions, Renderable};
use ezgui::{Color, GfxCtx}; use ezgui::{Color, GeomBatch, GfxCtx};
use geom::Polygon; use geom::Polygon;
use map_model::{Area, AreaID, AreaType, Map}; use map_model::{Area, AreaID, AreaType, Map};
@ -9,13 +9,15 @@ pub struct DrawArea {
} }
impl DrawArea { impl DrawArea {
pub fn new(area: &Area, cs: &ColorScheme) -> (DrawArea, Color, Polygon) { pub fn new(area: &Area, cs: &ColorScheme, batch: &mut GeomBatch) -> DrawArea {
let color = match area.area_type { batch.push(
match area.area_type {
AreaType::Park => cs.get_def("park area", Color::rgb(200, 250, 204)), AreaType::Park => cs.get_def("park area", Color::rgb(200, 250, 204)),
AreaType::Water => cs.get_def("water area", Color::rgb(170, 211, 223)), AreaType::Water => cs.get_def("water area", Color::rgb(170, 211, 223)),
}; },
area.polygon.clone(),
(DrawArea { id: area.id }, color, area.polygon.clone()) );
DrawArea { id: area.id }
} }
} }

View File

@ -1,6 +1,6 @@
use crate::helpers::{ColorScheme, ID}; use crate::helpers::{ColorScheme, ID};
use crate::render::{DrawCtx, DrawOptions, Renderable}; use crate::render::{DrawCtx, DrawOptions, Renderable};
use ezgui::{Color, Drawable, GfxCtx, Prerender}; use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
use geom::{Circle, Distance, Line, PolyLine, Polygon}; use geom::{Circle, Distance, Line, PolyLine, Polygon};
use map_model::{Map, LANE_THICKNESS}; use map_model::{Map, LANE_THICKNESS};
use sim::{CarID, CarStatus, DrawCarInput}; use sim::{CarID, CarStatus, DrawCarInput};
@ -21,7 +21,7 @@ impl DrawBike {
prerender: &Prerender, prerender: &Prerender,
cs: &ColorScheme, cs: &ColorScheme,
) -> DrawBike { ) -> DrawBike {
let mut draw_default = Vec::new(); let mut draw_default = GeomBatch::new();
// TODO Share constants with DrawPedestrian // TODO Share constants with DrawPedestrian
let body_radius = LANE_THICKNESS / 4.0; let body_radius = LANE_THICKNESS / 4.0;
@ -33,48 +33,48 @@ impl DrawBike {
CarStatus::Stuck => cs.get_def("stuck bike", Color::RED), CarStatus::Stuck => cs.get_def("stuck bike", Color::RED),
CarStatus::Parked => panic!("Can't have a parked bike {}", input.id), CarStatus::Parked => panic!("Can't have a parked bike {}", input.id),
}; };
draw_default.push(( draw_default.push(
cs.get_def("bike frame", Color::rgb(0, 128, 128)), cs.get_def("bike frame", Color::rgb(0, 128, 128)),
input.body.make_polygons(Distance::meters(0.4)), input.body.make_polygons(Distance::meters(0.4)),
)); );
let (body_pos, facing) = input.body.dist_along(0.4 * input.body.length()); let (body_pos, facing) = input.body.dist_along(0.4 * input.body.length());
let body_circle = Circle::new(body_pos, body_radius); let body_circle = Circle::new(body_pos, body_radius);
draw_default.push((body_color, body_circle.to_polygon())); draw_default.push(body_color, body_circle.to_polygon());
draw_default.push(( draw_default.push(
cs.get("pedestrian head"), cs.get("pedestrian head"),
Circle::new(body_pos, 0.5 * body_radius).to_polygon(), Circle::new(body_pos, 0.5 * body_radius).to_polygon(),
)); );
{ {
// Handlebars // Handlebars
let (hand_pos, hand_angle) = input.body.dist_along(0.9 * input.body.length()); let (hand_pos, hand_angle) = input.body.dist_along(0.9 * input.body.length());
draw_default.push(( draw_default.push(
cs.get("bike frame"), cs.get("bike frame"),
Line::new( Line::new(
hand_pos.project_away(body_radius, hand_angle.rotate_degs(90.0)), hand_pos.project_away(body_radius, hand_angle.rotate_degs(90.0)),
hand_pos.project_away(body_radius, hand_angle.rotate_degs(-90.0)), hand_pos.project_away(body_radius, hand_angle.rotate_degs(-90.0)),
) )
.make_polygons(Distance::meters(0.1)), .make_polygons(Distance::meters(0.1)),
)); );
// Hands // Hands
draw_default.push(( draw_default.push(
body_color, body_color,
Line::new( Line::new(
body_pos.project_away(0.9 * body_radius, facing.rotate_degs(-30.0)), body_pos.project_away(0.9 * body_radius, facing.rotate_degs(-30.0)),
hand_pos.project_away(0.4 * body_radius, hand_angle.rotate_degs(-90.0)), hand_pos.project_away(0.4 * body_radius, hand_angle.rotate_degs(-90.0)),
) )
.make_polygons(Distance::meters(0.08)), .make_polygons(Distance::meters(0.08)),
)); );
draw_default.push(( draw_default.push(
body_color, body_color,
Line::new( Line::new(
body_pos.project_away(0.9 * body_radius, facing.rotate_degs(30.0)), body_pos.project_away(0.9 * body_radius, facing.rotate_degs(30.0)),
hand_pos.project_away(0.4 * body_radius, hand_angle.rotate_degs(90.0)), hand_pos.project_away(0.4 * body_radius, hand_angle.rotate_degs(90.0)),
) )
.make_polygons(Distance::meters(0.08)), .make_polygons(Distance::meters(0.08)),
)); );
} }
if let Some(t) = input.waiting_for_turn { if let Some(t) = input.waiting_for_turn {
@ -86,7 +86,7 @@ impl DrawBike {
.make_arrow(Distance::meters(0.25)) .make_arrow(Distance::meters(0.25))
.unwrap() .unwrap()
{ {
draw_default.push((cs.get("blinker on"), poly)); draw_default.push(cs.get("blinker on"), poly);
} }
} }

View File

@ -1,6 +1,6 @@
use crate::helpers::{ColorScheme, ID}; use crate::helpers::{ColorScheme, ID};
use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS}; use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
use ezgui::{Color, GfxCtx}; use ezgui::{Color, GeomBatch, GfxCtx};
use geom::{Distance, Line, PolyLine, Polygon, Pt2D}; use geom::{Distance, Line, PolyLine, Polygon, Pt2D};
use map_model::{Building, BuildingID, BuildingType, Map, LANE_THICKNESS}; use map_model::{Building, BuildingID, BuildingType, Map, LANE_THICKNESS};
@ -9,7 +9,7 @@ pub struct DrawBuilding {
} }
impl DrawBuilding { impl DrawBuilding {
pub fn new(bldg: &Building, cs: &ColorScheme) -> (DrawBuilding, Vec<(Color, Polygon)>) { pub fn new(bldg: &Building, cs: &ColorScheme, batch: &mut GeomBatch) -> DrawBuilding {
// Trim the front path line away from the sidewalk's center line, so that it doesn't // Trim the front path line away from the sidewalk's center line, so that it doesn't
// overlap. For now, this cleanup is visual; it doesn't belong in the map_model layer. // overlap. For now, this cleanup is visual; it doesn't belong in the map_model layer.
let mut front_path_line = bldg.front_path.line.clone(); let mut front_path_line = bldg.front_path.line.clone();
@ -23,25 +23,21 @@ impl DrawBuilding {
} }
let front_path = front_path_line.make_polygons(Distance::meters(1.0)); let front_path = front_path_line.make_polygons(Distance::meters(1.0));
let default_draw = vec![ batch.push(
(
match bldg.building_type { match bldg.building_type {
BuildingType::Residence => { BuildingType::Residence => {
cs.get_def("residential building", Color::rgb(218, 165, 32)) cs.get_def("residential building", Color::rgb(218, 165, 32))
} }
BuildingType::Business => { BuildingType::Business => cs.get_def("business building", Color::rgb(210, 105, 30)),
cs.get_def("business building", Color::rgb(210, 105, 30))
}
BuildingType::Unknown => { BuildingType::Unknown => {
cs.get_def("unknown building", Color::rgb_f(0.7, 0.7, 0.7)) cs.get_def("unknown building", Color::rgb_f(0.7, 0.7, 0.7))
} }
}, },
bldg.polygon.clone(), bldg.polygon.clone(),
), );
(cs.get_def("building path", Color::grey(0.6)), front_path), batch.push(cs.get_def("building path", Color::grey(0.6)), front_path);
];
(DrawBuilding { id: bldg.id }, default_draw) DrawBuilding { id: bldg.id }
} }
} }

View File

@ -1,6 +1,6 @@
use crate::helpers::{ColorScheme, ID}; use crate::helpers::{ColorScheme, ID};
use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS}; use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
use ezgui::{Color, Drawable, GfxCtx, Prerender}; use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
use geom::{Angle, Circle, Distance, PolyLine, Polygon, Pt2D}; use geom::{Angle, Circle, Distance, PolyLine, Polygon, Pt2D};
use map_model::{Map, TurnType}; use map_model::{Map, TurnType};
use sim::{CarID, CarStatus, DrawCarInput}; use sim::{CarID, CarStatus, DrawCarInput};
@ -18,10 +18,10 @@ pub struct DrawCar {
impl DrawCar { impl DrawCar {
pub fn new(input: DrawCarInput, map: &Map, prerender: &Prerender, cs: &ColorScheme) -> DrawCar { pub fn new(input: DrawCarInput, map: &Map, prerender: &Prerender, cs: &ColorScheme) -> DrawCar {
let mut draw_default = Vec::new(); let mut draw_default = GeomBatch::new();
let body_polygon = input.body.make_polygons(CAR_WIDTH); let body_polygon = input.body.make_polygons(CAR_WIDTH);
draw_default.push(( draw_default.push(
// TODO if it's a bus, color it differently -- but how? :\ // TODO if it's a bus, color it differently -- but how? :\
// TODO color.shift(input.id.0) actually looks pretty bad still // TODO color.shift(input.id.0) actually looks pretty bad still
match input.status { match input.status {
@ -31,7 +31,7 @@ impl DrawCar {
CarStatus::Parked => cs.get_def("parked car", Color::rgb(180, 233, 76)), CarStatus::Parked => cs.get_def("parked car", Color::rgb(180, 233, 76)),
}, },
body_polygon.clone(), body_polygon.clone(),
)); );
{ {
let window_length_gap = Distance::meters(0.2); let window_length_gap = Distance::meters(0.2);
@ -62,8 +62,8 @@ impl DrawCar {
angle.rotate_degs(90.0), angle.rotate_degs(90.0),
) )
}; };
draw_default.push((cs.get_def("car window", Color::BLACK), front_window)); draw_default.push(cs.get_def("car window", Color::BLACK), front_window);
draw_default.push((cs.get("car window"), back_window)); draw_default.push(cs.get("car window"), back_window);
} }
{ {
@ -95,7 +95,7 @@ impl DrawCar {
let bg_color = cs.get_def("blinker background", Color::grey(0.2)); let bg_color = cs.get_def("blinker background", Color::grey(0.2));
for c in vec![&front_left, &front_right, &back_left, &back_right] { for c in vec![&front_left, &front_right, &back_left, &back_right] {
draw_default.push((bg_color, c.to_polygon())); draw_default.push(bg_color, c.to_polygon());
} }
let arrow_color = cs.get_def("blinker on", Color::RED); let arrow_color = cs.get_def("blinker on", Color::RED);
@ -105,33 +105,33 @@ impl DrawCar {
match turn.turn_type { match turn.turn_type {
TurnType::Left | TurnType::LaneChangeLeft => { TurnType::Left | TurnType::LaneChangeLeft => {
for circle in vec![front_left, back_left] { for circle in vec![front_left, back_left] {
for poly in PolyLine::new(vec![ draw_default.extend(
arrow_color,
PolyLine::new(vec![
circle.center.project_away(radius / 2.0, angle.opposite()), circle.center.project_away(radius / 2.0, angle.opposite()),
circle.center.project_away(radius / 2.0, angle), circle.center.project_away(radius / 2.0, angle),
]) ])
.make_arrow(Distance::meters(0.15)) .make_arrow(Distance::meters(0.15))
.unwrap() .unwrap(),
{ );
draw_default.push((arrow_color, poly));
}
} }
} }
TurnType::Right | TurnType::LaneChangeRight => { TurnType::Right | TurnType::LaneChangeRight => {
for circle in vec![front_right, back_right] { for circle in vec![front_right, back_right] {
for poly in PolyLine::new(vec![ draw_default.extend(
arrow_color,
PolyLine::new(vec![
circle.center.project_away(radius / 2.0, angle.opposite()), circle.center.project_away(radius / 2.0, angle.opposite()),
circle.center.project_away(radius / 2.0, angle), circle.center.project_away(radius / 2.0, angle),
]) ])
.make_arrow(Distance::meters(0.15)) .make_arrow(Distance::meters(0.15))
.unwrap() .unwrap(),
{ );
draw_default.push((arrow_color, poly));
}
} }
} }
TurnType::Straight => { TurnType::Straight => {
draw_default.push((arrow_color, back_left.to_polygon())); draw_default.push(arrow_color, back_left.to_polygon());
draw_default.push((arrow_color, back_right.to_polygon())); draw_default.push(arrow_color, back_right.to_polygon());
} }
TurnType::Crosswalk | TurnType::SharedSidewalkCorner => unreachable!(), TurnType::Crosswalk | TurnType::SharedSidewalkCorner => unreachable!(),
} }

View File

@ -27,7 +27,8 @@ impl DrawIntersection {
timer: &mut Timer, timer: &mut Timer,
) -> DrawIntersection { ) -> DrawIntersection {
// Order matters... main polygon first, then sidewalk corners. // Order matters... main polygon first, then sidewalk corners.
let mut default_geom = vec![( let mut default_geom = GeomBatch::new();
default_geom.push(
match i.intersection_type { match i.intersection_type {
IntersectionType::Border => { IntersectionType::Border => {
cs.get_def("border intersection", Color::rgb(50, 205, 50)) cs.get_def("border intersection", Color::rgb(50, 205, 50))
@ -40,12 +41,8 @@ impl DrawIntersection {
} }
}, },
i.polygon.clone(), i.polygon.clone(),
)];
default_geom.extend(
calculate_corners(i, map, timer)
.into_iter()
.map(|p| (cs.get("sidewalk"), p)),
); );
default_geom.extend(cs.get("sidewalk"), calculate_corners(i, map, timer));
match i.intersection_type { match i.intersection_type {
IntersectionType::Border => { IntersectionType::Border => {
if i.roads.len() != 1 { if i.roads.len() != 1 {
@ -53,13 +50,12 @@ impl DrawIntersection {
} }
let r = map.get_r(*i.roads.iter().next().unwrap()); let r = map.get_r(*i.roads.iter().next().unwrap());
default_geom.extend( default_geom.extend(
calculate_border_arrows(i, r, timer) cs.get_def("incoming border node arrow", Color::PURPLE),
.into_iter() calculate_border_arrows(i, r, timer),
.map(|p| (cs.get_def("incoming border node arrow", Color::PURPLE), p)),
); );
} }
IntersectionType::StopSign => { IntersectionType::StopSign => {
default_geom.extend(calculate_stop_sign(map, cs, map.get_stop_sign(i.id))); calculate_stop_sign(&mut default_geom, map, cs, map.get_stop_sign(i.id));
} }
IntersectionType::TrafficSignal => {} IntersectionType::TrafficSignal => {}
} }
@ -498,14 +494,9 @@ fn calculate_border_arrows(i: &Intersection, r: &Road, timer: &mut Timer) -> Vec
result result
} }
fn calculate_stop_sign( fn calculate_stop_sign(batch: &mut GeomBatch, map: &Map, cs: &ColorScheme, sign: &ControlStopSign) {
map: &Map,
cs: &ColorScheme,
sign: &ControlStopSign,
) -> Vec<(Color, Polygon)> {
let trim_back = Distance::meters(0.7); let trim_back = Distance::meters(0.7);
let mut result = Vec::new();
for (_, ss) in &sign.roads { for (_, ss) in &sign.roads {
if ss.enabled { if ss.enabled {
let rightmost = &map.get_l(*ss.travel_lanes.last().unwrap()).lane_center_pts; let rightmost = &map.get_l(*ss.travel_lanes.last().unwrap()).lane_center_pts;
@ -517,12 +508,12 @@ fn calculate_stop_sign(
.last_line() .last_line()
.shift_right(1.0 * LANE_THICKNESS); .shift_right(1.0 * LANE_THICKNESS);
result.push(( batch.push(
cs.get_def("stop sign on side of road", Color::RED), cs.get_def("stop sign on side of road", Color::RED),
make_octagon(last_line.pt2(), Distance::meters(1.0), last_line.angle()), make_octagon(last_line.pt2(), Distance::meters(1.0), last_line.angle()),
)); );
// A little pole for it too! // A little pole for it too!
result.push(( batch.push(
cs.get_def("stop sign pole", Color::grey(0.5)), cs.get_def("stop sign pole", Color::grey(0.5)),
Line::new( Line::new(
last_line last_line
@ -534,10 +525,9 @@ fn calculate_stop_sign(
.project_away(Distance::meters(0.9), last_line.angle().opposite()), .project_away(Distance::meters(0.9), last_line.angle().opposite()),
) )
.make_polygons(Distance::meters(0.3)), .make_polygons(Distance::meters(0.3)),
)); );
} }
} }
result
} }
// TODO A squished octagon would look better // TODO A squished octagon would look better

View File

@ -1,7 +1,7 @@
use crate::helpers::{ColorScheme, ID}; use crate::helpers::{ColorScheme, ID};
use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS}; use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
use abstutil::Timer; use abstutil::Timer;
use ezgui::{Color, Drawable, GfxCtx, Prerender}; use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
use geom::{Circle, Distance, Line, PolyLine, Polygon, Pt2D}; use geom::{Circle, Distance, Line, PolyLine, Polygon, Pt2D};
use map_model::{Lane, LaneID, LaneType, Map, Road, TurnType, LANE_THICKNESS, PARKING_SPOT_LENGTH}; use map_model::{Lane, LaneID, LaneType, Map, Road, TurnType, LANE_THICKNESS, PARKING_SPOT_LENGTH};
@ -25,7 +25,8 @@ impl DrawLane {
let road = map.get_r(lane.parent); let road = map.get_r(lane.parent);
let polygon = lane.lane_center_pts.make_polygons(LANE_THICKNESS); let polygon = lane.lane_center_pts.make_polygons(LANE_THICKNESS);
let mut draw: Vec<(Color, Polygon)> = vec![( let mut draw = GeomBatch::new();
draw.push(
match lane.lane_type { match lane.lane_type {
LaneType::Driving => cs.get_def("driving lane", Color::BLACK), LaneType::Driving => cs.get_def("driving lane", Color::BLACK),
LaneType::Bus => cs.get_def("bus lane", Color::rgb(190, 74, 76)), LaneType::Bus => cs.get_def("bus lane", Color::rgb(190, 74, 76)),
@ -34,18 +35,30 @@ impl DrawLane {
LaneType::Biking => cs.get_def("bike lane", Color::rgb(15, 125, 75)), LaneType::Biking => cs.get_def("bike lane", Color::rgb(15, 125, 75)),
}, },
polygon.clone(), polygon.clone(),
)]; );
if draw_lane_markings { if draw_lane_markings {
match lane.lane_type { match lane.lane_type {
LaneType::Sidewalk => { LaneType::Sidewalk => {
draw.extend(calculate_sidewalk_lines(lane, cs)); draw.extend(
cs.get_def("sidewalk lines", Color::grey(0.7)),
calculate_sidewalk_lines(lane),
);
} }
LaneType::Parking => { LaneType::Parking => {
draw.extend(calculate_parking_lines(lane, cs)); draw.extend(
cs.get_def("parking lines", Color::WHITE),
calculate_parking_lines(lane),
);
} }
LaneType::Driving | LaneType::Bus => { LaneType::Driving | LaneType::Bus => {
draw.extend(calculate_driving_lines(lane, road, cs, timer)); draw.extend(
draw.extend(calculate_turn_markings(map, lane, cs, timer)); cs.get_def("dashed lane line", Color::WHITE),
calculate_driving_lines(lane, road, timer),
);
draw.extend(
cs.get_def("turn restrictions on lane", Color::WHITE),
calculate_turn_markings(map, lane, timer),
);
} }
LaneType::Biking => {} LaneType::Biking => {}
}; };
@ -121,9 +134,8 @@ fn perp_line(l: Line, length: Distance) -> Line {
Line::new(pt1, pt2) Line::new(pt1, pt2)
} }
fn calculate_sidewalk_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygon)> { fn calculate_sidewalk_lines(lane: &Lane) -> Vec<Polygon> {
let tile_every = LANE_THICKNESS; let tile_every = LANE_THICKNESS;
let color = cs.get_def("sidewalk lines", Color::grey(0.7));
let length = lane.length(); let length = lane.length();
@ -134,20 +146,18 @@ fn calculate_sidewalk_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygo
let (pt, angle) = lane.dist_along(dist_along); let (pt, angle) = lane.dist_along(dist_along);
// Reuse perp_line. Project away an arbitrary amount // Reuse perp_line. Project away an arbitrary amount
let pt2 = pt.project_away(Distance::meters(1.0), angle); let pt2 = pt.project_away(Distance::meters(1.0), angle);
result.push(( result.push(
color,
perp_line(Line::new(pt, pt2), LANE_THICKNESS).make_polygons(Distance::meters(0.25)), perp_line(Line::new(pt, pt2), LANE_THICKNESS).make_polygons(Distance::meters(0.25)),
)); );
dist_along += tile_every; dist_along += tile_every;
} }
result result
} }
fn calculate_parking_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygon)> { fn calculate_parking_lines(lane: &Lane) -> Vec<Polygon> {
// meters, but the dims get annoying below to remove // meters, but the dims get annoying below to remove
let leg_length = Distance::meters(1.0); let leg_length = Distance::meters(1.0);
let color = cs.get_def("parking lines", Color::WHITE);
let mut result = Vec::new(); let mut result = Vec::new();
let num_spots = lane.number_parking_spots(); let num_spots = lane.number_parking_spots();
@ -160,34 +170,20 @@ fn calculate_parking_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygon
let t_pt = pt.project_away(LANE_THICKNESS * 0.4, perp_angle); let t_pt = pt.project_away(LANE_THICKNESS * 0.4, perp_angle);
// The perp leg // The perp leg
let p1 = t_pt.project_away(leg_length, perp_angle.opposite()); let p1 = t_pt.project_away(leg_length, perp_angle.opposite());
result.push(( result.push(Line::new(t_pt, p1).make_polygons(Distance::meters(0.25)));
color,
Line::new(t_pt, p1).make_polygons(Distance::meters(0.25)),
));
// Upper leg // Upper leg
let p2 = t_pt.project_away(leg_length, lane_angle); let p2 = t_pt.project_away(leg_length, lane_angle);
result.push(( result.push(Line::new(t_pt, p2).make_polygons(Distance::meters(0.25)));
color,
Line::new(t_pt, p2).make_polygons(Distance::meters(0.25)),
));
// Lower leg // Lower leg
let p3 = t_pt.project_away(leg_length, lane_angle.opposite()); let p3 = t_pt.project_away(leg_length, lane_angle.opposite());
result.push(( result.push(Line::new(t_pt, p3).make_polygons(Distance::meters(0.25)));
color,
Line::new(t_pt, p3).make_polygons(Distance::meters(0.25)),
));
} }
} }
result result
} }
fn calculate_driving_lines( fn calculate_driving_lines(lane: &Lane, parent: &Road, timer: &mut Timer) -> Vec<Polygon> {
lane: &Lane,
parent: &Road,
cs: &ColorScheme,
timer: &mut Timer,
) -> Vec<(Color, Polygon)> {
// The leftmost lanes don't have dashed white lines. // The leftmost lanes don't have dashed white lines.
if parent.dir_and_offset(lane.id).1 == 0 { if parent.dir_and_offset(lane.id).1 == 0 {
return Vec::new(); return Vec::new();
@ -204,22 +200,13 @@ fn calculate_driving_lines(
return Vec::new(); return Vec::new();
} }
// Don't draw the dashes too close to the ends. // Don't draw the dashes too close to the ends.
let polygons = lane_edge_pts lane_edge_pts
.exact_slice(dash_separation, lane_edge_pts.length() - dash_separation) .exact_slice(dash_separation, lane_edge_pts.length() - dash_separation)
.dashed_polygons(Distance::meters(0.25), dash_len, dash_separation); .dashed_polygons(Distance::meters(0.25), dash_len, dash_separation)
polygons
.into_iter()
.map(|p| (cs.get_def("dashed lane line", Color::WHITE), p))
.collect()
} }
fn calculate_turn_markings( fn calculate_turn_markings(map: &Map, lane: &Lane, timer: &mut Timer) -> Vec<Polygon> {
map: &Map, let mut results = Vec::new();
lane: &Lane,
cs: &ColorScheme,
timer: &mut Timer,
) -> Vec<(Color, Polygon)> {
let mut results: Vec<(Color, Polygon)> = Vec::new();
// Are there multiple driving lanes on this side of the road? // Are there multiple driving lanes on this side of the road?
if map if map
@ -232,14 +219,13 @@ fn calculate_turn_markings(
return results; return results;
} }
let color = cs.get_def("turn restrictions on lane", Color::WHITE);
let thickness = Distance::meters(0.2); let thickness = Distance::meters(0.2);
let common_base = lane.lane_center_pts.exact_slice( let common_base = lane.lane_center_pts.exact_slice(
lane.length() - Distance::meters(7.0), lane.length() - Distance::meters(7.0),
lane.length() - Distance::meters(5.0), lane.length() - Distance::meters(5.0),
); );
results.push((color, common_base.make_polygons(thickness))); results.push(common_base.make_polygons(thickness));
// TODO Maybe draw arrows per target road, not lane // TODO Maybe draw arrows per target road, not lane
for turn in map.get_turns_from_lane(lane.id) { for turn in map.get_turns_from_lane(lane.id) {
@ -255,9 +241,7 @@ fn calculate_turn_markings(
.project_away(LANE_THICKNESS / 2.0, turn.angle()), .project_away(LANE_THICKNESS / 2.0, turn.angle()),
]) ])
.make_arrow(thickness) .make_arrow(thickness)
.with_context(timer, format!("turn_markings for {}", turn.id)) .with_context(timer, format!("turn_markings for {}", turn.id)),
.into_iter()
.map(|p| (color, p)),
); );
} }

View File

@ -11,8 +11,8 @@ use crate::render::Renderable;
use crate::ui::Flags; use crate::ui::Flags;
use aabb_quadtree::QuadTree; use aabb_quadtree::QuadTree;
use abstutil::Timer; use abstutil::Timer;
use ezgui::{Color, Drawable, Prerender}; use ezgui::{Color, Drawable, GeomBatch, Prerender};
use geom::{Bounds, Duration, FindClosest, Polygon}; use geom::{Bounds, Duration, FindClosest};
use map_model::{ use map_model::{
AreaID, BuildingID, BusStopID, DirectedRoadID, IntersectionID, IntersectionType, Lane, LaneID, AreaID, BuildingID, BusStopID, DirectedRoadID, IntersectionID, IntersectionType, Lane, LaneID,
Map, RoadID, Traversable, Turn, TurnID, TurnType, LANE_THICKNESS, Map, RoadID, Traversable, Turn, TurnID, TurnType, LANE_THICKNESS,
@ -52,19 +52,19 @@ impl DrawMap {
timer: &mut Timer, timer: &mut Timer,
) -> DrawMap { ) -> DrawMap {
let mut roads: Vec<DrawRoad> = Vec::new(); let mut roads: Vec<DrawRoad> = Vec::new();
let mut all_roads: Vec<(Color, Polygon)> = Vec::new(); let mut all_roads = GeomBatch::new();
timer.start_iter("make DrawRoads", map.all_roads().len()); timer.start_iter("make DrawRoads", map.all_roads().len());
for r in map.all_roads() { for r in map.all_roads() {
timer.next(); timer.next();
let draw_r = DrawRoad::new(r, cs, prerender); let draw_r = DrawRoad::new(r, cs, prerender);
all_roads.push(( all_roads.push(
osm_rank_to_color(cs, r.get_rank()), osm_rank_to_color(cs, r.get_rank()),
r.get_thick_polygon().get(timer), r.get_thick_polygon().get(timer),
)); );
all_roads.push(( all_roads.push(
cs.get_def("unzoomed outline", Color::BLACK), cs.get_def("unzoomed outline", Color::BLACK),
draw_r.get_outline(map), draw_r.get_outline(map),
)); );
roads.push(draw_r); roads.push(draw_r);
} }
let draw_all_thick_roads = prerender.upload(all_roads); let draw_all_thick_roads = prerender.upload(all_roads);
@ -100,32 +100,30 @@ impl DrawMap {
} }
let mut intersections: Vec<DrawIntersection> = Vec::new(); let mut intersections: Vec<DrawIntersection> = Vec::new();
let mut all_intersections: Vec<(Color, Polygon)> = Vec::new(); let mut all_intersections = GeomBatch::new();
timer.start_iter("make DrawIntersections", map.all_intersections().len()); timer.start_iter("make DrawIntersections", map.all_intersections().len());
for i in map.all_intersections() { for i in map.all_intersections() {
timer.next(); timer.next();
let draw_i = DrawIntersection::new(i, map, cs, prerender, timer); let draw_i = DrawIntersection::new(i, map, cs, prerender, timer);
if i.intersection_type == IntersectionType::StopSign { if i.intersection_type == IntersectionType::StopSign {
all_intersections.push((osm_rank_to_color(cs, i.get_rank(map)), i.polygon.clone())); all_intersections.push(osm_rank_to_color(cs, i.get_rank(map)), i.polygon.clone());
all_intersections.push((cs.get("unzoomed outline"), draw_i.get_outline(map))); all_intersections.push(cs.get("unzoomed outline"), draw_i.get_outline(map));
} else { } else {
all_intersections.push(( all_intersections.push(
cs.get_def("unzoomed interesting intersection", Color::BLACK), cs.get_def("unzoomed interesting intersection", Color::BLACK),
i.polygon.clone(), i.polygon.clone(),
)); );
} }
intersections.push(draw_i); intersections.push(draw_i);
} }
let draw_all_unzoomed_intersections = prerender.upload(all_intersections); let draw_all_unzoomed_intersections = prerender.upload(all_intersections);
let mut buildings: Vec<DrawBuilding> = Vec::new(); let mut buildings: Vec<DrawBuilding> = Vec::new();
let mut all_buildings: Vec<(Color, Polygon)> = Vec::new(); let mut all_buildings = GeomBatch::new();
timer.start_iter("make DrawBuildings", map.all_buildings().len()); timer.start_iter("make DrawBuildings", map.all_buildings().len());
for b in map.all_buildings() { for b in map.all_buildings() {
timer.next(); timer.next();
let (b, draw) = DrawBuilding::new(b, cs); buildings.push(DrawBuilding::new(b, cs, &mut all_buildings));
buildings.push(b);
all_buildings.extend(draw);
} }
let draw_all_buildings = prerender.upload(all_buildings); let draw_all_buildings = prerender.upload(all_buildings);
@ -169,13 +167,11 @@ impl DrawMap {
} }
let mut areas: Vec<DrawArea> = Vec::new(); let mut areas: Vec<DrawArea> = Vec::new();
let mut all_areas: Vec<(Color, Polygon)> = Vec::new(); let mut all_areas = GeomBatch::new();
timer.start_iter("make DrawAreas", map.all_areas().len()); timer.start_iter("make DrawAreas", map.all_areas().len());
for a in map.all_areas() { for a in map.all_areas() {
timer.next(); timer.next();
let (draw, color, poly) = DrawArea::new(a, cs); areas.push(DrawArea::new(a, cs, &mut all_areas));
areas.push(draw);
all_areas.push((color, poly));
} }
let draw_all_areas = prerender.upload(all_areas); let draw_all_areas = prerender.upload(all_areas);

View File

@ -1,6 +1,6 @@
use crate::helpers::{ColorScheme, ID}; use crate::helpers::{ColorScheme, ID};
use crate::render::{DrawCtx, DrawOptions, Renderable}; use crate::render::{DrawCtx, DrawOptions, Renderable};
use ezgui::{Color, Drawable, GfxCtx, Prerender}; use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
use geom::{Circle, Distance, PolyLine, Polygon}; use geom::{Circle, Distance, PolyLine, Polygon};
use map_model::{Map, LANE_THICKNESS}; use map_model::{Map, LANE_THICKNESS};
use sim::{DrawPedestrianInput, PedestrianID}; use sim::{DrawPedestrianInput, PedestrianID};
@ -27,7 +27,7 @@ impl DrawPedestrian {
// - front paths are too skinny // - front paths are too skinny
let radius = LANE_THICKNESS / 4.0; let radius = LANE_THICKNESS / 4.0;
let mut draw_default = Vec::new(); let mut draw_default = GeomBatch::new();
let foot_radius = 0.2 * radius; let foot_radius = 0.2 * radius;
let left_foot = Circle::new( let left_foot = Circle::new(
@ -47,11 +47,11 @@ impl DrawPedestrian {
let jitter = input.id.0 % 2 == 0; let jitter = input.id.0 % 2 == 0;
let remainder = step_count % 6; let remainder = step_count % 6;
if input.waiting_for_turn.is_some() { if input.waiting_for_turn.is_some() {
draw_default.push((foot_color, left_foot.to_polygon())); draw_default.push(foot_color, left_foot.to_polygon());
draw_default.push((foot_color, right_foot.to_polygon())); draw_default.push(foot_color, right_foot.to_polygon());
} else if jitter == (remainder < 3) { } else if jitter == (remainder < 3) {
draw_default.push((foot_color, left_foot.to_polygon())); draw_default.push(foot_color, left_foot.to_polygon());
draw_default.push(( draw_default.push(
foot_color, foot_color,
Circle::new( Circle::new(
input input
@ -60,10 +60,10 @@ impl DrawPedestrian {
foot_radius, foot_radius,
) )
.to_polygon(), .to_polygon(),
)); );
} else { } else {
draw_default.push((foot_color, right_foot.to_polygon())); draw_default.push(foot_color, right_foot.to_polygon());
draw_default.push(( draw_default.push(
foot_color, foot_color,
Circle::new( Circle::new(
input input
@ -72,7 +72,7 @@ impl DrawPedestrian {
foot_radius, foot_radius,
) )
.to_polygon(), .to_polygon(),
)); );
}; };
let body_circle = Circle::new(input.pos, radius); let body_circle = Circle::new(input.pos, radius);
@ -85,11 +85,11 @@ impl DrawPedestrian {
.shift(input.id.0) .shift(input.id.0)
}; };
// TODO Arms would look fabulous. // TODO Arms would look fabulous.
draw_default.push((body_color, body_circle.to_polygon())); draw_default.push(body_color, body_circle.to_polygon());
draw_default.push(( draw_default.push(
cs.get_def("pedestrian head", Color::rgb(139, 69, 19)), cs.get_def("pedestrian head", Color::rgb(139, 69, 19)),
head_circle.to_polygon(), head_circle.to_polygon(),
)); );
if let Some(t) = input.waiting_for_turn { if let Some(t) = input.waiting_for_turn {
// A silly idea for peds... use hands to point at their turn? // A silly idea for peds... use hands to point at their turn?
@ -101,7 +101,7 @@ impl DrawPedestrian {
.make_arrow(Distance::meters(0.25)) .make_arrow(Distance::meters(0.25))
.unwrap() .unwrap()
{ {
draw_default.push((cs.get("blinker on"), poly)); draw_default.push(cs.get("blinker on"), poly);
} }
} }

View File

@ -1,6 +1,6 @@
use crate::helpers::{ColorScheme, ID}; use crate::helpers::{ColorScheme, ID};
use crate::render::{DrawCtx, DrawOptions, Renderable, BIG_ARROW_THICKNESS, OUTLINE_THICKNESS}; use crate::render::{DrawCtx, DrawOptions, Renderable, BIG_ARROW_THICKNESS, OUTLINE_THICKNESS};
use ezgui::{Color, Drawable, GfxCtx, Prerender}; use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
use geom::{Polygon, Pt2D}; use geom::{Polygon, Pt2D};
use map_model::{Map, Road, RoadID}; use map_model::{Map, Road, RoadID};
@ -13,13 +13,15 @@ pub struct DrawRoad {
impl DrawRoad { impl DrawRoad {
pub fn new(r: &Road, cs: &ColorScheme, prerender: &Prerender) -> DrawRoad { pub fn new(r: &Road, cs: &ColorScheme, prerender: &Prerender) -> DrawRoad {
let mut draw = GeomBatch::new();
draw.push(
cs.get_def("road center line", Color::YELLOW),
r.center_pts.make_polygons(BIG_ARROW_THICKNESS),
);
DrawRoad { DrawRoad {
id: r.id, id: r.id,
zorder: r.get_zorder(), zorder: r.get_zorder(),
draw_center_line: prerender.upload(vec![( draw_center_line: prerender.upload(draw),
cs.get_def("road center line", Color::YELLOW),
r.center_pts.make_polygons(BIG_ARROW_THICKNESS),
)]),
} }
} }
} }

View File

@ -120,7 +120,7 @@ impl DrawCrosswalk {
Line::new(pts[1], pts[2]) Line::new(pts[1], pts[2])
}; };
let mut draw = Vec::new(); let mut draw = GeomBatch::new();
let available_length = line.length() - (boundary * 2.0); let available_length = line.length() - (boundary * 2.0);
if available_length > Distance::ZERO { if available_length > Distance::ZERO {
let num_markings = (available_length / tile_every).floor() as usize; let num_markings = (available_length / tile_every).floor() as usize;
@ -131,11 +131,11 @@ impl DrawCrosswalk {
let pt1 = line.dist_along(dist_along); let pt1 = line.dist_along(dist_along);
// Reuse perp_line. Project away an arbitrary amount // Reuse perp_line. Project away an arbitrary amount
let pt2 = pt1.project_away(Distance::meters(1.0), turn.angle()); let pt2 = pt1.project_away(Distance::meters(1.0), turn.angle());
draw.push(( draw.push(
cs.get_def("crosswalk", Color::WHITE), cs.get_def("crosswalk", Color::WHITE),
perp_line(Line::new(pt1, pt2), LANE_THICKNESS) perp_line(Line::new(pt1, pt2), LANE_THICKNESS)
.make_polygons(CROSSWALK_LINE_THICKNESS), .make_polygons(CROSSWALK_LINE_THICKNESS),
)); );
dist_along += tile_every; dist_along += tile_every;
} }
} }

View File

@ -135,11 +135,9 @@ impl<'a> GfxCtx<'a> {
} }
pub fn draw_polygons(&mut self, color: Color, polygons: &Vec<Polygon>) { pub fn draw_polygons(&mut self, color: Color, polygons: &Vec<Polygon>) {
self.draw_polygon_batch(polygons.iter().map(|p| (color, p)).collect()) let obj = self
} .prerender
.upload_temporary(polygons.iter().map(|p| (color, p)).collect());
pub fn draw_polygon_batch(&mut self, list: Vec<(Color, &Polygon)>) {
let obj = self.prerender.upload_temporary(list);
self.redraw(&obj); self.redraw(&obj);
} }
@ -284,7 +282,7 @@ impl<'a> GfxCtx<'a> {
} }
pub struct GeomBatch { pub struct GeomBatch {
list: Vec<(Color, Polygon)>, pub(crate) list: Vec<(Color, Polygon)>,
} }
impl GeomBatch { impl GeomBatch {
@ -304,6 +302,7 @@ impl GeomBatch {
pub fn draw(self, g: &mut GfxCtx) { pub fn draw(self, g: &mut GfxCtx) {
let refs = self.list.iter().map(|(color, p)| (*color, p)).collect(); let refs = self.list.iter().map(|(color, p)| (*color, p)).collect();
g.draw_polygon_batch(refs); let obj = g.prerender.upload_temporary(refs);
g.redraw(&obj);
} }
} }

View File

@ -1,6 +1,8 @@
use crate::input::ContextMenu; use crate::input::ContextMenu;
use crate::text::FONT_SIZE; use crate::text::FONT_SIZE;
use crate::{Canvas, Color, GfxCtx, HorizontalAlignment, Text, UserInput, VerticalAlignment}; use crate::{
Canvas, Color, GeomBatch, GfxCtx, HorizontalAlignment, Text, UserInput, VerticalAlignment,
};
use abstutil::{elapsed_seconds, Timer, TimerSink}; use abstutil::{elapsed_seconds, Timer, TimerSink};
use geom::Polygon; use geom::Polygon;
use glium::implement_vertex; use glium::implement_vertex;
@ -41,8 +43,8 @@ impl<'a> Prerender<'a> {
self.actually_upload(true, list) self.actually_upload(true, list)
} }
pub fn upload(&self, list: Vec<(Color, Polygon)>) -> Drawable { pub fn upload(&self, batch: GeomBatch) -> Drawable {
let borrows = list.iter().map(|(c, p)| (*c, p)).collect(); let borrows = batch.list.iter().map(|(c, p)| (*c, p)).collect();
self.actually_upload(true, borrows) self.actually_upload(true, borrows)
} }