From 5aee85f19dba8e406f6e5822dfd6d629a08f9405 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Fri, 2 Oct 2020 08:06:35 -0700 Subject: [PATCH] Allow colorschemes to optionally color zoomed-in lanes based on OSM road rank. Most schemes don't do this, but one needs to, and maintaining a separate git branch has become annoying. Should have no behavioral change to existing color schemes. --- game/src/colors.rs | 75 ++++++++++++++++++++++++++++----- game/src/helpers.rs | 6 +-- game/src/render/building.rs | 10 ++++- game/src/render/intersection.rs | 10 +++-- game/src/render/lane.rs | 11 +---- game/src/render/map.rs | 16 ++----- game/src/render/parking_lot.rs | 17 ++++++-- game/src/render/road.rs | 8 ++-- map_model/src/osm.rs | 2 +- 9 files changed, 107 insertions(+), 48 deletions(-) diff --git a/game/src/colors.rs b/game/src/colors.rs index 08848f257f..ed9a531b13 100644 --- a/game/src/colors.rs +++ b/game/src/colors.rs @@ -1,5 +1,7 @@ use crate::common::ColorScale; use crate::helpers::loading_tips; +use map_model::osm::RoadRank; +use map_model::LaneType; use widgetry::{Choice, Color, Fill, Style, Texture}; // I've gone back and forth how to organize color scheme code. I was previously against having one @@ -25,6 +27,7 @@ pub enum ColorSchemeChoice { Textured, MapboxLight, MapboxDark, + FadedZoom, } impl ColorSchemeChoice { @@ -40,11 +43,14 @@ impl ColorSchemeChoice { Choice::new("textured", ColorSchemeChoice::Textured), Choice::new("mapbox light", ColorSchemeChoice::MapboxLight), Choice::new("mapbox dark", ColorSchemeChoice::MapboxDark), + Choice::new("faded zoom", ColorSchemeChoice::FadedZoom), ] } } pub struct ColorScheme { + scheme: ColorSchemeChoice, + // UI pub hovering: Color, pub panel_bg: Color, @@ -62,19 +68,19 @@ pub struct ColorScheme { pub dialog_bg: Color, // Roads - pub driving_lane: Color, - pub bus_lane: Color, - pub parking_lane: Color, - pub bike_lane: Color, - pub sidewalk: Color, + driving_lane: Color, + bus_lane: Color, + parking_lane: Color, + bike_lane: Color, + sidewalk: Color, pub sidewalk_lines: Color, pub general_road_marking: Color, pub road_center_line: Color, pub light_rail_track: Color, pub private_road: Color, - pub unzoomed_highway: Color, - pub unzoomed_arterial: Color, - pub unzoomed_residential: Color, + unzoomed_highway: Color, + unzoomed_arterial: Color, + unzoomed_residential: Color, // Intersections pub normal_intersection: Color, @@ -127,13 +133,15 @@ pub struct ColorScheme { // Misc pub parking_trip: Color, + pub bike_trip: Color, + pub bus_trip: Color, pub before_changes: Color, pub after_changes: Color, } impl ColorScheme { pub fn new(scheme: ColorSchemeChoice) -> ColorScheme { - match scheme { + let mut cs = match scheme { ColorSchemeChoice::Standard => ColorScheme::standard(), ColorSchemeChoice::NightMode => ColorScheme::night_mode(), ColorSchemeChoice::SAMGreenDay => ColorScheme::sam_green_day(), @@ -144,13 +152,18 @@ impl ColorScheme { ColorSchemeChoice::Textured => ColorScheme::textured(), ColorSchemeChoice::MapboxLight => ColorScheme::mapbox_light(), ColorSchemeChoice::MapboxDark => ColorScheme::mapbox_dark(), - } + ColorSchemeChoice::FadedZoom => ColorScheme::faded_zoom(), + }; + cs.scheme = scheme; + cs } fn standard() -> ColorScheme { let mut gui_style = Style::standard(); gui_style.loading_tips = loading_tips(); ColorScheme { + scheme: ColorSchemeChoice::Standard, + // UI hovering: gui_style.hovering_color, panel_bg: gui_style.panel_bg, @@ -239,6 +252,8 @@ impl ColorScheme { // Misc parking_trip: hex("#4E30A6"), + bike_trip: Color::rgb(15, 125, 75), + bus_trip: Color::rgb(190, 74, 76), before_changes: Color::BLUE, after_changes: Color::RED, } @@ -260,6 +275,40 @@ impl ColorScheme { pub fn rotating_color_agents(&self, idx: usize) -> Color { modulo_color(&self.agent_colors, idx) } + + pub fn unzoomed_road_surface(&self, rank: RoadRank) -> Color { + match rank { + RoadRank::Highway => self.unzoomed_highway, + RoadRank::Arterial => self.unzoomed_arterial, + RoadRank::Local => self.unzoomed_residential, + } + } + + pub fn zoomed_road_surface(&self, lane: LaneType, rank: RoadRank) -> Color { + match self.scheme { + ColorSchemeChoice::FadedZoom => match rank { + RoadRank::Highway => hex("#BEB2C0"), + RoadRank::Arterial => hex("#B6BDC5"), + RoadRank::Local => hex("#C6CDD5"), + }, + _ => match lane { + LaneType::Driving => self.driving_lane, + LaneType::Bus => self.bus_lane, + LaneType::Parking => self.parking_lane, + LaneType::Sidewalk | LaneType::Shoulder => self.sidewalk, + LaneType::Biking => self.bike_lane, + LaneType::SharedLeftTurn => self.driving_lane, + LaneType::Construction => self.parking_lane, + LaneType::LightRail => unreachable!(), + }, + } + } + pub fn zoomed_intersection_surface(&self, rank: RoadRank) -> Color { + match self.scheme { + ColorSchemeChoice::FadedZoom => self.zoomed_road_surface(LaneType::Driving, rank), + _ => self.normal_intersection, + } + } } fn modulo_color(colors: &Vec, idx: usize) -> Color { @@ -395,6 +444,7 @@ impl ColorScheme { cs.residential_building = hex("#2C2C2B").into(); cs.commerical_building = hex("#2C2C2B").into(); + // TODO Things like this could be refactored in zoomed_road_surface cs.driving_lane = road; cs.parking_lane = road; cs.bike_lane = road; @@ -408,4 +458,9 @@ impl ColorScheme { cs } + + fn faded_zoom() -> ColorScheme { + let cs = ColorScheme::standard(); + cs + } } diff --git a/game/src/helpers.rs b/game/src/helpers.rs index 89a977b287..6435fac138 100644 --- a/game/src/helpers.rs +++ b/game/src/helpers.rs @@ -135,7 +135,7 @@ pub fn color_for_agent_type(app: &App, a: AgentType) -> Color { AgentType::Pedestrian => app.cs.unzoomed_pedestrian, AgentType::Bike => app.cs.unzoomed_bike, AgentType::Bus | AgentType::Train => app.cs.unzoomed_bus, - AgentType::TransitRider => app.cs.bus_lane, + AgentType::TransitRider => app.cs.bus_trip, AgentType::Car => app.cs.unzoomed_car, } } @@ -144,10 +144,10 @@ pub fn color_for_trip_phase(app: &App, tpt: TripPhaseType) -> Color { match tpt { TripPhaseType::Driving => app.cs.unzoomed_car, TripPhaseType::Walking => app.cs.unzoomed_pedestrian, - TripPhaseType::Biking => app.cs.bike_lane, + TripPhaseType::Biking => app.cs.bike_trip, TripPhaseType::Parking => app.cs.parking_trip, TripPhaseType::WaitingForBus(_, _) => app.cs.bus_layer, - TripPhaseType::RidingBus(_, _, _) => app.cs.bus_lane, + TripPhaseType::RidingBus(_, _, _) => app.cs.bus_trip, TripPhaseType::Aborted | TripPhaseType::Finished => unreachable!(), TripPhaseType::DelayedStart => Color::YELLOW, TripPhaseType::Remote => Color::PINK, diff --git a/game/src/render/building.rs b/game/src/render/building.rs index 6b7424e58f..40fd793dcc 100644 --- a/game/src/render/building.rs +++ b/game/src/render/building.rs @@ -4,7 +4,7 @@ use crate::helpers::ID; use crate::options::{CameraAngle, Options}; use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS}; use geom::{Angle, Distance, Line, Polygon, Pt2D, Ring}; -use map_model::{Building, BuildingID, Map, OffstreetParking, NORMAL_LANE_THICKNESS}; +use map_model::{Building, BuildingID, LaneType, Map, OffstreetParking, NORMAL_LANE_THICKNESS}; use std::cell::RefCell; use widgetry::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, Text}; @@ -188,7 +188,13 @@ impl DrawBuilding { } } } - paths_batch.push(cs.sidewalk, driveway.make_polygons(NORMAL_LANE_THICKNESS)); + paths_batch.push( + cs.zoomed_road_surface( + LaneType::Sidewalk, + map.get_parent(bldg.sidewalk()).get_rank(), + ), + driveway.make_polygons(NORMAL_LANE_THICKNESS), + ); DrawBuilding { id: bldg.id, diff --git a/game/src/render/intersection.rs b/game/src/render/intersection.rs index 095d12f151..9e5da24824 100644 --- a/game/src/render/intersection.rs +++ b/game/src/render/intersection.rs @@ -6,7 +6,7 @@ use crate::render::{ }; use geom::{Angle, ArrowCap, Distance, Line, PolyLine, Polygon, Pt2D, Ring, Time, EPSILON_DIST}; use map_model::{ - Direction, DrivingSide, Intersection, IntersectionID, IntersectionType, Map, Road, + Direction, DrivingSide, Intersection, IntersectionID, IntersectionType, LaneType, Map, Road, RoadWithStopSign, Turn, TurnType, SIDEWALK_THICKNESS, }; use std::cell::RefCell; @@ -41,8 +41,12 @@ impl DrawIntersection { // Order matters... main polygon first, then sidewalk corners. let mut default_geom = GeomBatch::new(); - default_geom.push(app.cs.normal_intersection, i.polygon.clone()); - default_geom.extend(app.cs.sidewalk, calculate_corners(i, map)); + let rank = i.get_rank(map); + default_geom.push(app.cs.zoomed_intersection_surface(rank), i.polygon.clone()); + default_geom.extend( + app.cs.zoomed_road_surface(LaneType::Sidewalk, rank), + calculate_corners(i, map), + ); for turn in map.get_turns_in_intersection(i.id) { // Avoid double-rendering diff --git a/game/src/render/lane.rs b/game/src/render/lane.rs index 139a5724f7..f78064156f 100644 --- a/game/src/render/lane.rs +++ b/game/src/render/lane.rs @@ -39,16 +39,7 @@ impl DrawLane { let mut draw = GeomBatch::new(); if !lane.is_light_rail() { draw.push( - match lane.lane_type { - LaneType::Driving => app.cs.driving_lane, - LaneType::Bus => app.cs.bus_lane, - LaneType::Parking => app.cs.parking_lane, - LaneType::Sidewalk | LaneType::Shoulder => app.cs.sidewalk, - LaneType::Biking => app.cs.bike_lane, - LaneType::SharedLeftTurn => app.cs.driving_lane, - LaneType::Construction => app.cs.parking_lane, - LaneType::LightRail => unreachable!(), - }, + app.cs.zoomed_road_surface(lane.lane_type, road.get_rank()), self.polygon.clone(), ); } diff --git a/game/src/render/map.rs b/game/src/render/map.rs index ae7beb90f7..3f3aa268ba 100644 --- a/game/src/render/map.rs +++ b/game/src/render/map.rs @@ -13,8 +13,8 @@ use aabb_quadtree::QuadTree; use abstutil::Timer; use geom::{Bounds, Circle, Distance, Polygon, Pt2D, Time}; use map_model::{ - osm, AreaID, BuildingID, BusStopID, IntersectionID, LaneID, Map, ParkingLotID, RoadID, - Traversable, NORMAL_LANE_THICKNESS, SIDEWALK_THICKNESS, + AreaID, BuildingID, BusStopID, IntersectionID, LaneID, Map, ParkingLotID, RoadID, Traversable, + NORMAL_LANE_THICKNESS, SIDEWALK_THICKNESS, }; use sim::{GetDrawAgents, UnzoomedAgent, VehicleType}; use std::borrow::Borrow; @@ -210,7 +210,7 @@ impl DrawMap { } else if r.is_private() { cs.private_road } else { - rank_to_color(cs, r.get_rank()) + cs.unzoomed_road_surface(r.get_rank()) }, )); } @@ -224,7 +224,7 @@ impl DrawMap { } else if i.is_private(map) { cs.private_road } else { - rank_to_color(cs, i.get_rank(map)) + cs.unzoomed_road_surface(i.get_rank(map)) } } else { cs.unzoomed_interesting_intersection @@ -522,11 +522,3 @@ impl UnzoomedAgents { } } } - -fn rank_to_color(cs: &ColorScheme, rank: osm::RoadRank) -> Color { - match rank { - osm::RoadRank::Highway => cs.unzoomed_highway, - osm::RoadRank::Arterial => cs.unzoomed_arterial, - osm::RoadRank::Local => cs.unzoomed_residential, - } -} diff --git a/game/src/render/parking_lot.rs b/game/src/render/parking_lot.rs index 8533792f81..d74704512b 100644 --- a/game/src/render/parking_lot.rs +++ b/game/src/render/parking_lot.rs @@ -3,7 +3,9 @@ use crate::colors::ColorScheme; use crate::helpers::ID; use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS}; use geom::{Distance, PolyLine, Polygon, Pt2D}; -use map_model::{Map, ParkingLot, ParkingLotID, NORMAL_LANE_THICKNESS, PARKING_LOT_SPOT_LENGTH}; +use map_model::{ + osm, LaneType, Map, ParkingLot, ParkingLotID, NORMAL_LANE_THICKNESS, PARKING_LOT_SPOT_LENGTH, +}; use std::cell::RefCell; use widgetry::{Drawable, EventCtx, GeomBatch, GfxCtx}; @@ -23,7 +25,7 @@ impl DrawParkingLot { for aisle in &lot.aisles { let aisle_thickness = NORMAL_LANE_THICKNESS / 2.0; unzoomed_batch.push( - cs.unzoomed_residential, + cs.unzoomed_road_surface(osm::RoadRank::Local), PolyLine::unchecked_new(aisle.clone()).make_polygons(aisle_thickness), ); } @@ -64,14 +66,21 @@ impl Renderable for DrawParkingLot { // TODO This isn't getting clipped to the parking lot boundary properly, so just stick // this on the lowest order for now. batch.push( - app.cs.sidewalk, + app.cs.zoomed_road_surface( + LaneType::Sidewalk, + app.primary + .map + .get_parent(lot.sidewalk_pos.lane()) + .get_rank(), + ), front_path_line.make_polygons(NORMAL_LANE_THICKNESS), ); batch.push(app.cs.parking_lot, lot.polygon.clone()); for aisle in &lot.aisles { let aisle_thickness = NORMAL_LANE_THICKNESS / 2.0; batch.push( - app.cs.driving_lane, + app.cs + .zoomed_road_surface(LaneType::Driving, osm::RoadRank::Local), PolyLine::unchecked_new(aisle.clone()).make_polygons(aisle_thickness), ); } diff --git a/game/src/render/road.rs b/game/src/render/road.rs index d5e8bf2340..fffd223cc4 100644 --- a/game/src/render/road.rs +++ b/game/src/render/road.rs @@ -2,7 +2,7 @@ use crate::app::App; use crate::helpers::ID; use crate::render::{DrawOptions, Renderable}; use geom::{Distance, Polygon, Pt2D}; -use map_model::{Map, Road, RoadID}; +use map_model::{LaneType, Map, Road, RoadID}; use std::cell::RefCell; use widgetry::{Drawable, GeomBatch, GfxCtx, Line, Text}; @@ -86,9 +86,11 @@ impl Renderable for DrawRoad { app.cs.road_center_line }; let bg = if r.is_private() { - app.cs.driving_lane.lerp(app.cs.private_road, 0.5) + app.cs + .zoomed_road_surface(LaneType::Driving, r.get_rank()) + .lerp(app.cs.private_road, 0.5) } else { - app.cs.driving_lane + app.cs.zoomed_road_surface(LaneType::Driving, r.get_rank()) }; if false { diff --git a/map_model/src/osm.rs b/map_model/src/osm.rs index 7b10a2028b..8ae151d557 100644 --- a/map_model/src/osm.rs +++ b/map_model/src/osm.rs @@ -30,7 +30,7 @@ pub const ENDPT_BACK: &str = "abst:endpt_back"; pub const INFERRED_PARKING: &str = "abst:parking_inferred"; pub const INFERRED_SIDEWALKS: &str = "abst:sidewalks_inferred"; -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum RoadRank { Local, Arterial,