sloppy (and incorrect!) implementation of gradients. temporarily breaks

non-glium backends, about to cleanup.
This commit is contained in:
Dustin Carlino 2020-03-30 15:48:23 -07:00
parent 336e942464
commit 0fb22b5f50
16 changed files with 198 additions and 65 deletions

View File

@ -148,7 +148,7 @@ pub struct VecMap<K, V> {
inner: Vec<(K, V)>,
}
impl<K: Copy + PartialEq, V> VecMap<K, V> {
impl<K: Clone + PartialEq, V> VecMap<K, V> {
pub fn new() -> VecMap<K, V> {
VecMap { inner: Vec::new() }
}

View File

@ -0,0 +1,13 @@
<svg width="549" height="130" viewBox="0 0 549 130" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect y="10.8333" width="549" height="119.167" rx="10" fill="#2A2A2A"/>
<rect x="2" y="2" width="545" height="115.167" rx="8" fill="url(#paint0_linear)" stroke="#2A2A2A" stroke-width="4"/>
<path d="M232.66 77.0001H222.292C221.876 77.0001 221.57 76.9126 221.373 76.7376C221.198 76.5408 221.111 76.2345 221.111 75.8189V71.9802C221.111 71.5646 221.198 71.2693 221.373 71.0943C221.57 70.8974 221.876 70.799 222.292 70.799H231.118C231.402 70.799 231.61 70.7115 231.741 70.5365C231.894 70.3397 231.971 70.11 231.971 69.8475C231.971 69.4757 231.894 69.2022 231.741 69.0273C231.61 68.8523 231.402 68.7538 231.118 68.732L226.196 68.043C224.665 67.8242 223.429 67.3211 222.489 66.5337C221.57 65.7463 221.111 64.4339 221.111 62.5965V59.1514C221.111 57.2922 221.712 55.8705 222.915 54.8861C224.118 53.88 225.781 53.3769 227.902 53.3769H237.089C237.505 53.3769 237.8 53.4753 237.975 53.6722C238.172 53.8472 238.27 54.1425 238.27 54.5581V58.4624C238.27 58.878 238.172 59.1843 237.975 59.3811C237.8 59.5561 237.505 59.6436 237.089 59.6436H229.445C229.16 59.6436 228.941 59.742 228.788 59.9389C228.635 60.1139 228.559 60.3435 228.559 60.6279C228.559 60.9123 228.635 61.1529 228.788 61.3497C228.941 61.5466 229.16 61.6559 229.445 61.6778L234.333 62.334C235.864 62.5528 237.1 63.0558 238.041 63.8433C238.981 64.6307 239.452 65.9431 239.452 67.7805V71.2255C239.452 73.0848 238.839 74.5175 237.614 75.5236C236.411 76.5079 234.76 77.0001 232.66 77.0001ZM253.876 77.0001H248.56C248.145 77.0001 247.839 76.9126 247.642 76.7376C247.467 76.5408 247.379 76.2345 247.379 75.8189V59.7092H242.556C242.141 59.7092 241.834 59.6217 241.638 59.4467C241.463 59.2499 241.375 58.9437 241.375 58.5281V54.5581C241.375 54.1425 241.463 53.8472 241.638 53.6722C241.834 53.4753 242.141 53.3769 242.556 53.3769H259.88C260.296 53.3769 260.591 53.4753 260.766 53.6722C260.963 53.8472 261.061 54.1425 261.061 54.5581V58.5281C261.061 58.9437 260.963 59.2499 260.766 59.4467C260.591 59.6217 260.296 59.7092 259.88 59.7092H255.057V75.8189C255.057 76.2345 254.958 76.5408 254.762 76.7376C254.587 76.9126 254.291 77.0001 253.876 77.0001ZM271.502 60.267L269.96 65.2541H275.111L273.569 60.267C273.481 60.0701 273.383 59.928 273.273 59.8405C273.186 59.753 273.076 59.7092 272.945 59.7092H272.125C271.994 59.7092 271.873 59.753 271.764 59.8405C271.677 59.928 271.589 60.0701 271.502 60.267ZM269.631 75.8189C269.631 76.2345 269.533 76.5408 269.336 76.7376C269.161 76.9126 268.866 77.0001 268.45 77.0001H263.627C263.212 77.0001 262.905 76.9126 262.709 76.7376C262.534 76.5408 262.446 76.2345 262.446 75.8189V67.1571C262.446 66.5009 262.544 65.7463 262.741 64.8932C262.96 64.0401 263.288 63.0449 263.726 61.9075L266.58 54.4596C266.711 54.0878 266.908 53.8144 267.171 53.6394C267.455 53.4644 267.816 53.3769 268.253 53.3769H277.079C277.495 53.3769 277.834 53.4644 278.096 53.6394C278.381 53.8144 278.589 54.0878 278.72 54.4596L281.574 61.9075C282.012 63.0449 282.329 64.0401 282.526 64.8932C282.744 65.7463 282.854 66.5009 282.854 67.1571V75.8189C282.854 76.2345 282.755 76.5408 282.559 76.7376C282.384 76.9126 282.088 77.0001 281.673 77.0001H276.718C276.281 77.0001 275.953 76.9126 275.734 76.7376C275.537 76.5408 275.439 76.2345 275.439 75.8189V71.2255H269.631V75.8189ZM294.32 59.2827V63.4824H296.781C297.349 63.4824 297.732 63.3402 297.929 63.0558C298.126 62.7496 298.224 62.3778 298.224 61.9403V60.8248C298.224 60.3873 298.126 60.0264 297.929 59.742C297.732 59.4358 297.349 59.2827 296.781 59.2827H294.32ZM293.139 77.0001H288.086C287.67 77.0001 287.364 76.9126 287.167 76.7376C286.992 76.5408 286.905 76.2345 286.905 75.8189V54.5581C286.905 54.1425 286.992 53.8472 287.167 53.6722C287.364 53.4753 287.67 53.3769 288.086 53.3769H299.012C301.462 53.3769 303.146 53.8909 304.064 54.919C305.005 55.9251 305.475 57.2375 305.475 58.8562V60.3654C305.475 61.2841 305.333 62.0715 305.049 62.7277C304.786 63.3621 304.316 63.8214 303.638 64.1058C304.819 64.237 305.771 64.7182 306.492 65.5494C307.236 66.3806 307.608 67.4852 307.608 68.8632V75.8189C307.608 76.2345 307.51 76.5408 307.313 76.7376C307.138 76.9126 306.842 77.0001 306.427 77.0001H301.341C300.926 77.0001 300.619 76.9126 300.423 76.7376C300.248 76.5408 300.16 76.2345 300.16 75.8189V70.799C300.16 70.3178 300.062 69.9678 299.865 69.7491C299.69 69.5085 299.373 69.3882 298.913 69.3882H294.32V75.8189C294.32 76.2345 294.221 76.5408 294.025 76.7376C293.85 76.9126 293.554 77.0001 293.139 77.0001ZM321.45 77.0001H316.135C315.719 77.0001 315.413 76.9126 315.216 76.7376C315.041 76.5408 314.954 76.2345 314.954 75.8189V59.7092H310.131C309.715 59.7092 309.409 59.6217 309.212 59.4467C309.037 59.2499 308.95 58.9437 308.95 58.5281V54.5581C308.95 54.1425 309.037 53.8472 309.212 53.6722C309.409 53.4753 309.715 53.3769 310.131 53.3769H327.454C327.87 53.3769 328.165 53.4753 328.34 53.6722C328.537 53.8472 328.636 54.1425 328.636 54.5581V58.5281C328.636 58.9437 328.537 59.2499 328.34 59.4467C328.165 59.6217 327.87 59.7092 327.454 59.7092H322.631V75.8189C322.631 76.2345 322.533 76.5408 322.336 76.7376C322.161 76.9126 321.866 77.0001 321.45 77.0001Z" fill="black"/>
<defs>
<linearGradient id="paint0_linear" x1="124.515" y1="-51.1574" x2="178.507" y2="215.49" gradientUnits="userSpaceOnUse">
<stop offset="0.0621119" stop-color="#F4DF4D"/>
<stop offset="0.49324" stop-color="#F4DF4D"/>
<stop offset="0.543163" stop-color="#F4C622"/>
<stop offset="1" stop-color="#F4C622"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

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 glium::uniforms::UniformValue;
use glium::Surface;
@ -180,7 +180,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<Vertex> = Vec::new();
let mut indices: Vec<u32> = Vec::new();
@ -189,10 +189,16 @@ impl PrerenderInnards {
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],
FancyColor::Plain(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],
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],

View File

@ -1,3 +1,4 @@
use geom::{Line, Pt2D};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
@ -19,6 +20,15 @@ impl fmt::Display for Color {
}
}
// TODO Not sure if this is hacky or not. Maybe Color should be specialized to RGBA, and these are
// other cases...
#[derive(Clone, PartialEq)]
pub enum FancyColor {
Plain(Color),
// The line, then stops (percent along, color)
LinearGradient(Line, Vec<(f64, Color)>),
}
impl Color {
// TODO Won't this confuse the shader? :P
pub const INVISIBLE: Color = Color::rgba_f(1.0, 0.0, 0.0, 0.0);
@ -95,4 +105,65 @@ impl Color {
_ => unreachable!(),
}
}
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!(),
}
}
}
impl FancyColor {
pub(crate) fn linear_gradient(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 {
let color = Color::rgba(
stop.color.red as usize,
stop.color.green as usize,
stop.color.blue as usize,
stop.opacity.value() as f32,
);
stops.push((stop.offset.value(), color));
}
FancyColor::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))
.unwrap();
if pct < stops[0].0 {
return stops[0].1;
}
if pct > stops.last().unwrap().0 {
return stops.last().unwrap().1;
}
// In between two
for ((pct1, c1), (pct2, c2)) in stops.iter().zip(stops.iter().skip(1)) {
if pct >= *pct1 && pct <= *pct2 {
return c1.lerp(*c2, to_pct(pct, (*pct1, *pct2)) as f32);
}
}
unreachable!()
}
}
fn to_pct(value: f64, (low, high): (f64, f64)) -> f64 {
assert!(low <= high);
assert!(value >= low);
assert!(value <= high);
(value - low) / (high - low)
}
fn lerp(pct: f32, (x1, x2): (f32, f32)) -> f32 {
x1 + pct * (x2 - x1)
}

