From a4a1721dc56be571fde946528149f422fcab92e2 Mon Sep 17 00:00:00 2001 From: Noah Huesser Date: Wed, 21 Aug 2019 21:14:45 +0200 Subject: [PATCH] Add configurable background color via per tile feature; panicks somehow ... --- config/default.toml | 2 +- config/style.css | 4 ++ src/css.rs | 40 +++++++++---------- src/drawing/feature.rs | 2 +- src/drawing/feature_collection.rs | 1 + src/drawing/painter.rs | 47 +++++++++++++++++++++-- src/drawing/ui.rs | 6 +-- src/vector_tile/object.rs | 3 -- src/vector_tile/tile.rs | 64 ++++++++++++++++++++++++------- 9 files changed, 124 insertions(+), 45 deletions(-) diff --git a/config/default.toml b/config/default.toml index c4cb76a..552aa24 100644 --- a/config/default.toml +++ b/config/default.toml @@ -7,6 +7,6 @@ vertex_shader = "config/shader.vert" fragment_shader = "config/shader.frag" css = "config/style.css" max_tiles = 200 -max_features = 1000 +max_features = 1001 tile_size = 384 msaa_samples = 1 diff --git a/config/style.css b/config/style.css index 96ed610..b735fc5 100644 --- a/config/style.css +++ b/config/style.css @@ -1,3 +1,7 @@ +background { + background-color: white; +} + layer[name=water] { background-color: rgba(14, 181, 223, 1.0); border-width: 1px; diff --git a/src/css.rs b/src/css.rs index 5ae6e18..80a300f 100644 --- a/src/css.rs +++ b/src/css.rs @@ -240,26 +240,26 @@ impl Selector { } /// Makes the selector require the type `typ`. - pub fn with_type(mut self, typ: String) -> Self { - self.typ = Some(typ); + pub fn with_type(mut self, typ: impl Into) -> Self { + self.typ = Some(typ.into()); self } /// Makes the selector require the id `id`. - pub fn _with_id(mut self, id: String) -> Self { - self.id = Some(id); + pub fn _with_id(mut self, id: impl Into) -> Self { + self.id = Some(id.into()); self } /// Makes the selector require the class `class`. - pub fn _with_class(mut self, class: String) -> Self { - self.classes.push(class); + pub fn _with_class(mut self, class: impl Into) -> Self { + self.classes.push(class.into()); self } /// Makes the selector require the kv `key`/`value`. - pub fn with_any(mut self, key: String, value: String) -> Self { - self.any.insert(key, value); + pub fn with_any(mut self, key: impl Into, value: impl Into) -> Self { + self.any.insert(key.into(), value.into()); self } @@ -473,19 +473,19 @@ fn unitless_value<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str /// A struct to represent any RGB color. #[derive(Debug,PartialEq, Clone)] pub struct Color { - pub r: u8, - pub g: u8, - pub b: u8, + pub r: f32, + pub g: f32, + pub b: f32, pub a: f32, } impl Color { - pub const TRANSPARENT: Color = Color { r: 0, g: 0, b: 0, a: 0.0, }; - pub const _WHITE: Color = Color { r: 255, g: 255, b: 255, a: 1.0, }; - pub const _BLACK: Color = Color { r: 0, g: 0, b: 0, a: 1.0, }; - pub const RED: Color = Color { r: 255, g: 0, b: 0, a: 1.0, }; - pub const GREEN: Color = Color { r: 0, g: 255, b: 0, a: 1.0, }; - pub const BLUE: Color = Color { r: 0, g: 0, b: 255, a: 1.0, }; + pub const TRANSPARENT: Color = Color { r: 0.0, g: 0.0, b: 0.0, a: 0.0, }; + pub const WHITE: Color = Color { r: 1.0, g: 1.0, b: 1.0, a: 1.0, }; + pub const BLACK: Color = Color { r: 0.0, g: 0.0, b: 0.0, a: 1.0, }; + pub const RED: Color = Color { r: 1.0, g: 0.0, b: 0.0, a: 1.0, }; + pub const GREEN: Color = Color { r: 0.0, g: 1.0, b: 0.0, a: 1.0, }; + pub const BLUE: Color = Color { r: 0.0, g: 0.0, b: 1.0, a: 1.0, }; } /// Converts a hex string into an `u8`. @@ -511,7 +511,7 @@ fn hex_color<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, CSS let (input, _) = tag("#")(input)?; let (input, (r, g, b)) = tuple((hex_primary, hex_primary, hex_primary))(input)?; - Ok((input, CSSValue::Color(Color { r, g, b, a: 1.0 }))) + Ok((input, CSSValue::Color(Color { r: r as f32 / 255.0, g: g as f32 / 255.0, b: b as f32 / 255.0, a: 1.0 }))) } fn u8<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, u8, E> { @@ -535,7 +535,7 @@ fn rgba_color<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, CS float, ))(input)?; let (input, _) = tag(")")(input)?; - Ok((input, CSSValue::Color(Color { r, g, b, a }))) + Ok((input, CSSValue::Color(Color {r: r as f32 / 255.0, g: g as f32 / 255.0, b: b as f32 / 255.0, a }))) } /// Parse a single hex color code including the `#`. @@ -549,5 +549,5 @@ fn rgb_color<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, CSS u8, ))(input)?; let (input, _) = tag(")")(input)?; - Ok((input, CSSValue::Color(Color { r, g, b, a: 1.0 }))) + Ok((input, CSSValue::Color(Color { r: r as f32 / 255.0, g: g as f32 / 255.0, b: b as f32 / 255.0, a: 1.0 }))) } \ No newline at end of file diff --git a/src/drawing/feature.rs b/src/drawing/feature.rs index 2e1060f..79f189b 100644 --- a/src/drawing/feature.rs +++ b/src/drawing/feature.rs @@ -17,7 +17,7 @@ pub struct DrawableColor { impl From for DrawableColor { fn from(value: Color) -> Self { Self { - r: value.r as f32 / 255.0, g: value.g as f32 / 255.0, b: value.b as f32 / 255.0, a: value.a, + r: value.r, g: value.g, b: value.b, a: value.a, } } } diff --git a/src/drawing/feature_collection.rs b/src/drawing/feature_collection.rs index 7580b97..e665080 100644 --- a/src/drawing/feature_collection.rs +++ b/src/drawing/feature_collection.rs @@ -27,6 +27,7 @@ impl FeatureCollection { } pub fn add_feature(&mut self, mut feature: Feature) -> u32 { + dbg!(self.features.len()); assert!(self.features.len() < self.n_features_max as usize); feature.id = self.features.len() as u32; self.features.push(feature); diff --git a/src/drawing/painter.rs b/src/drawing/painter.rs index 29881f3..4258763 100644 --- a/src/drawing/painter.rs +++ b/src/drawing/painter.rs @@ -24,7 +24,12 @@ use crate::vector_tile::math::TileId; use crate::drawing::{ drawable_tile::DrawableTile, }; -use crate::css::RulesCache; +use crate::css::{ + CSSValue, + Selector, + Color, + RulesCache, + }; use std::collections::BTreeMap; use wgpu::{ @@ -190,7 +195,7 @@ impl Painter { ] }); - let feature_collection = Arc::new(RwLock::new(FeatureCollection::new(500))); + let feature_collection = Arc::new(RwLock::new(FeatureCollection::new(CONFIG.renderer.max_features as u32))); let swap_chain_descriptor = wgpu::SwapChainDescriptor { usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, @@ -715,6 +720,41 @@ impl Painter { feature_collection.load_styles(app_state.zoom, &mut app_state.css_cache); } + pub fn load_background_color(&self, app_state: &AppState) -> Color { + let rules = app_state.css_cache.get_matching_rules( + &Selector::new().with_type("background".to_string()).with_any("zoom".to_string(), (app_state.zoom.floor() as u32).to_string()) + ); + + let background_color = rules + .iter() + .filter_map(|r| r.kvs.get("background-color")) + .last(); + + if let Some(color) = background_color { + match color { + CSSValue::Color(bg) => bg.clone(), + CSSValue::String(string) => { + match &string[..] { + "red" => Color::RED, + "green" => Color::GREEN, + "blue" => Color::BLUE, + // Other CSS colors to come later. + color => { + log::info!("The color '{}' is currently not supported.", color); + Color::WHITE + }, + } + }, + value => { + log::info!("The value '{:?}' is currently not supported for 'background-color'.", value); + Color::WHITE + }, + } + } else { + Color::WHITE + } + } + pub fn paint(&mut self, hud: &mut super::ui::HUD, app_state: &mut AppState) { let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); self.load_tiles(app_state); @@ -733,6 +773,7 @@ impl Painter { let num_tiles = self.loaded_tiles.len(); let features = feature_collection.get_features(); if features.len() > 0 && num_tiles > 0 { + let c = self.load_background_color(app_state); let frame = self.swap_chain.get_next_texture(); { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { @@ -741,7 +782,7 @@ impl Painter { resolve_target: if CONFIG.renderer.msaa_samples > 1 { Some(&frame.view) } else { None }, load_op: wgpu::LoadOp::Clear, store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color::WHITE, + clear_color: wgpu::Color { r: c.r, g: c.g, b: c.b, a: c.a }, }], depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor{ attachment: &self.stencil, diff --git a/src/drawing/ui.rs b/src/drawing/ui.rs index 3f85b54..0acdb52 100644 --- a/src/drawing/ui.rs +++ b/src/drawing/ui.rs @@ -196,9 +196,9 @@ fn add_color_picker(ui: &Ui, rule: &mut Rule, attribute: &str) { .build(&ui); rule.kvs.insert(attribute.to_string(), CSSValue::Color(Color { - r: (color[0] * 255.0) as u8, - g: (color[1] * 255.0) as u8, - b: (color[2] * 255.0) as u8, + r: color[0], + g: color[1], + b: color[2], a: color[3], })); } \ No newline at end of file diff --git a/src/vector_tile/object.rs b/src/vector_tile/object.rs index 3b88b91..659e08b 100644 --- a/src/vector_tile/object.rs +++ b/src/vector_tile/object.rs @@ -12,7 +12,6 @@ pub enum ObjectType { #[derive(Debug, Clone)] pub struct Object { pub selector: Selector, - pub tags: HashMap, pub points: Vec, pub object_type: ObjectType, } @@ -20,13 +19,11 @@ pub struct Object { impl Object { pub fn new( selector: Selector, - tags: HashMap, points: Vec, object_type: ObjectType ) -> Self { Self { selector, - tags, points, object_type } diff --git a/src/vector_tile/tile.rs b/src/vector_tile/tile.rs index 4457547..69fed08 100644 --- a/src/vector_tile/tile.rs +++ b/src/vector_tile/tile.rs @@ -17,11 +17,17 @@ use crate::vector_tile::object::ObjectType; use lyon::tessellation::geometry_builder::{ VertexBuffers, }; +use crate::css::Selector; +use crate::vector_tile::object::Object; use crate::drawing::vertex::{ Vertex, LayerVertexCtor, }; +use lyon::tessellation::{ + FillTessellator, + FillOptions, +}; use lyon::path::Path; @@ -76,6 +82,39 @@ impl Tile { let mut builder = MeshBuilder::new(&mut mesh, LayerVertexCtor::new(tile_id, 1.0)); let extent = tile.layers[0].extent as u16; + // Add a background rectangle to each tile + // let selector = Selector::new().with_type("background"); + + // let mut path_builder = Path::builder(); + // path_builder.move_to((-10.0, -10.0).into()); + // path_builder.line_to((-10.0, extent as f32 + 10.0).into()); + // path_builder.line_to((extent as f32 + 10.0, extent as f32 + 10.0).into()); + // path_builder.line_to((extent as f32 + 10.0, -10.0).into()); + // path_builder.close(); + // let path = path_builder.build(); + + // { + // let mut feature_collection = feature_collection.write().unwrap(); + // let current_feature_id = if let Some(feature_id) = feature_collection.get_feature_id(&selector) { + // feature_id + // } else { + // feature_collection.add_feature(Feature::new(selector.clone(), 0)) + // }; + // builder.set_current_feature_id(current_feature_id); + // } + + // FillTessellator::new().tessellate_path( + // &path, + // &FillOptions::tolerance(0.0001).with_normals(true), + // &mut builder, + // ).expect("This is a bug. Please report it."); + + // objects.push(Object::new( + // selector, + // path.points().iter().cloned().collect(), + // ObjectType::Polygon + // )); + for layer in tile.layers { let mut index_start_before = builder.get_current_index(); let layer_id = layer_num(&layer.name); @@ -91,8 +130,6 @@ impl Tile { let mut selector = crate::css::Selector::new() .with_type("layer".to_string()) .with_any("name".to_string(), layer.name.to_string()); - - let mut tags = std::collections::HashMap::::new(); for tag in feature.tags.chunks(2) { let key = layer.keys[tag[0] as usize].to_string(); @@ -107,18 +144,18 @@ impl Tile { value.string_value.clone().unwrap().to_string() ) }, - _ => (), + _ => { + selector = selector.with_any(key.clone(), { + value.string_value.map_or(String::new(), |v| v.to_string()) + + &value.float_value.map_or(String::new(), |v| v.to_string()) + + &value.double_value.map_or(String::new(), |v| v.to_string()) + + &value.int_value.map_or(String::new(), |v| v.to_string()) + + &value.uint_value.map_or(String::new(), |v| v.to_string()) + + &value.sint_value.map_or(String::new(), |v| v.to_string()) + + &value.bool_value.map_or(String::new(), |v| v.to_string()) + }); + }, } - - tags.insert(key, { - value.string_value.map_or(String::new(), |v| v.to_string()) - + &value.float_value.map_or(String::new(), |v| v.to_string()) - + &value.double_value.map_or(String::new(), |v| v.to_string()) - + &value.int_value.map_or(String::new(), |v| v.to_string()) - + &value.uint_value.map_or(String::new(), |v| v.to_string()) - + &value.sint_value.map_or(String::new(), |v| v.to_string()) - + &value.bool_value.map_or(String::new(), |v| v.to_string()) - }); } let paths = geometry_commands_to_paths( @@ -135,7 +172,6 @@ impl Tile { object_type.map(|ot| objects.push(object::Object::new( selector.clone(), - tags, paths[0].points().iter().cloned().collect(), ot )));