mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 17:34:58 +03:00
generalize ezgui Color to also cleanly represent textured things
This commit is contained in:
parent
5ef4ed16b8
commit
9867619c9c
@ -3,15 +3,18 @@ use std::fmt;
|
||||
|
||||
// Copy could be reconsidered, but eh
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Color(pub(crate) [f32; 4]);
|
||||
pub enum Color {
|
||||
RGBA(f32, f32, f32, f32),
|
||||
// The texture ID to pass to the shader
|
||||
Texture(f32),
|
||||
}
|
||||
|
||||
impl fmt::Display for Color {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Color(r={}, g={}, b={}, a={})",
|
||||
self.0[0], self.0[1], self.0[2], self.0[3]
|
||||
)
|
||||
match self {
|
||||
Color::RGBA(r, g, b, a) => write!(f, "Color(r={}, g={}, b={}, a={})", r, g, b, a),
|
||||
Color::Texture(id) => write!(f, "Color::Texture({})", id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,28 +39,31 @@ impl Color {
|
||||
}
|
||||
|
||||
pub const fn rgb_f(r: f32, g: f32, b: f32) -> Color {
|
||||
Color([r, g, b, 1.0])
|
||||
Color::RGBA(r, g, b, 1.0)
|
||||
}
|
||||
|
||||
pub fn rgba(r: usize, g: usize, b: usize, a: f32) -> Color {
|
||||
Color([
|
||||
Color::RGBA(
|
||||
(r as f32) / 255.0,
|
||||
(g as f32) / 255.0,
|
||||
(b as f32) / 255.0,
|
||||
a,
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
pub const fn rgba_f(r: f32, g: f32, b: f32, a: f32) -> Color {
|
||||
Color([r, g, b, a])
|
||||
Color::RGBA(r, g, b, a)
|
||||
}
|
||||
|
||||
pub const fn grey(f: f32) -> Color {
|
||||
Color([f, f, f, 1.0])
|
||||
Color::RGBA(f, f, f, 1.0)
|
||||
}
|
||||
|
||||
pub const fn alpha(&self, a: f32) -> Color {
|
||||
Color([self.0[0], self.0[1], self.0[2], a])
|
||||
pub fn alpha(&self, a: f32) -> Color {
|
||||
match self {
|
||||
Color::RGBA(r, g, b, _) => Color::RGBA(*r, *g, *b, a),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_hex(raw: &str) -> Color {
|
||||
|
@ -136,9 +136,14 @@ impl<'a> GfxCtx<'a> {
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, color: Color) {
|
||||
// Without this, SRGB gets enabled and post-processes the color from the fragment shader.
|
||||
self.target
|
||||
.clear_color_srgb_and_depth((color.0[0], color.0[1], color.0[2], color.0[3]), 1.0);
|
||||
match color {
|
||||
Color::RGBA(r, g, b, a) => {
|
||||
// Without this, SRGB gets enabled and post-processes the color from the fragment
|
||||
// shader.
|
||||
self.target.clear_color_srgb_and_depth((r, g, b, a), 1.0);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_line(&mut self, color: Color, thickness: Distance, line: &Line) {
|
||||
|
@ -67,27 +67,24 @@ impl<'a> Prerender<'a> {
|
||||
for (color, poly) in list {
|
||||
let idx_offset = vertices.len();
|
||||
let (pts, raw_indices) = poly.raw_for_rendering();
|
||||
let bounds = poly.get_bounds();
|
||||
let mut maybe_bounds = None;
|
||||
for pt in pts {
|
||||
// TODO Encode this more directly in Color!
|
||||
let style = if color == Color::rgb(170, 211, 223) {
|
||||
[
|
||||
0.0,
|
||||
((pt.x() - bounds.min_x) / (bounds.max_x - bounds.min_x)) as f32,
|
||||
// TODO Maybe need to do y inversion here
|
||||
((pt.y() - bounds.min_y) / (bounds.max_y - bounds.min_y)) as f32,
|
||||
0.0,
|
||||
]
|
||||
} else if color == Color::rgb(200, 250, 204) {
|
||||
[
|
||||
1.0,
|
||||
((pt.x() - bounds.min_x) / (bounds.max_x - bounds.min_x)) as f32,
|
||||
// TODO Maybe need to do y inversion here
|
||||
((pt.y() - bounds.min_y) / (bounds.max_y - bounds.min_y)) as f32,
|
||||
0.0,
|
||||
]
|
||||
} else {
|
||||
[color.0[0], color.0[1], color.0[2], color.0[3]]
|
||||
let style = match color {
|
||||
Color::RGBA(r, g, b, a) => [r, g, b, a],
|
||||
Color::Texture(id) => {
|
||||
if maybe_bounds.is_none() {
|
||||
maybe_bounds = Some(poly.get_bounds());
|
||||
}
|
||||
let b = maybe_bounds.as_ref().unwrap();
|
||||
|
||||
[
|
||||
id,
|
||||
((pt.x() - b.min_x) / (b.max_x - b.min_x)) as f32,
|
||||
// TODO Maybe need to do y inversion here
|
||||
((pt.y() - b.min_y) / (b.max_y - b.min_y)) as f32,
|
||||
0.0,
|
||||
]
|
||||
}
|
||||
};
|
||||
vertices.push(Vertex {
|
||||
position: [pt.x() as f32, pt.y() as f32],
|
||||
@ -167,6 +164,15 @@ impl<'a> EventCtx<'a> {
|
||||
self.input.window_lost_cursor()
|
||||
|| (!self.canvas.is_dragging() && self.input.get_moved_mouse().is_some())
|
||||
}
|
||||
|
||||
pub fn texture(&self, filename: &str) -> Color {
|
||||
for (idx, (name, _)) in self.canvas.textures.iter().enumerate() {
|
||||
if filename == name {
|
||||
return Color::Texture(idx as f32);
|
||||
}
|
||||
}
|
||||
panic!("Don't know texture {}", filename);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoadingScreen<'a> {
|
||||
|
@ -205,7 +205,10 @@ pub fn draw_text_bubble(
|
||||
max_size = max_size.max(span.size);
|
||||
SectionText {
|
||||
text: &span.text,
|
||||
color: span.fg_color.0,
|
||||
color: match span.fg_color {
|
||||
Color::RGBA(r, g, b, a) => [r, g, b, a],
|
||||
_ => unreachable!(),
|
||||
},
|
||||
scale: Scale::uniform(span.size as f32),
|
||||
..SectionText::default()
|
||||
}
|
||||
@ -273,7 +276,10 @@ pub fn draw_text_bubble_mapspace(
|
||||
max_size = max_size.max(span.size);
|
||||
SectionText {
|
||||
text: &span.text,
|
||||
color: span.fg_color.0,
|
||||
color: match span.fg_color {
|
||||
Color::RGBA(r, g, b, a) => [r, g, b, a],
|
||||
_ => unreachable!(),
|
||||
},
|
||||
scale: Scale::uniform(span.size as f32),
|
||||
..SectionText::default()
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut Event
|
||||
&ui.primary.map,
|
||||
&ui.primary.current_flags,
|
||||
&ui.cs,
|
||||
ctx.prerender,
|
||||
ctx,
|
||||
&mut timer,
|
||||
);
|
||||
timer.stop("setup primary");
|
||||
@ -215,7 +215,7 @@ fn launch_savestate(test: &ABTest, ss_path: String, ui: &mut UI, ctx: &mut Event
|
||||
&ss.secondary_map,
|
||||
&ui.primary.current_flags,
|
||||
&ui.cs,
|
||||
ctx.prerender,
|
||||
ctx,
|
||||
&mut timer,
|
||||
),
|
||||
map: ss.secondary_map,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::helpers::{ColorScheme, ID};
|
||||
use crate::helpers::ID;
|
||||
use crate::render::{DrawCtx, DrawOptions, Renderable};
|
||||
use ezgui::{Color, GeomBatch, GfxCtx};
|
||||
use ezgui::{EventCtx, GeomBatch, GfxCtx};
|
||||
use geom::Polygon;
|
||||
use map_model::{Area, AreaID, AreaType, Map};
|
||||
|
||||
@ -9,11 +9,13 @@ pub struct DrawArea {
|
||||
}
|
||||
|
||||
impl DrawArea {
|
||||
pub fn new(area: &Area, cs: &ColorScheme, batch: &mut GeomBatch) -> DrawArea {
|
||||
pub fn new(area: &Area, ctx: &EventCtx, batch: &mut GeomBatch) -> DrawArea {
|
||||
batch.push(
|
||||
match area.area_type {
|
||||
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::Park => cs.get_def("park area", Color::rgb(200, 250, 204)),
|
||||
//AreaType::Water => cs.get_def("water area", Color::rgb(170, 211, 223)),
|
||||
AreaType::Park => ctx.texture("assets/grass_texture.png"),
|
||||
AreaType::Water => ctx.texture("assets/water_texture.png"),
|
||||
},
|
||||
area.polygon.clone(),
|
||||
);
|
||||
|
@ -12,7 +12,7 @@ use crate::render::Renderable;
|
||||
use crate::ui::{Flags, PerMapUI};
|
||||
use aabb_quadtree::QuadTree;
|
||||
use abstutil::{Cloneable, Timer};
|
||||
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
|
||||
use ezgui::{Color, Drawable, EventCtx, GeomBatch, GfxCtx};
|
||||
use geom::{Bounds, Circle, Distance, Duration, FindClosest};
|
||||
use map_model::{
|
||||
AreaID, BuildingID, BusStopID, DirectedRoadID, IntersectionID, Lane, LaneID, Map, RoadID,
|
||||
@ -52,7 +52,7 @@ impl DrawMap {
|
||||
map: &Map,
|
||||
flags: &Flags,
|
||||
cs: &ColorScheme,
|
||||
prerender: &Prerender,
|
||||
ctx: &EventCtx,
|
||||
timer: &mut Timer,
|
||||
) -> DrawMap {
|
||||
let mut roads: Vec<DrawRoad> = Vec::new();
|
||||
@ -60,7 +60,7 @@ impl DrawMap {
|
||||
timer.start_iter("make DrawRoads", map.all_roads().len());
|
||||
for r in map.all_roads() {
|
||||
timer.next();
|
||||
let draw_r = DrawRoad::new(r, cs, prerender);
|
||||
let draw_r = DrawRoad::new(r, cs, ctx.prerender);
|
||||
all_roads.push(
|
||||
osm_rank_to_color(cs, r.get_rank()),
|
||||
r.get_thick_polygon().get(timer),
|
||||
@ -72,7 +72,7 @@ impl DrawMap {
|
||||
roads.push(draw_r);
|
||||
}
|
||||
timer.start("upload thick roads");
|
||||
let draw_all_thick_roads = prerender.upload(all_roads);
|
||||
let draw_all_thick_roads = ctx.prerender.upload(all_roads);
|
||||
timer.stop("upload thick roads");
|
||||
|
||||
let almost_lanes =
|
||||
@ -91,7 +91,7 @@ impl DrawMap {
|
||||
let mut lanes: Vec<DrawLane> = Vec::new();
|
||||
for almost in almost_lanes {
|
||||
timer.next();
|
||||
lanes.push(almost.finish(prerender));
|
||||
lanes.push(almost.finish(ctx.prerender));
|
||||
}
|
||||
|
||||
timer.start_iter("compute_turn_to_lane_offset", map.all_lanes().len());
|
||||
@ -117,7 +117,7 @@ impl DrawMap {
|
||||
timer.start_iter("make DrawIntersections", map.all_intersections().len());
|
||||
for i in map.all_intersections() {
|
||||
timer.next();
|
||||
let draw_i = DrawIntersection::new(i, map, cs, prerender, timer);
|
||||
let draw_i = DrawIntersection::new(i, map, cs, ctx.prerender, timer);
|
||||
if i.is_stop_sign() {
|
||||
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));
|
||||
@ -130,7 +130,7 @@ impl DrawMap {
|
||||
intersections.push(draw_i);
|
||||
}
|
||||
timer.start("upload all intersections");
|
||||
let draw_all_unzoomed_intersections = prerender.upload(all_intersections);
|
||||
let draw_all_unzoomed_intersections = ctx.prerender.upload(all_intersections);
|
||||
timer.stop("upload all intersections");
|
||||
|
||||
let mut buildings: Vec<DrawBuilding> = Vec::new();
|
||||
@ -141,7 +141,7 @@ impl DrawMap {
|
||||
buildings.push(DrawBuilding::new(b, cs, &mut all_buildings));
|
||||
}
|
||||
timer.start("upload all buildings");
|
||||
let draw_all_buildings = prerender.upload(all_buildings);
|
||||
let draw_all_buildings = ctx.prerender.upload(all_buildings);
|
||||
timer.stop("upload all buildings");
|
||||
|
||||
let mut extra_shapes: Vec<DrawExtraShape> = Vec::new();
|
||||
@ -182,7 +182,7 @@ impl DrawMap {
|
||||
let mut bus_stops: HashMap<BusStopID, DrawBusStop> = HashMap::new();
|
||||
for s in map.all_bus_stops().values() {
|
||||
timer.next();
|
||||
bus_stops.insert(s.id, DrawBusStop::new(s, map, cs, prerender));
|
||||
bus_stops.insert(s.id, DrawBusStop::new(s, map, cs, ctx.prerender));
|
||||
}
|
||||
|
||||
let mut areas: Vec<DrawArea> = Vec::new();
|
||||
@ -190,13 +190,13 @@ impl DrawMap {
|
||||
timer.start_iter("make DrawAreas", map.all_areas().len());
|
||||
for a in map.all_areas() {
|
||||
timer.next();
|
||||
areas.push(DrawArea::new(a, cs, &mut all_areas));
|
||||
areas.push(DrawArea::new(a, ctx, &mut all_areas));
|
||||
}
|
||||
timer.start("upload all areas");
|
||||
let draw_all_areas = prerender.upload(all_areas);
|
||||
let draw_all_areas = ctx.prerender.upload(all_areas);
|
||||
timer.stop("upload all areas");
|
||||
|
||||
let boundary_polygon = prerender.upload_borrowed(vec![(
|
||||
let boundary_polygon = ctx.prerender.upload_borrowed(vec![(
|
||||
cs.get_def("map background", Color::rgb(242, 239, 233)),
|
||||
map.get_boundary_polygon(),
|
||||
)]);
|
||||
@ -227,7 +227,7 @@ impl DrawMap {
|
||||
|
||||
timer.note(format!(
|
||||
"static DrawMap consumes {} MB on the GPU",
|
||||
abstutil::prettyprint_usize(prerender.get_total_bytes_uploaded() / 1024 / 1024)
|
||||
abstutil::prettyprint_usize(ctx.prerender.get_total_bytes_uploaded() / 1024 / 1024)
|
||||
));
|
||||
|
||||
DrawMap {
|
||||
|
@ -469,7 +469,7 @@ impl PerMapUI {
|
||||
mem.reset("Map and Sim", timer);
|
||||
|
||||
timer.start("draw_map");
|
||||
let draw_map = DrawMap::new(&map, &flags, cs, ctx.prerender, timer);
|
||||
let draw_map = DrawMap::new(&map, &flags, cs, ctx, timer);
|
||||
timer.stop("draw_map");
|
||||
mem.reset("DrawMap", timer);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user