From 1215f6f1fe955d74daf8b69d3aa7fa4a50317e8d Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Fri, 4 Apr 2014 13:24:11 -0700 Subject: [PATCH] refs #101: data sources with styling * add second, satellite class to stylesheet * get rid of tile clipping masks for now * flesh out raster styling properties --- bin/style.js | 122 +++++++++++++++++++++++ include/llmr/map/source.hpp | 3 +- include/llmr/renderer/painter.hpp | 4 +- include/llmr/style/class_description.hpp | 1 + include/llmr/style/properties.hpp | 9 ++ include/llmr/style/style.hpp | 1 + include/llmr/style/style_parser.hpp | 1 + src/map/map.cpp | 73 ++++++++------ src/map/source.cpp | 15 +-- src/renderer/painter.cpp | 52 +++++----- src/style/style.cpp | 12 +++ src/style/style_parser.cpp | 16 +++ 12 files changed, 246 insertions(+), 63 deletions(-) diff --git a/bin/style.js b/bin/style.js index cda0b0f94..b9d404a9e 100644 --- a/bin/style.js +++ b/bin/style.js @@ -2,6 +2,10 @@ module.exports = { "buckets": { + "satellite": { + "source": "satellite", + "type": "raster" + }, "water": { "source": "mapbox streets", "layer": "water", @@ -128,6 +132,7 @@ module.exports = { "text": "#000000", }, "structure": [ + { "name": "satellite", "bucket": "satellite" }, { "name": "park", "bucket": "park" }, { "name": "wood", "bucket": "wood" }, { "name": "water", "bucket": "water" }, @@ -265,6 +270,123 @@ module.exports = { "size": ["exponential", 14, 8, 1, 8, 12] }, } + }, + { + "name": "satellite", + "layers": { + "background": { + "type": "background", + "color": "#333333", + "opacity": 1.0 + }, + "park": { + "type": "fill", + "opacity": 0, + }, + "wood": { + "type": "fill", + "opacity": 0, + }, + "water": { + "type": "fill", + "opacity": 0, + }, + "building": { + "type": "fill", + "opacity": 0, + }, + "road_limited": { + "type": "line", + "color": "#BBBBBB", + "width": [ + "stops", + { z: 0, val: 1 }, + { z: 30, val: 1 } + ] + }, + "road_regular": { + "type": "line", + "color": "#999999", + "width": [ + "stops", + { z: 0, val: 0.5 }, + { z: 13, val: 0.5 }, + { z: 16, val: 2 }, + { z: 20, val: 16 }, + { z: 30, val: 16 } + ], + }, + "road_large": { + "type": "line", + "color": "#666666", + "width": [ + "stops", + { z: 0, val: 0.5 }, + { z: 11, val: 0.5 }, + { z: 13, val: 1 }, + { z: 16, val: 4 }, + { z: 20, val: 32 }, + { z: 30, val: 32 } + ], + }, + "alcohol_poi": { + "type": "point", + "color": "#cccccc", + "size": 18, + "image": "alcohol-shop", + "enabled": [ "min", 17 ] + }, + "cafe_poi": { + "type": "point", + "color": "#cccccc", + "size": 18, + "image": "cafe", + "enabled": [ "min", 17 ] + }, + "embassy_poi": { + "type": "point", + "color": "#cccccc", + "size": 18, + "image": "embassy", + "enabled": [ "min", 17 ] + }, + "park_poi": { + "type": "point", + "color": "#cccccc", + "size": 18, + "image": "park", + "enabled": [ "min", 17 ] + }, + "restaurant_poi": { + "type": "point", + "color": "#cccccc", + "size": 18, + "image": "restaurant", + "enabled": [ "min", 17 ] + }, + "country_label": { + "type": "text", + "stroke": [ 1, 1, 1, 0.7 ], + "color": "text", + "size": 16 + }, + "place_label": { + "type": "text", + "stroke": [1,1,1,0.7], + "color": "text", + "size": 18 + }, + "road_label": { + "type": "text", + "color": "text", + "stroke": [1,1,1,0.7], + "size": ["exponential", 14, 8, 1, 8, 12] + }, + "satellite": { + "type": "raster", + "opacity": 0.25 + }, + } } ] }; diff --git a/include/llmr/map/source.hpp b/include/llmr/map/source.hpp index 7eca41875..2ae210ab8 100644 --- a/include/llmr/map/source.hpp +++ b/include/llmr/map/source.hpp @@ -27,7 +27,8 @@ public: Source(Map& map, Transform& transform, Painter& painter, Texturepool& texturepool, const char *url = "", float pixel_ratio = 1.0, Type type = Type::vector, std::list zooms = {0}, uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 14, bool enabled = true); bool update(); - void render(); + void prepare_render(bool is_baselayer = false); + void render(bool is_baselayer = false); public: bool enabled; diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index c5cf22c5e..fd3c84d3f 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -46,13 +46,13 @@ public: void resize(int width, int height); void prepareClippingMask(); - void drawClippingMask(const mat4& matrix, uint8_t clip_id, bool opaque = true); + void drawClippingMask(const mat4& matrix, uint8_t clip_id); void finishClippingMask(); bool needsAnimation() const; private: void setupShaders(); - void renderRaster(const std::shared_ptr& tile); + void renderRaster(const std::string& layer_name, const std::shared_ptr& tile_data); void renderLayers(const std::shared_ptr& tile, const std::vector& layers); void renderLayer(const std::shared_ptr& tile_data, const LayerDescription& layer_desc); void renderDebug(const std::shared_ptr& tile); diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp index e98aee0c5..dc8c5faa2 100644 --- a/include/llmr/style/class_description.hpp +++ b/include/llmr/style/class_description.hpp @@ -15,6 +15,7 @@ public: std::map line; std::map point; std::map text; + std::map raster; }; diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp index 563201177..8baa6cfef 100644 --- a/include/llmr/style/properties.hpp +++ b/include/llmr/style/properties.hpp @@ -136,6 +136,15 @@ struct BackgroundProperties { float opacity = 1.0; }; +struct RasterClass { + FunctionProperty enabled = true; + FunctionProperty opacity = 1; +}; + +struct RasterProperties { + bool enabled = true; + float opacity = 1.0; +}; } diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index a004df438..2f1e42c4f 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -47,6 +47,7 @@ public: std::map lines; std::map points; std::map texts; + std::map rasters; } computed; }; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 60bb9a050..a096a81a8 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -25,6 +25,7 @@ private: PointClass parsePointClass(JSVal value); TextClass parseTextClass(JSVal value); BackgroundClass parseBackgroundClass(JSVal value); + RasterClass parseRasterClass(JSVal value); bool parseBoolean(JSVal value); std::string parseString(JSVal value); diff --git a/src/map/map.cpp b/src/map/map.cpp index a02cc93eb..b7ee7a4c5 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -37,9 +37,33 @@ void Map::setup(float pixelRatio) { style.loadJSON(resources::style, resources::style_size); - sources.emplace("mapbox streets", Source(*this, transform, painter, texturepool, "http://a.gl-api-us-east-1.tilestream.net/v3/mapbox.mapbox-streets-v4/%d/%d/%d.gl.pbf", pixelRatio, Source::Type::vector, {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14}, 512, 0, 14, true)); + sources.emplace("mapbox streets", + Source(*this, + transform, + painter, + texturepool, + "http://a.gl-api-us-east-1.tilestream.net/v3/mapbox.mapbox-streets-v4/%d/%d/%d.gl.pbf", + pixelRatio, + Source::Type::vector, + {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14}, + 512, + 0, + 14, + true)); - sources.emplace("satellite", Source(*this, transform, painter, texturepool, "https://a.tiles.mapbox.com/v3/justin.hh0gkdfm/%d/%d/%d%s.png256", pixelRatio, Source::Type::raster, {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21}, 256, 0, 21, false)); + sources.emplace("satellite", + Source(*this, + transform, + painter, + texturepool, + "https://a.tiles.mapbox.com/v3/justin.hh0gkdfm/%d/%d/%d%s.png256", + pixelRatio, + Source::Type::raster, + {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21}, + 256, + 0, + 21, + false)); } void Map::loadStyle(const uint8_t *const data, uint32_t bytes) { @@ -295,41 +319,32 @@ bool Map::render() { painter.changeMatrix(); - // First, update all tile matrices with the new transform and render into - // the stencil buffer. -// uint8_t i = 1; - + // First, update the sources' tile matrices with the new + // transform and render into the stencil buffer, including + // drawing the background. + painter.prepareClippingMask(); -// for (Tile& tile : tiles) { -// if (tile.data && tile.data->state == TileData::State::parsed) { -// // The position matrix. -// transform.matrixFor(tile.matrix, tile.id); -// matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix); -// tile.clip_id = i++; -// painter.drawClippingMask(tile.matrix, tile.clip_id, !tile.data->use_raster); -// } -// } + bool is_baselayer = true; for (std::pair pair : sources) { Source& source = pair.second; - source.render(); + source.prepare_render(is_baselayer); + is_baselayer = source.enabled ? false : (true && is_baselayer); } -// painter.finishClippingMask(); + painter.finishClippingMask(); -// for (const Tile& tile : tiles) { -// if (tile.data && tile.data->state == TileData::State::parsed) { -// if (tile.data->use_raster && *tile.data->raster && !tile.data->raster->textured) { -// tile.data->raster->setTexturepool(&texturepool); -// tile.data->raster->beginFadeInAnimation(); -// } -// if (tile.data->use_raster && tile.data->raster->needsAnimation()) { -// tile.data->raster->updateAnimations(); -// } -// painter.render(tile); -// } -// } + // Then, render each source's tiles. TODO: handle more than one + // vector source. + + is_baselayer = true; + + for (std::pair pair : sources) { + Source& source = pair.second; + source.render(is_baselayer); + is_baselayer = source.enabled ? false : (true && is_baselayer); + } painter.renderMatte(); diff --git a/src/map/source.cpp b/src/map/source.cpp index 7685b1a6d..2f692b8f0 100644 --- a/src/map/source.cpp +++ b/src/map/source.cpp @@ -30,24 +30,25 @@ bool Source::update() { return updateTiles(); } -void Source::render() { - if (!enabled) { - return; - } +void Source::prepare_render(bool is_baselayer) { + if (!enabled) return; uint8_t i = 1; for (Tile& tile : tiles) { if (tile.data && tile.data->state == TileData::State::parsed) { - // The position matrix. transform.matrixFor(tile.matrix, tile.id); matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix); tile.clip_id = i++; - painter.drawClippingMask(tile.matrix, tile.clip_id, (type != Type::raster)); + if (is_baselayer) { + painter.drawClippingMask(tile.matrix, tile.clip_id); + } } } +} - painter.finishClippingMask(); +void Source::render(bool is_baselayer) { + if (!enabled) return; for (const Tile& tile : tiles) { if (tile.data && tile.data->state == TileData::State::parsed) { diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index a04de1733..994016aaa 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -123,13 +123,13 @@ void Painter::prepareClippingMask() { coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); } -void Painter::drawClippingMask(const mat4& matrix, uint8_t clip_id, bool opaque) { +void Painter::drawClippingMask(const mat4& matrix, uint8_t clip_id) { plainShader->setMatrix(matrix); plainShader->setColor(style.computed.background.color); plainShader->setOpacity(style.computed.background.opacity); - glStencilFunc(GL_ALWAYS, clip_id, 0xFF); + glStencilFunc(GL_ALWAYS, 1, 0xFF); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); } @@ -160,31 +160,14 @@ void Painter::render(const Tile& tile) { frameHistory.record(transform.getNormalizedZoom()); matrix = tile.matrix; - glStencilFunc(GL_EQUAL, tile.clip_id, 0xFF); - if (tile.data->raster) { - renderRaster(tile.data); - } else { - renderLayers(tile.data, style.layers); - } + renderLayers(tile.data, style.layers); if (settings.debug) { renderDebug(tile.data); } } -void Painter::renderRaster(const std::shared_ptr& tile_data) { - useProgram(rasterShader->program); - rasterShader->setMatrix(matrix); - rasterShader->setImage(0); - rasterShader->setOpacity(tile_data->raster->opacity); - tile_data->raster->bind(true); - - coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0)); - glDepthRange(strata, 1.0f); - glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); -} - void Painter::renderLayers(const std::shared_ptr& tile_data, const std::vector& layers) { float strata_thickness = 1.0f / (layers.size() + 1); @@ -226,14 +209,35 @@ void Painter::renderLayer(const std::shared_ptr& tile_data, const Laye } else { // This is a singular layer. Try to find the bucket associated with // this layer and render it. - auto bucket_it = tile_data->buckets.find(layer_desc.bucket_name); - if (bucket_it != tile_data->buckets.end()) { - assert(bucket_it->second); - bucket_it->second->render(*this, layer_desc.name, tile_data->id); + if (layer_desc.name == "satellite" && tile_data && tile_data->raster) { // FIXME + renderRaster(layer_desc.name, tile_data); + } else { + auto bucket_it = tile_data->buckets.find(layer_desc.bucket_name); + if (bucket_it != tile_data->buckets.end()) { + assert(bucket_it->second); + bucket_it->second->render(*this, layer_desc.name, tile_data->id); + } } } } +void Painter::renderRaster(const std::string& layer_name, const std::shared_ptr& tile_data) { + if (pass == Opaque) return; + + const RasterProperties& properties = style.computed.rasters[layer_name]; + if (!properties.enabled) return; + + useProgram(rasterShader->program); + rasterShader->setMatrix(matrix); + rasterShader->setImage(0); + rasterShader->setOpacity(properties.opacity * tile_data->raster->opacity); + tile_data->raster->bind(true); + + coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0)); + glDepthRange(strata, 1.0f); + glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index()); +} + void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id) { // Abort early. if (bucket.empty()) return; diff --git a/src/style/style.cpp b/src/style/style.cpp index 0a63e9d5b..cfda9699a 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -92,6 +92,18 @@ void Style::cascade(float z) { text.alwaysVisible = layer.alwaysVisible.evaluate(z); } + // Cascade raster classes + for (const auto& raster_pair : sheetClass.raster) { + const std::string& layer_name = raster_pair.first; + const llmr::RasterClass& layer = raster_pair.second; + + // TODO: This should be restricted to raster styles that have actual + // values so as to not override with default values. + llmr::RasterProperties& raster = computed.rasters[layer_name]; + raster.enabled = layer.enabled.evaluate(z); + raster.opacity = layer.opacity.evaluate(z); + } + // Cascade background computed.background.color = sheetClass.background.color; computed.background.opacity = sheetClass.background.opacity.evaluate(z); diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 893e65ea7..9064b3ac6 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -254,6 +254,8 @@ void StyleParser::parseClass(const std::string& name, JSVal value, ClassDescript class_desc.point.insert({ name, std::forward(parsePointClass(value)) }); } else if (type_name == "text") { class_desc.text.insert({ name, std::forward(parseTextClass(value)) }); + } else if (type_name == "raster") { + class_desc.raster.insert({ name, std::forward(parseRasterClass(value)) }); } else if (type_name == "background") { class_desc.background = parseBackgroundClass(value); } else { @@ -502,6 +504,20 @@ TextClass StyleParser::parseTextClass(JSVal value) { return klass; } +RasterClass StyleParser::parseRasterClass(JSVal value) { + RasterClass klass; + + if (value.HasMember("enabled")) { + klass.enabled = parseFunction(value["enabled"]); + } + + if (value.HasMember("opacity")) { + klass.opacity = parseFunction(value["opacity"]); + } + + return klass; +} + BackgroundClass StyleParser::parseBackgroundClass(JSVal value) { BackgroundClass klass;