refactoring Color / FancyColor. remove hatching style 1

This commit is contained in:
Dustin Carlino 2020-03-30 16:15:32 -07:00
parent 0fb22b5f50
commit 06bb5e08e6
14 changed files with 115 additions and 176 deletions

View File

@ -98,15 +98,11 @@ pub struct GfxCtxInnards<'a> {
}
impl<'a> GfxCtxInnards<'a> {
pub fn clear(&mut self, color: Color) {
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 clear(&mut self, c: Color) {
// Without this, SRGB gets enabled and post-processes the color from the fragment
// shader.
self.target
.clear_color_srgb_and_depth((c.r, c.g, c.b, c.a), 1.0);
}
pub fn redraw(&mut self, obj: &Drawable, uniforms: &Uniforms, prerender: &PrerenderInnards) {
@ -188,21 +184,9 @@ impl PrerenderInnards {
let idx_offset = vertices.len();
let (pts, raw_indices) = poly.raw_for_rendering();
for pt in pts {
let style = match color {
FancyColor::Plain(Color::RGBA(r, g, b, a)) => [r, g, b, a],
// Two special cases
FancyColor::Plain(Color::HatchingStyle1) => [100.0, 0.0, 0.0, 0.0],
FancyColor::Plain(Color::HatchingStyle2) => [101.0, 0.0, 0.0, 0.0],
FancyColor::LinearGradient(ref line, ref lg) => {
match FancyColor::interp_lg(line, lg, *pt) {
Color::RGBA(r, g, b, a) => [r, g, b, a],
_ => unreachable!(),
}
}
};
vertices.push(Vertex {
position: [pt.x() as f32, pt.y() as f32],
style,
style: color.style(*pt),
});
}
for idx in raw_indices {

View File

@ -1,5 +1,5 @@
use crate::drawing::Uniforms;
use crate::{Canvas, Color, ScreenDims, ScreenRectangle};
use crate::{Canvas, Color, FancyColor, ScreenDims, ScreenRectangle};
use geom::Polygon;
use glow::HasContext;
use std::cell::Cell;
@ -96,15 +96,12 @@ pub struct GfxCtxInnards<'a> {
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);
unsafe {
self.gl.clear_color(color.r, color.g, color.b, color.a);
self.gl.clear(glow::COLOR_BUFFER_BIT);
self.gl.clear_depth_f32(1.0);
self.gl.clear(glow::DEPTH_BUFFER_BIT);
},
_ => unreachable!(),
self.gl.clear_depth_f32(1.0);
self.gl.clear(glow::DEPTH_BUFFER_BIT);
}
}
@ -197,7 +194,7 @@ pub struct PrerenderInnards {
}
impl PrerenderInnards {
pub fn actually_upload(&self, permanent: bool, list: Vec<(Color, &Polygon)>) -> Drawable {
pub fn actually_upload(&self, permanent: bool, list: Vec<(FancyColor, &Polygon)>) -> Drawable {
let mut vertices: Vec<[f32; 6]> = Vec::new();
let mut indices: Vec<u32> = Vec::new();
@ -205,12 +202,7 @@ impl PrerenderInnards {
let idx_offset = vertices.len();
let (pts, raw_indices) = poly.raw_for_rendering();
for pt in pts {
let style = match color {
Color::RGBA(r, g, b, a) => [r, g, b, a],
// Two special cases
Color::HatchingStyle1 => [100.0, 0.0, 0.0, 0.0],
Color::HatchingStyle2 => [101.0, 0.0, 0.0, 0.0],
};
let style = color.style(*pt);
vertices.push([
pt.x() as f32,
pt.y() as f32,

View File

@ -1,5 +1,5 @@
use crate::drawing::Uniforms;
use crate::{Canvas, Color, ScreenDims, ScreenRectangle};
use crate::{Canvas, Color, FancyColor, ScreenDims, ScreenRectangle};
use geom::Polygon;
use glow::HasContext;
use std::cell::Cell;
@ -116,15 +116,12 @@ pub struct GfxCtxInnards<'a> {
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);
unsafe {
self.gl.clear_color(color.r, color.g, color.b, color.a);
self.gl.clear(glow::COLOR_BUFFER_BIT);
self.gl.clear_depth_f32(1.0);
self.gl.clear(glow::DEPTH_BUFFER_BIT);
},
_ => unreachable!(),
self.gl.clear_depth_f32(1.0);
self.gl.clear(glow::DEPTH_BUFFER_BIT);
}
}
@ -215,7 +212,7 @@ pub struct PrerenderInnards {
}
impl PrerenderInnards {
pub fn actually_upload(&self, permanent: bool, list: Vec<(Color, &Polygon)>) -> Drawable {
pub fn actually_upload(&self, permanent: bool, list: Vec<(FancyColor, &Polygon)>) -> Drawable {
let mut vertices: Vec<[f32; 6]> = Vec::new();
let mut indices: Vec<u32> = Vec::new();
@ -223,12 +220,7 @@ impl PrerenderInnards {
let idx_offset = vertices.len();
let (pts, raw_indices) = poly.raw_for_rendering();
for pt in pts {
let style = match color {
Color::RGBA(r, g, b, a) => [r, g, b, a],
// Two special cases
Color::HatchingStyle1 => [100.0, 0.0, 0.0, 0.0],
Color::HatchingStyle2 => [101.0, 0.0, 0.0, 0.0],
};
let style = color.style(*pt);
vertices.push([
pt.x() as f32,
pt.y() as f32,

View File

@ -3,30 +3,29 @@ use serde_derive::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum Color {
RGBA(f32, f32, f32, f32),
// TODO Figure out how to pack more data into this.
HatchingStyle1,
HatchingStyle2,
pub struct Color {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
impl fmt::Display for Color {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Color::RGBA(r, g, b, a) => write!(f, "Color(r={}, g={}, b={}, a={})", r, g, b, a),
Color::HatchingStyle1 => write!(f, "Color::HatchingStyle1"),
Color::HatchingStyle2 => write!(f, "Color::HatchingStyle2"),
}
write!(
f,
"Color(r={}, g={}, b={}, a={})",
self.r, self.g, self.b, self.a
)
}
}
// TODO Not sure if this is hacky or not. Maybe Color should be specialized to RGBA, and these are
// other cases...
// TODO Maybe needs a better name
#[derive(Clone, PartialEq)]
pub enum FancyColor {
Plain(Color),
// The line, then stops (percent along, color)
LinearGradient(Line, Vec<(f64, Color)>),
RGBA(Color),
Hatching,
LinearGradient(LinearGradient),
}
impl Color {
@ -52,38 +51,38 @@ impl Color {
}
pub const fn rgb_f(r: f32, g: f32, b: f32) -> Color {
Color::RGBA(r, g, b, 1.0)
Color { r, g, b, a: 1.0 }
}
pub fn rgba(r: usize, g: usize, b: usize, a: f32) -> Color {
Color::RGBA(
(r as f32) / 255.0,
(g as f32) / 255.0,
(b as f32) / 255.0,
Color {
r: (r as f32) / 255.0,
g: (g as f32) / 255.0,
b: (b as f32) / 255.0,
a,
)
}
}
pub const fn rgba_f(r: f32, g: f32, b: f32, a: f32) -> Color {
Color::RGBA(r, g, b, a)
Color { r, g, b, a }
}
pub const fn grey(f: f32) -> Color {
Color::RGBA(f, f, f, 1.0)
Color::rgb_f(f, f, f)
}
pub fn alpha(&self, a: f32) -> Color {
match self {
Color::RGBA(r, g, b, _) => Color::RGBA(*r, *g, *b, a),
_ => unreachable!(),
}
let mut c = self.clone();
c.a = a;
c
}
pub fn fade(&self, factor: f32) -> Color {
match self {
Color::RGBA(r, g, b, a) => Color::RGBA(*r / factor, *g / factor, *b / factor, *a),
_ => unreachable!(),
}
let mut c = self.clone();
c.r /= factor;
c.g /= factor;
c.b /= factor;
c
}
pub fn hex(raw: &str) -> Color {
@ -95,32 +94,34 @@ impl Color {
}
pub fn to_hex(&self) -> String {
match self {
Color::RGBA(r, g, b, _) => format!(
"#{:02X}{:02X}{:02X}",
(r * 255.0) as usize,
(g * 255.0) as usize,
(b * 255.0) as usize
),
_ => unreachable!(),
}
format!(
"#{:02X}{:02X}{:02X}",
(self.r * 255.0) as usize,
(self.g * 255.0) as usize,
(self.b * 255.0) as usize
)
}
fn lerp(self, other: Color, pct: f32) -> Color {
match (self, other) {
(Color::RGBA(r1, g1, b1, a1), Color::RGBA(r2, g2, b2, a2)) => Color::RGBA(
lerp(pct, (r1, r2)),
lerp(pct, (g1, g2)),
lerp(pct, (b1, b2)),
lerp(pct, (a1, a2)),
),
_ => unreachable!(),
}
Color::rgba_f(
lerp(pct, (self.r, other.r)),
lerp(pct, (self.g, other.g)),
lerp(pct, (self.b, other.b)),
lerp(pct, (self.a, other.a)),
)
}
}
impl FancyColor {
pub(crate) fn linear_gradient(lg: &usvg::LinearGradient) -> FancyColor {
// https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient is the best reference I've
// found, even though it's technically for CSS, not SVG
#[derive(Clone, PartialEq)]
pub struct LinearGradient {
line: Line,
stops: Vec<(f64, Color)>,
}
impl LinearGradient {
pub(crate) fn new(lg: &usvg::LinearGradient) -> FancyColor {
let line = Line::new(Pt2D::new(lg.x1, lg.y1), Pt2D::new(lg.x2, lg.y2));
let mut stops = Vec::new();
for stop in &lg.stops {
@ -132,23 +133,22 @@ impl FancyColor {
);
stops.push((stop.offset.value(), color));
}
FancyColor::LinearGradient(line, stops)
FancyColor::LinearGradient(LinearGradient { line, stops })
}
pub(crate) fn interp_lg(line: &Line, stops: &Vec<(f64, Color)>, corner: Pt2D) -> Color {
// https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient is the best reference
// I've found, even though it's technically for CSS, not SVG
let pct = line
.percent_along_of_point(line.project_pt(corner))
fn interp(&self, pt: Pt2D) -> Color {
let pct = self
.line
.percent_along_of_point(self.line.project_pt(pt))
.unwrap();
if pct < stops[0].0 {
return stops[0].1;
if pct < self.stops[0].0 {
return self.stops[0].1;
}
if pct > stops.last().unwrap().0 {
return stops.last().unwrap().1;
if pct > self.stops.last().unwrap().0 {
return self.stops.last().unwrap().1;
}
// In between two
for ((pct1, c1), (pct2, c2)) in stops.iter().zip(stops.iter().skip(1)) {
for ((pct1, c1), (pct2, c2)) in self.stops.iter().zip(self.stops.iter().skip(1)) {
if pct >= *pct1 && pct <= *pct2 {
return c1.lerp(*c2, to_pct(pct, (*pct1, *pct2)) as f32);
}
@ -167,3 +167,16 @@ fn to_pct(value: f64, (low, high): (f64, f64)) -> f64 {
fn lerp(pct: f32, (x1, x2): (f32, f32)) -> f32 {
x1 + pct * (x2 - x1)
}
impl FancyColor {
pub(crate) fn style(&self, pt: Pt2D) -> [f32; 4] {
match self {
FancyColor::RGBA(c) => [c.r, c.g, c.b, c.a],
FancyColor::Hatching => [100.0, 0.0, 0.0, 0.0],
FancyColor::LinearGradient(ref lg) => {
let c = lg.interp(pt);
[c.r, c.g, c.b, c.a]
}
}
}
}

View File

@ -138,7 +138,7 @@ impl<'a> GfxCtx<'a> {
pub fn draw_polygon(&mut self, color: Color, poly: &Polygon) {
let obj = self
.prerender
.upload_temporary(vec![(FancyColor::Plain(color), poly)]);
.upload_temporary(vec![(FancyColor::RGBA(color), poly)]);
self.redraw(&obj);
}
@ -146,7 +146,7 @@ impl<'a> GfxCtx<'a> {
let obj = self.prerender.upload_temporary(
polygons
.iter()
.map(|p| (FancyColor::Plain(color), p))
.map(|p| (FancyColor::RGBA(color), p))
.collect(),
);
self.redraw(&obj);

View File

@ -23,7 +23,7 @@ impl GeomBatch {
GeomBatch {
list: list
.into_iter()
.map(|(c, p)| (FancyColor::Plain(c), p))
.map(|(c, p)| (FancyColor::RGBA(c), p))
.collect(),
dims_text: false,
}
@ -31,7 +31,7 @@ impl GeomBatch {
/// Adds a single colored polygon.
pub fn push(&mut self, color: Color, p: Polygon) {
self.list.push((FancyColor::Plain(color), p));
self.list.push((FancyColor::RGBA(color), p));
}
pub fn fancy_push(&mut self, color: FancyColor, p: Polygon) {
self.list.push((color, p));
@ -40,7 +40,7 @@ impl GeomBatch {
/// Applies one color to many polygons.
pub fn extend(&mut self, color: Color, polys: Vec<Polygon>) {
for p in polys {
self.list.push((FancyColor::Plain(color), p));
self.list.push((FancyColor::RGBA(color), p));
}
}
@ -112,7 +112,7 @@ impl GeomBatch {
/// Transforms all colors in a batch.
pub fn rewrite_color(&mut self, transformation: RewriteColor) {
for (fancy, _) in self.list.iter_mut() {
if let FancyColor::Plain(ref mut c) = fancy {
if let FancyColor::RGBA(ref mut c) = fancy {
match transformation {
RewriteColor::NoOp => {}
RewriteColor::Change(from, to) => {

View File

@ -40,7 +40,7 @@ mod widgets;
pub use crate::backend::Drawable;
pub use crate::canvas::{Canvas, HorizontalAlignment, VerticalAlignment};
pub use crate::color::{Color, FancyColor};
pub use crate::color::{Color, FancyColor, LinearGradient};
pub use crate::drawing::{GfxCtx, Prerender};
pub use crate::event::{hotkey, hotkeys, lctrl, Event, Key, MultiKey};
pub use crate::event_ctx::EventCtx;

View File

@ -11,19 +11,6 @@ out vec4 f_color;
void main() {
// See actually_upload in drawing.rs to understand the different things encoded.
if (pass_style[0] == 100.0) {
// The hatching should be done in map-space, so panning/zooming doesn't move the stripes.
// This is screen_to_map, also accounting for the y-inversion done by the vertex shader.
float map_x = (gl_FragCoord.x + transform[0]) / transform[2];
float map_y = (window[1] - gl_FragCoord.y + transform[1]) / transform[2];
if (mod(map_x + map_y, 2.0) <= 0.1) {
f_color = vec4(0.0, 1.0, 1.0, 1.0);
} else if (mod(map_x - map_y, 2.0) <= 0.1) {
f_color = vec4(0.0, 1.0, 1.0, 1.0);
} else {
// Let the polygon with its original colors show instead.
discard;
}
} else if (pass_style[0] == 101.0) {
float map_x = (gl_FragCoord.x + transform[0]) / transform[2];
float map_y = (window[1] - gl_FragCoord.y + transform[1]) / transform[2];
if (mod(map_x + map_y, 2.0) <= 0.5) {

View File

@ -14,19 +14,6 @@ out vec4 f_color;
void main() {
// See actually_upload in drawing.rs to understand the different things encoded.
if (pass_style[0] == 100.0) {
// The hatching should be done in map-space, so panning/zooming doesn't move the stripes.
// This is screen_to_map, also accounting for the y-inversion done by the vertex shader.
float map_x = (gl_FragCoord.x + transform[0]) / transform[2];
float map_y = (window[1] - gl_FragCoord.y + transform[1]) / transform[2];
if (mod(map_x + map_y, 2.0) <= 0.1) {
f_color = vec4(0.0, 1.0, 1.0, 1.0);
} else if (mod(map_x - map_y, 2.0) <= 0.1) {
f_color = vec4(0.0, 1.0, 1.0, 1.0);
} else {
// Let the polygon with its original colors show instead.
discard;
}
} else if (pass_style[0] == 101.0) {
float map_x = (gl_FragCoord.x + transform[0]) / transform[2];
float map_y = (window[1] - gl_FragCoord.y + transform[1]) / transform[2];
if (mod(map_x + map_y, 2.0) <= 0.5) {

View File

@ -1,4 +1,4 @@
use crate::{Color, FancyColor, GeomBatch, Prerender};
use crate::{Color, FancyColor, GeomBatch, LinearGradient, Prerender};
use abstutil::VecMap;
use geom::{Bounds, Polygon, Pt2D};
use lyon::math::Point;
@ -232,14 +232,14 @@ fn convert_stroke(
fn convert_color(paint: &usvg::Paint, opacity: f64, tree: &usvg::Tree) -> FancyColor {
match paint {
usvg::Paint::Color(c) => FancyColor::Plain(Color::rgba(
usvg::Paint::Color(c) => FancyColor::RGBA(Color::rgba(
c.red as usize,
c.green as usize,
c.blue as usize,
opacity as f32,
)),
usvg::Paint::Link(name) => match *tree.defs_by_id(name).unwrap().borrow() {
usvg::NodeKind::LinearGradient(ref lg) => FancyColor::linear_gradient(lg),
usvg::NodeKind::LinearGradient(ref lg) => LinearGradient::new(lg),
_ => panic!("Unsupported color style {}", name),
},
}

View File

@ -88,15 +88,7 @@ impl ColorScheme {
if false {
let mut copy = OverrideColorScheme(BTreeMap::new());
for (name, c) in &map {
if let Color::RGBA(r, g, b, a) = *c {
let hex = format!(
"#{:02X}{:02X}{:02X}",
(r * 255.0) as usize,
(g * 255.0) as usize,
(b * 255.0) as usize
);
copy.0.insert(name.clone(), (hex, a));
}
copy.0.insert(name.clone(), (c.to_hex(), c.a));
}
abstutil::write_json("../data/system/override_colors.json".to_string(), &copy);
}

View File

@ -4,7 +4,7 @@ use crate::render::{
draw_signal_phase, DrawOptions, Renderable, CROSSWALK_LINE_THICKNESS, OUTLINE_THICKNESS,
};
use abstutil::Timer;
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text};
use ezgui::{Color, Drawable, FancyColor, GeomBatch, GfxCtx, Line, Prerender, Text};
use geom::{Angle, Distance, Line, PolyLine, Polygon, Pt2D, Time, EPSILON_DIST};
use map_model::raw::DrivingSide;
use map_model::{
@ -72,7 +72,7 @@ impl DrawIntersection {
}
}
IntersectionType::Construction => {
default_geom.push(cs.get("construction hatching"), i.polygon.clone());
default_geom.fancy_push(FancyColor::Hatching, i.polygon.clone());
}
IntersectionType::TrafficSignal => {}
}

View File

@ -2,7 +2,7 @@ use crate::app::App;
use crate::helpers::{ColorScheme, ID};
use crate::render::{dashed_lines, DrawOptions, Renderable, OUTLINE_THICKNESS};
use abstutil::Timer;
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
use ezgui::{Color, Drawable, FancyColor, GeomBatch, GfxCtx, Prerender};
use geom::{Angle, Distance, Line, PolyLine, Polygon, Pt2D};
use map_model::{Lane, LaneID, LaneType, Map, Road, TurnType, PARKING_SPOT_LENGTH};
@ -147,10 +147,8 @@ impl DrawLane {
);
}
LaneType::Construction => {
draw.push(
cs.get_def("construction hatching", Color::HatchingStyle2),
polygon.clone(),
);
// TODO Can't put this in ColorScheme without switching to FancyColor
draw.fancy_push(FancyColor::Hatching, polygon.clone());
}
};
}

View File

@ -671,15 +671,9 @@ impl Model {
LaneType::Construction => Color::rgb(255, 109, 0),
};
if unset {
match color {
Color::RGBA(_, g, b, _) => Color::rgba_f(0.9, g, b, 0.5),
_ => unreachable!(),
}
Color::rgba_f(0.9, color.g, color.b, 0.5)
} else if lanes_unknown {
match color {
Color::RGBA(r, g, _, _) => Color::rgba_f(r, g, 0.9, 0.5),
_ => unreachable!(),
}
Color::rgba_f(color.r, color.g, 0.9, 0.5)
} else {
color
}