View File

@ -1,8 +1,8 @@
use crate::assets::Assets;
use crate::backend::{GfxCtxInnards, PrerenderInnards};
use crate::{
Canvas, Color, Drawable, GeomBatch, HorizontalAlignment, ScreenDims, ScreenPt, ScreenRectangle,
Text, VerticalAlignment,
Canvas, Color, Drawable, FancyColor, GeomBatch, HorizontalAlignment, ScreenDims, ScreenPt,
ScreenRectangle, Text, VerticalAlignment,
};
use geom::{Bounds, Circle, Distance, Line, Polygon, Pt2D};
use std::cell::Cell;
@ -136,14 +136,19 @@ impl<'a> GfxCtx<'a> {
}
pub fn draw_polygon(&mut self, color: Color, poly: &Polygon) {
let obj = self.prerender.upload_temporary(vec![(color, poly)]);
let obj = self
.prerender
.upload_temporary(vec![(FancyColor::Plain(color), poly)]);
self.redraw(&obj);
}
pub fn draw_polygons(&mut self, color: Color, polygons: &Vec<Polygon>) {
let obj = self
.prerender
.upload_temporary(polygons.iter().map(|p| (color, p)).collect());
let obj = self.prerender.upload_temporary(
polygons
.iter()
.map(|p| (FancyColor::Plain(color), p))
.collect(),
);
self.redraw(&obj);
}
@ -285,12 +290,8 @@ pub struct Prerender {
}
impl Prerender {
pub fn upload_borrowed(&self, list: Vec<(Color, &Polygon)>) -> Drawable {
self.actually_upload(true, list)
}
pub fn upload(&self, batch: GeomBatch) -> Drawable {
let borrows = batch.list.iter().map(|(c, p)| (*c, p)).collect();
let borrows = batch.list.iter().map(|(c, p)| (c.clone(), p)).collect();
self.actually_upload(true, borrows)
}
@ -298,11 +299,11 @@ impl Prerender {
self.inner.total_bytes_uploaded.get()
}
pub(crate) fn upload_temporary(&self, list: Vec<(Color, &Polygon)>) -> Drawable {
pub(crate) fn upload_temporary(&self, list: Vec<(FancyColor, &Polygon)>) -> Drawable {
self.actually_upload(false, list)
}
fn actually_upload(&self, permanent: bool, list: Vec<(Color, &Polygon)>) -> Drawable {
fn actually_upload(&self, permanent: bool, list: Vec<(FancyColor, &Polygon)>) -> Drawable {
// println!("{:?}", backtrace::Backtrace::new());
self.num_uploads.set(self.num_uploads.get() + 1);
self.inner.actually_upload(permanent, list)

View File

@ -1,10 +1,10 @@
use crate::{svg, Color, Drawable, EventCtx, GfxCtx, Prerender, ScreenDims};
use crate::{svg, Color, Drawable, EventCtx, FancyColor, GfxCtx, Prerender, ScreenDims};
use geom::{Angle, Bounds, Polygon, Pt2D};
/// A mutable builder for a group of colored polygons.
#[derive(Clone)]
pub struct GeomBatch {
pub(crate) list: Vec<(Color, Polygon)>,
pub(crate) list: Vec<(FancyColor, Polygon)>,
// TODO A weird hack for text.
pub(crate) dims_text: bool,
}
@ -21,20 +21,26 @@ impl GeomBatch {
/// Creates a batch of colored polygons.
pub fn from(list: Vec<(Color, Polygon)>) -> GeomBatch {
GeomBatch {
list,
list: list
.into_iter()
.map(|(c, p)| (FancyColor::Plain(c), p))
.collect(),
dims_text: false,
}
}
/// Adds a single colored polygon.
pub fn push(&mut self, color: Color, p: Polygon) {
self.list.push((FancyColor::Plain(color), p));
}
pub fn fancy_push(&mut self, color: FancyColor, p: Polygon) {
self.list.push((color, p));
}
/// Applies one color to many polygons.
pub fn extend(&mut self, color: Color, polys: Vec<Polygon>) {
for p in polys {
self.list.push((color, p));
self.list.push((FancyColor::Plain(color), p));
}
}
@ -44,13 +50,17 @@ impl GeomBatch {
}
/// Returns the colored polygons in this batch, destroying the batch.
pub fn consume(self) -> Vec<(Color, Polygon)> {
pub fn consume(self) -> Vec<(FancyColor, Polygon)> {
self.list
}
/// Draws the batch, consuming it. Only use this for drawing things once.
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.clone(), p))
.collect();
let obj = g.prerender.upload_temporary(refs);
g.redraw(&obj);
}
@ -101,17 +111,19 @@ impl GeomBatch {
/// Transforms all colors in a batch.
pub fn rewrite_color(&mut self, transformation: RewriteColor) {
for (c, _) in self.list.iter_mut() {
match transformation {
RewriteColor::NoOp => {}
RewriteColor::Change(from, to) => {
if *c == from {
for (fancy, _) in self.list.iter_mut() {
if let FancyColor::Plain(ref mut c) = fancy {
match transformation {
RewriteColor::NoOp => {}
RewriteColor::Change(from, to) => {
if *c == from {
*c = to;
}
}
RewriteColor::ChangeAll(to) => {
*c = to;
}
}
RewriteColor::ChangeAll(to) => {
*c = to;
}
}
}
}
@ -158,7 +170,7 @@ impl GeomBatch {
if rotate != Angle::ZERO {
poly = poly.rotate(rotate);
}
self.push(color, poly);
self.fancy_push(color, poly);
}
}
@ -166,7 +178,7 @@ impl GeomBatch {
/// Adds geometry from another batch to the current batch, first translating it.
pub fn add_translated(&mut self, other: GeomBatch, dx: f64, dy: f64) {
for (color, poly) in other.consume() {
self.push(color, poly.translate(dx, dy));
self.fancy_push(color, poly.translate(dx, dy));
}
}
}

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;
pub use crate::color::{Color, FancyColor};
pub use crate::drawing::{GfxCtx, Prerender};
pub use crate::event::{hotkey, hotkeys, lctrl, Event, Key, MultiKey};
pub use crate::event_ctx::EventCtx;

View File

@ -1,4 +1,4 @@
use crate::{Color, GeomBatch, Prerender};
use crate::{Color, FancyColor, GeomBatch, Prerender};
use abstutil::VecMap;
use geom::{Bounds, Polygon, Pt2D};
use lyon::math::Point;
@ -51,14 +51,15 @@ pub fn add_svg_inner(
) -> Result<Bounds, String> {
let mut fill_tess = tessellation::FillTessellator::new();
let mut stroke_tess = tessellation::StrokeTessellator::new();
let mut mesh_per_color: VecMap<Color, VertexBuffers<_, u16>> = VecMap::new();
// TODO This breaks on start.svg; the order there matters. color1, color2, then color1 again.
let mut mesh_per_color: VecMap<FancyColor, VertexBuffers<_, u16>> = VecMap::new();
for node in svg_tree.root().descendants() {
if let usvg::NodeKind::Path(ref p) = *node.borrow() {
// TODO Handle transforms
if let Some(ref fill) = p.fill {
let color = convert_color(&fill.paint, fill.opacity.value());
let color = convert_color(&fill.paint, fill.opacity.value(), &svg_tree);
let geom = mesh_per_color.mut_or_insert(color, VertexBuffers::new);
if fill_tess
.tessellate(
@ -73,7 +74,7 @@ pub fn add_svg_inner(
}
if let Some(ref stroke) = p.stroke {
let (color, stroke_opts) = convert_stroke(stroke, tolerance);
let (color, stroke_opts) = convert_stroke(stroke, tolerance, &svg_tree);
let geom = mesh_per_color.mut_or_insert(color, VertexBuffers::new);
stroke_tess
.tessellate(convert_path(p), &stroke_opts, &mut simple_builder(geom))
@ -83,7 +84,7 @@ pub fn add_svg_inner(
}
for (color, mesh) in mesh_per_color.consume() {
batch.push(
batch.fancy_push(
color,
Polygon::precomputed(
mesh.vertices
@ -204,8 +205,12 @@ fn convert_path<'a>(p: &'a usvg::Path) -> PathConvIter<'a> {
}
}
fn convert_stroke(s: &usvg::Stroke, tolerance: f32) -> (Color, tessellation::StrokeOptions) {
let color = convert_color(&s.paint, s.opacity.value());
fn convert_stroke(
s: &usvg::Stroke,
tolerance: f32,
tree: &usvg::Tree,
) -> (FancyColor, tessellation::StrokeOptions) {
let color = convert_color(&s.paint, s.opacity.value(), tree);
let linecap = match s.linecap {
usvg::LineCap::Butt => tessellation::LineCap::Butt,
usvg::LineCap::Square => tessellation::LineCap::Square,
@ -225,15 +230,17 @@ fn convert_stroke(s: &usvg::Stroke, tolerance: f32) -> (Color, tessellation::Str
(color, opt)
}
fn convert_color(paint: &usvg::Paint, opacity: f64) -> Color {
if let usvg::Paint::Color(c) = paint {
Color::rgba(
fn convert_color(paint: &usvg::Paint, opacity: f64, tree: &usvg::Tree) -> FancyColor {
match paint {
usvg::Paint::Color(c) => FancyColor::Plain(Color::rgba(
c.red as usize,
c.green as usize,
c.blue as usize,
opacity as f32,
)
} else {
panic!("Unsupported paint {:?}", paint);
)),
usvg::Paint::Link(name) => match *tree.defs_by_id(name).unwrap().borrow() {
usvg::NodeKind::LinearGradient(ref lg) => FancyColor::linear_gradient(lg),
_ => panic!("Unsupported color style {}", name),
},
}
}

View File

@ -272,7 +272,7 @@ impl Text {
// Add all of the padding at the bottom of the line.
let offset = line_height / SCALE_LINE_HEIGHT * 0.2;
for (color, poly) in line_batch.consume() {
master_batch.push(color, poly.translate(0.0, y - offset));
master_batch.fancy_push(color, poly.translate(0.0, y - offset));
}
max_width = max_width.max(line_dims.width);
@ -282,7 +282,7 @@ impl Text {
output_batch.push(c, Polygon::rectangle(max_width, y));
}
for (color, poly) in master_batch.consume() {
output_batch.push(color, poly);
output_batch.fancy_push(color, poly);
}
output_batch.dims_text = true;

View File

@ -182,7 +182,7 @@ impl<T: 'static + Ord + PartialEq + Copy + core::fmt::Debug + Yvalue<T>> Plot<T>
// TODO Need ticks now to actually see where this goes
let mut batch = GeomBatch::new();
for (color, poly) in Text::from(Line(t.to_string())).render_ctx(ctx).consume() {
batch.push(color, poly.rotate(Angle::new_degs(-15.0)));
batch.fancy_push(color, poly.rotate(Angle::new_degs(-15.0)));
}
row.push(Widget::draw_batch(ctx, batch.autocrop()));
}

View File

@ -194,7 +194,7 @@ pub fn details(ctx: &mut EventCtx, app: &App, trip: TripID, details: &mut Detail
let mut hovered = GeomBatch::from(vec![(color.alpha(1.0), rect.clone())]);
for (c, p) in normal.clone().consume().into_iter().skip(1) {
hovered.push(c, p);
hovered.fancy_push(c, p);
}
timeline.push(

View File

@ -30,9 +30,9 @@ impl TitleScreen {
Composite::new(
Widget::col(vec![
Widget::draw_svg(ctx, "../data/system/assets/pregame/logo.svg").margin(5),
// TODO that nicer font
// TODO Any key
Btn::text_bg2("PLAY")
// TODO The hover color is wacky
Btn::svg_def("../data/system/assets/pregame/start.svg")
.build(ctx, "start game", hotkeys(vec![Key::Space, Key::Enter]))
.margin(5),
])

View File

@ -1,7 +1,7 @@
use crate::app::App;
use crate::helpers::{ColorScheme, ID};
use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS};
use ezgui::{Color, Drawable, GfxCtx, Prerender};
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
use geom::{Distance, PolyLine, Polygon, Pt2D};
use map_model::{BusStop, BusStopID, Map};
@ -46,10 +46,10 @@ impl DrawBusStop {
]));
let polygon = polyline.make_polygons(lane.width * 0.25);
let draw_default = prerender.upload_borrowed(vec![(
let draw_default = prerender.upload(GeomBatch::from(vec![(
cs.get_def("bus stop marking", Color::CYAN),
&polygon,
)]);
polygon.clone(),
)]));
DrawBusStop {
id: stop.id,

View File

@ -208,10 +208,10 @@ impl DrawMap {
let draw_all_areas = all_areas.upload(ctx);
timer.stop("upload all areas");
let boundary_polygon = ctx.prerender.upload_borrowed(vec![(
let boundary_polygon = ctx.prerender.upload(GeomBatch::from(vec![(
cs.get_def("map background", Color::grey(0.87)),
map.get_boundary_polygon(),
)]);
map.get_boundary_polygon().clone(),
)]));
timer.start("create quadtree");
let mut quadtree = QuadTree::default(map.get_bounds().as_bbox());

View File

@ -306,7 +306,7 @@ pub fn make_signal_diagram(
normal.push(Color::BLACK, bbox.clone());
// Move to the origin and apply zoom
for (color, poly) in orig_batch.consume() {
normal.push(
normal.fancy_push(
color,
poly.translate(-bounds.min_x, -bounds.min_y).scale(zoom),
);

View File

@ -1,4 +1,5 @@
use crate::{Angle, Distance, PolyLine, Polygon, Pt2D, EPSILON_DIST};
use geo::prelude::ClosestPoint;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
@ -131,13 +132,16 @@ impl Line {
self.percent_along(dist / len)
}
pub fn percent_along(&self, percent: f64) -> Pt2D {
assert!(percent >= 0.0 && percent <= 1.0);
pub fn unbounded_percent_along(&self, percent: f64) -> Pt2D {
Pt2D::new(
self.pt1().x() + percent * (self.pt2().x() - self.pt1().x()),
self.pt1().y() + percent * (self.pt2().y() - self.pt1().y()),
)
}
pub fn percent_along(&self, percent: f64) -> Pt2D {
assert!(percent >= 0.0 && percent <= 1.0);
self.unbounded_percent_along(percent)
}
pub fn unbounded_dist_along(&self, dist: Distance) -> Pt2D {
let len = self.length();
@ -162,6 +166,25 @@ impl Line {
None
}
}
pub fn percent_along_of_point(&self, pt: Pt2D) -> Option<f64> {
let dist = self.dist_along_of_point(pt)?;
Some(dist / self.length())
}
// Returns a point on the line segment.
pub fn project_pt(&self, pt: Pt2D) -> Pt2D {
let line: geo::LineString<f64> = vec![
geo::Point::new(self.0.x(), self.0.y()),
geo::Point::new(self.1.x(), self.1.y()),
]
.into();
match line.closest_point(&geo::Point::new(pt.x(), pt.y())) {
geo::Closest::Intersection(hit) | geo::Closest::SinglePoint(hit) => {
Pt2D::new(hit.x(), hit.y())
}
geo::Closest::Indeterminate => unreachable!(),
}
}
}
impl fmt::Display for Line {