diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-01-27 14:07:56 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-01-27 14:07:56 +0100 |
commit | e2dbcc95b5cf171e99e237513998d17a0c70f3ad (patch) | |
tree | bc7fc34b47402aaa9303c8d038d2158f1b7b7aa3 /src | |
parent | 2a6e4597e29d440e03416b0cf9d47da4eb2ff781 (diff) | |
download | qtlocation-mapboxgl-e2dbcc95b5cf171e99e237513998d17a0c70f3ad.tar.gz |
draw fills according to the style
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/map/map.cpp | 10 | ||||
-rw-r--r-- | src/map/tile.cpp | 169 | ||||
-rw-r--r-- | src/renderer/fill_bucket.cpp | 11 | ||||
-rw-r--r-- | src/renderer/painter.cpp | 37 | ||||
-rw-r--r-- | src/resources/style.cpp | 9 | ||||
-rw-r--r-- | src/style/bucket_description.cpp | 19 | ||||
-rw-r--r-- | src/style/layer_description.cpp | 12 | ||||
-rw-r--r-- | src/style/style.cpp | 163 | ||||
-rw-r--r-- | src/style/value.cpp | 25 |
10 files changed, 418 insertions, 43 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7593877d91..6a6e7e4a9b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,8 +11,12 @@ SET(llmr_SOURCES renderer/shader-outline.cpp renderer/shader.cpp renderer/fill_bucket.cpp + resources/style.cpp shader/shaders.cpp style/style.cpp + style/value.cpp + style/bucket_description.cpp + style/layer_description.cpp util/animation.cpp util/mat4.cpp ) @@ -40,6 +44,7 @@ SET(llmr_HEADERS ) INCLUDE_DIRECTORIES( + ${Boost_INCLUDE_DIR} ../include ) @@ -52,4 +57,5 @@ LINK_DIRECTORIES( ) TARGET_LINK_LIBRARIES(llmr + ${Boost_LIBRARIES} ) diff --git a/src/map/map.cpp b/src/map/map.cpp index 6d716fea42..31c4f1d81f 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -2,6 +2,8 @@ #include <llmr/map/tile.hpp> //#include <llmr/util/vec2.hpp> +#include <llmr/resources/style.hpp> + #include <iostream> #include <thread> @@ -24,10 +26,12 @@ Map::~Map() { void Map::setup() { painter.setup(); + + style.load(resources::style, resources::style_size); } -void Map::loadStyle(const uint8_t *data, uint32_t bytes) { - style.load(pbf(data, bytes)); +void Map::loadStyle(const uint8_t *const data, uint32_t bytes) { + style.load(data, bytes); update(); } @@ -119,7 +123,7 @@ Tile::Ptr Map::addTile(const Tile::ID& id) { if (!tile.get()) { // We couldn't find the tile in the list. Create a new one. - tile = std::make_shared<Tile>(id); + tile = std::make_shared<Tile>(id, style); assert(tile); // std::cerr << "init " << id.z << "/" << id.x << "/" << id.y << std::endl; // std::cerr << "add " << tile->toString() << std::endl; diff --git a/src/map/tile.cpp b/src/map/tile.cpp index 4dac3e82f1..e8a0c1979a 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -9,6 +9,8 @@ #include <llmr/util/string.hpp> #include <llmr/geometry/geometry.hpp> #include <llmr/renderer/fill_bucket.hpp> +#include <llmr/style/style.hpp> +#include <llmr/style/value.hpp> #include <cmath> using namespace llmr; @@ -39,17 +41,20 @@ std::forward_list<Tile::ID> Tile::children(const ID& id, int32_t z) { } -Tile::Tile(ID id) +Tile::Tile(ID id, const Style& style) : id(id), state(initial), - fillBuffer(), + lineVertex(std::make_shared<linevertexbuffer>()), + debugFontVertex(std::make_shared<debug_font_buffer>()), + fillBuffer(std::make_shared<FillBuffer>()), data(0), - bytes(0) { + bytes(0), + style(style) { // Initialize tile debug coordinates char coord[32]; snprintf(coord, sizeof(coord), "%d/%d/%d", id.z, id.x, id.y); - debugFontVertex.addText(coord, 50, 200, 5); + debugFontVertex->addText(coord, 50, 200, 5); } Tile::~Tile() { @@ -58,6 +63,7 @@ Tile::~Tile() { // fprintf(stderr, "[%p] deleting tile %d/%d/%d\n", this, id.z, id.x, id.y); if (this->data) { free(this->data); + this->data = NULL; } } @@ -88,17 +94,11 @@ bool Tile::parse() { return false; } - // fprintf(stderr, "[%p] parsing tile [%d/%d/%d]...\n", this, z, x, y); - - pbf tile(data, bytes); try { - while (tile.next()) { - if (tile.tag == 3) { // layer - parseLayer(tile.message()); - } else { - tile.skip(); - } - } + pbf tile(data, bytes); + // fprintf(stderr, "[%p] parsing tile [%d/%d/%d]...\n", this, z, x, y); + + parseLayers(tile, style.layers); } catch (const std::exception& ex) { fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what()); cancel(); @@ -114,18 +114,65 @@ bool Tile::parse() { return true; } -void Tile::parseLayer(const pbf data) { - pbf layer(data); - while (layer.next()) { - if (layer.tag == 1) { - std::string name = layer.string(); - if (name == "water") { - layers.emplace_front(name, createFillBucket(data)); +void Tile::parseLayers(const pbf& data, const std::vector<LayerDescription>& layers) { + for (const LayerDescription& layer_desc : layers) { + if (layer_desc.child_layer.size()) { + // This is a layer group. + // TODO: create framebuffer + parseLayers(data, layer_desc.child_layer); + // TODO: render framebuffer on previous framebuffer + } else { + // This is a singular layer. Check if this bucket already exists. If not, + // parse this bucket. + auto bucket_it = buckets.find(layer_desc.bucket_name); + if (bucket_it == buckets.end()) { + auto bucket_it = style.buckets.find(layer_desc.bucket_name); + if (bucket_it != style.buckets.end()) { + // Only create the new bucket if we have an actual specification + // for it. + std::shared_ptr<Bucket> bucket = createBucket(data, bucket_it->second); + if (bucket) { + // Bucket creation might fail because the data tile may not + // contain any data that falls into this bucket. + buckets[layer_desc.bucket_name] = bucket; + } + } else { + // There is no proper specification for this bucket, even though + // it is referenced in the stylesheet. + fprintf(stderr, "Stylesheet specifies bucket %s, but it is not defined\n", layer_desc.bucket_name.c_str()); + } + } + } + } +} + +std::shared_ptr<Bucket> Tile::createBucket(const pbf& data, const BucketDescription& bucket_desc) { + pbf tile(data); + // TODO: remember data locations in tiles for faster parsing so that we don't + // have to go through the entire vector tile all the time. + while (tile.next()) { + if (tile.tag == 3) { // layer + pbf layer = tile.message(); + while (layer.next()) { + if (layer.tag == 1) { + std::string name = layer.string(); + if (name == bucket_desc.source_layer) { + if (bucket_desc.type == BucketType::Fill) { + return createFillBucket(layer, bucket_desc); + } else { + // TODO: create other bucket types. + } + } + } else { + layer.skip(); + } } } else { - layer.skip(); + tile.skip(); } } + + return NULL; } enum geom_type { @@ -135,19 +182,87 @@ enum geom_type { Polygon = 3 }; -std::shared_ptr<Bucket> Tile::createFillBucket(const pbf data) { - pbf layer(data); +std::shared_ptr<Bucket> Tile::createFillBucket(const pbf data, const BucketDescription& bucket_desc) { + pbf layer; std::shared_ptr<FillBucket> bucket = std::make_shared<FillBucket>(fillBuffer); + int32_t key = -1; + std::set<uint32_t> values; + + // If we filter further by field/value, parse the key/value indices first + // because protobuf doesn't mandate a particular key order. + if (bucket_desc.source_field.size()) { + uint32_t key_id = 0; + uint32_t value_id = 0; + + // Find out what key/value IDs we need. + layer = data; + while (layer.next()) { + if (layer.tag == 3) { // keys + if (layer.string() == bucket_desc.source_field) { + // We found the key + key = key_id; + } + key_id++; + } else if (layer.tag == 4) { // values + Value value = parseValue(layer.message()); + if (std::find(bucket_desc.source_value.begin(), bucket_desc.source_value.end(), value) != bucket_desc.source_value.end()) { + values.insert(value_id); + } + value_id++; + } else { + layer.skip(); + } + } + + if (key < 0 || values.empty()) { + // There are no valid values that we could possibly find. Abort early. + return bucket; + } + } + + // Now parse the features and optionally filter by key/value IDs. + layer = data; while (layer.next()) { if (layer.tag == 2) { // feature pbf feature = layer.message(); pbf geometry; geom_type type = Unknown; + bool skip = false; - while (feature.next()) { - if (feature.tag == 3) { // geometry type + while (!skip && feature.next()) { + if (feature.tag == 2) { // tags + if (key < 0) { + // We want to parse the entire layer anyway + feature.skip(); + } else { + // We only want to parse some features. + skip = true; + // tags are packed varints. They should have an even length. + pbf tags = feature.message(); + while (tags) { + uint32_t tag_key = tags.varint(); + if (tags) { + uint32_t tag_val = tags.varint(); + // Now check if the tag_key/tag_val pair is included + // in the set of key/values that we are looking for. + if (key == tag_key && values.find(tag_val) != values.end()) { + skip = false; + break; + } + } else { + // This should not happen; otherwise the vector tile + // is invalid. + throw std::runtime_error("uneven number of feature tag ids"); + } + } + } + } else if (feature.tag == 3) { // geometry type type = (geom_type)feature.varint(); + if (type != Polygon) { + skip = true; + break; + } } else if (feature.tag == 4) { // geometry geometry = feature.message(); } else { @@ -155,7 +270,7 @@ std::shared_ptr<Bucket> Tile::createFillBucket(const pbf data) { } } - if (type == Polygon && geometry) { + if (!skip && geometry) { bucket->addGeometry(geometry); } } else { diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp index f3d09511d3..07282a05ae 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -15,10 +15,10 @@ struct geometry_too_long_exception : std::exception {}; using namespace llmr; -FillBucket::FillBucket(FillBuffer& buffer) +FillBucket::FillBucket(const std::shared_ptr<FillBuffer>& buffer) : buffer(buffer), - vertex_start(buffer.vertex_length()), - elements_start(buffer.elements_length()), + vertex_start(buffer->vertex_length()), + elements_start(buffer->elements_length()), length(0) { } @@ -44,6 +44,9 @@ void FillBucket::addGeometry(pbf& geom) { } } + // Alias this. + FillBuffer& buffer = *this->buffer; + for (const std::vector<std::pair<int16_t, int16_t>>& line : lines) { uint32_t vertex_start = buffer.vertex_length(); @@ -96,7 +99,7 @@ void FillBucket::addGeometry(pbf& geom) { void FillBucket::drawElements(int32_t attrib) { char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(uint16_t)); char *elements_index = BUFFER_OFFSET(elements_start * 3 * sizeof(uint16_t)); - buffer.bind(); + buffer->bind(); for (const auto& group : groups) { glVertexAttribPointer(attrib, 2, GL_SHORT, GL_FALSE, 0, vertex_index); glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index); diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index b3e1fee569..139e434820 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -169,9 +169,7 @@ void Painter::render(const Tile::Ptr& tile) { // glLineWidth(2.0f); // glDrawArrays(GL_LINE_STRIP, 0, tile->lineVertex.length()); - for (Layer& layer : tile->layers) { - layer.bucket->render(*this, layer.name); - } + renderLayers(tile, style.layers); if (settings.debug) { renderDebug(tile); @@ -180,8 +178,33 @@ void Painter::render(const Tile::Ptr& tile) { renderBackground(); } +void Painter::renderLayers(const std::shared_ptr<Tile>& tile, const std::vector<LayerDescription>& layers) { + // Render everything top-to-bottom by using reverse iterators + typedef std::vector<LayerDescription>::const_reverse_iterator iterator; + for (iterator it = layers.rbegin(), end = layers.rend(); it != end; it++) { + const LayerDescription& layer_desc = *it; + + if (layer_desc.child_layer.size()) { + // This is a layer group. + // TODO: create framebuffer + renderLayers(tile, layer_desc.child_layer); + // TODO: render framebuffer on previous framebuffer + } else { + // This is a singular layer. Try to find the bucket associated with + // this layer and render it. + auto bucket_it = tile->buckets.find(layer_desc.bucket_name); + if (bucket_it != tile->buckets.end()) { + assert(bucket_it->second); + bucket_it->second->render(*this, layer_desc.name); + } + } + } +} + void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) { - const FillProperties& properties = style.computedFills[layer_name]; + const FillProperties& properties = style.computed.fills[layer_name]; + + if (!properties.enabled) return; // Draw the stencil mask. { @@ -315,14 +338,14 @@ void Painter::renderDebug(const Tile::Ptr& tile) { // draw debug info switchShader(lineShader); glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix); - tile->debugFontVertex.bind(); + tile->debugFontVertex->bind(); glVertexAttribPointer(lineShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, BUFFER_OFFSET(0)); glUniform4f(lineShader->u_color, 1.0f, 1.0f, 1.0f, 1.0f); glLineWidth(4.0f); - glDrawArrays(GL_LINES, 0, tile->debugFontVertex.length()); + glDrawArrays(GL_LINES, 0, tile->debugFontVertex->length()); glUniform4f(lineShader->u_color, 0.0f, 0.0f, 0.0f, 1.0f); glLineWidth(2.0f); - glDrawArrays(GL_LINES, 0, tile->debugFontVertex.length()); + glDrawArrays(GL_LINES, 0, tile->debugFontVertex->length()); // Revert blending mode to blend to the back. glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE); diff --git a/src/resources/style.cpp b/src/resources/style.cpp new file mode 100644 index 0000000000..69c0b10655 --- /dev/null +++ b/src/resources/style.cpp @@ -0,0 +1,9 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. +#include <llmr/resources/style.hpp> + +using namespace llmr; + +const unsigned char resources::style[] = { + 10, 25, 10, 5, 119, 97, 116, 101, 114, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 5, 119, 97, 116, 101, 114, 10, 60, 10, 10, 114, 111, 97, 100, 95, 108, 97, 114, 103, 101, 16, 2, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, 42, 5, 99, 108, 97, 115, 115, 50, 10, 10, 8, 109, 111, 116, 111, 114, 119, 97, 121, 50, 6, 10, 4, 109, 97, 105, 110, 56, 1, 64, 2, 10, 52, 10, 12, 114, 111, 97, 100, 95, 114, 101, 103, 117, 108, 97, 114, 16, 2, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, 42, 5, 99, 108, 97, 115, 115, 50, 8, 10, 6, 115, 116, 114, 101, 101, 116, 56, 1, 64, 2, 10, 60, 10, 12, 114, 111, 97, 100, 95, 108, 105, 109, 105, 116, 101, 100, 16, 2, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 4, 114, 111, 97, 100, 42, 5, 99, 108, 97, 115, 115, 50, 16, 10, 14, 115, 116, 114, 101, 101, 116, 95, 108, 105, 109, 105, 116, 101, 100, 56, 1, 64, 2, 10, 41, 10, 4, 112, 97, 114, 107, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 6, 10, 4, 112, 97, 114, 107, 10, 41, 10, 4, 119, 111, 111, 100, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 6, 10, 4, 119, 111, 111, 100, 10, 45, 10, 6, 115, 99, 104, 111, 111, 108, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 8, 10, 6, 115, 99, 104, 111, 111, 108, 10, 49, 10, 8, 99, 101, 109, 101, 116, 101, 114, 121, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 10, 10, 8, 99, 101, 109, 101, 116, 101, 114, 121, 10, 53, 10, 10, 105, 110, 100, 117, 115, 116, 114, 105, 97, 108, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 7, 108, 97, 110, 100, 117, 115, 101, 42, 5, 99, 108, 97, 115, 115, 50, 12, 10, 10, 105, 110, 100, 117, 115, 116, 114, 105, 97, 108, 10, 31, 10, 8, 98, 117, 105, 108, 100, 105, 110, 103, 16, 1, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 8, 98, 117, 105, 108, 100, 105, 110, 103, 10, 48, 10, 7, 97, 108, 99, 111, 104, 111, 108, 16, 3, 26, 7, 115, 116, 114, 101, 101, 116, 115, 34, 9, 112, 111, 105, 95, 108, 97, 98, 101, 108, 42, 4, 116, 121, 112, 101, 50, 9, 10, 7, 65, 108, 99, 111, 104, 111, 108, 18, 12, 10, 4, 112, 97, 114, 107, 18, 4, 112, 97, 114, 107, 18, 12, 10, 4, 119, 111, 111, 100, 18, 4, 119, 111, 111, 100, 18, 14, 10, 5, 119, 97, 116, 101, 114, 18, 5, 119, 97, 116, 101, 114, 18, 28, 10, 12, 114, 111, 97, 100, 95, 108, 105, 109, 105, 116, 101, 100, 18, 12, 114, 111, 97, 100, 95, 108, 105, 109, 105, 116, 101, 100, 18, 28, 10, 12, 114, 111, 97, 100, 95, 114, 101, 103, 117, 108, 97, 114, 18, 12, 114, 111, 97, 100, 95, 114, 101, 103, 117, 108, 97, 114, 18, 24, 10, 10, 114, 111, 97, 100, 95, 108, 97, 114, 103, 101, 18, 10, 114, 111, 97, 100, 95, 108, 97, 114, 103, 101, 18, 18, 10, 7, 97, 108, 99, 111, 104, 111, 108, 18, 7, 97, 108, 99, 111, 104, 111, 108, 26, 139, 2, 10, 7, 100, 101, 102, 97, 117, 108, 116, 18, 17, 10, 10, 98, 97, 99, 107, 103, 114, 111, 117, 110, 100, 21, 255, 255, 255, 255, 18, 13, 10, 4, 112, 97, 114, 107, 21, 255, 159, 223, 200, 24, 1, 18, 13, 10, 4, 119, 111, 111, 100, 21, 255, 102, 170, 51, 24, 1, 18, 14, 10, 5, 119, 97, 116, 101, 114, 21, 255, 230, 182, 115, 24, 1, 18, 46, 10, 12, 114, 111, 97, 100, 95, 108, 105, 109, 105, 116, 101, 100, 21, 255, 187, 187, 187, 34, 25, 10, 5, 115, 116, 111, 112, 115, 18, 16, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 160, 65, 0, 0, 128, 63, 18, 62, 10, 12, 114, 111, 97, 100, 95, 114, 101, 103, 117, 108, 97, 114, 21, 255, 153, 153, 153, 34, 41, 10, 5, 115, 116, 111, 112, 115, 18, 32, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 80, 65, 0, 0, 0, 63, 0, 0, 128, 65, 0, 0, 0, 64, 0, 0, 160, 65, 0, 0, 0, 66, 18, 68, 10, 10, 114, 111, 97, 100, 95, 108, 97, 114, 103, 101, 21, 255, 102, 102, 102, 34, 49, 10, 5, 115, 116, 111, 112, 115, 18, 40, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 48, 65, 0, 0, 0, 63, 0, 0, 80, 65, 0, 0, 128, 63, 0, 0, 128, 65, 0, 0, 128, 64, 0, 0, 160, 65, 0, 0, 128, 66, 18, 9, 10, 7, 97, 108, 99, 111, 104, 111, 108 +}; +const unsigned long resources::style_size = sizeof(resources::style); diff --git a/src/style/bucket_description.cpp b/src/style/bucket_description.cpp new file mode 100644 index 0000000000..94d0b8115c --- /dev/null +++ b/src/style/bucket_description.cpp @@ -0,0 +1,19 @@ +#include <llmr/style/bucket_description.hpp> + +#include <iostream> + +std::ostream& llmr::operator<<(std::ostream& os, const BucketDescription& bucket) { + os << "Bucket:" << std::endl; + os << " - type: " << (uint32_t)bucket.type << std::endl; + os << " - source_name: " << bucket.source_name << std::endl; + os << " - source_layer: " << bucket.source_layer << std::endl; + os << " - source_field: " << bucket.source_field << std::endl; + for (const Value& value : bucket.source_value) { + os << " - source_value: " << value << std::endl; + } + os << " - cap: " << (uint32_t)bucket.cap << std::endl; + os << " - join: " << (uint32_t)bucket.join << std::endl; + os << " - font: " << bucket.font << std::endl; + os << " - font_size: " << bucket.font_size << std::endl; + return os; +} diff --git a/src/style/layer_description.cpp b/src/style/layer_description.cpp new file mode 100644 index 0000000000..d4b8b7d678 --- /dev/null +++ b/src/style/layer_description.cpp @@ -0,0 +1,12 @@ +#include <llmr/style/layer_description.hpp> + +#include <iostream> + +std::ostream& llmr::operator<<(std::ostream& os, const LayerDescription& layer) { + os << "Structure: " << layer.name << std::endl; + os << " - bucket_name: " << layer.bucket_name << std::endl; + for (const LayerDescription& value : layer.child_layer) { + os << " - child_layer: " << value << std::endl; + } + return os; +} diff --git a/src/style/style.cpp b/src/style/style.cpp index a999289a04..0acce7c35b 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -1,15 +1,174 @@ #include <llmr/style/style.hpp> +#include <llmr/resources/style.hpp> + using namespace llmr; Style::Style() { - + appliedClasses.insert("default"); } void Style::reset() { + computed.fills.clear(); + computed.strokes.clear(); +} + +void Style::load(const uint8_t *const data, uint32_t bytes) { + pbf style(data, bytes); + + while (style.next()) { + if (style.tag == 1) { // bucket + buckets.insert(loadBucket(style.message())); + } else if (style.tag == 2) { // structure + layers.push_back(loadLayer(style.message())); + } else if (style.tag == 3) { // class + classes.insert(loadClass(style.message())); + } else { + style.skip(); + } + } + + cascade(); +} + +std::pair<std::string, BucketDescription> Style::loadBucket(pbf data) { + BucketDescription bucket; + std::string name; + + while (data.next()) { + if (data.tag == 1) { // name + name = data.string(); + } else if (data.tag == 2) { // type + bucket.type = (BucketType)data.varint(); + } else if (data.tag == 3) { // source_name + bucket.source_name = data.string(); + } else if (data.tag == 4) { // source_layer + bucket.source_layer = data.string(); + } else if (data.tag == 5) { // source_field + bucket.source_field = data.string(); + } else if (data.tag == 6) { // source_value + bucket.source_value.emplace_back(parseValue(data.message())); + } else if (data.tag == 7) { // cap + bucket.cap = (CapType)data.varint(); + } else if (data.tag == 8) { // join + bucket.join = (JoinType)data.varint(); + } else if (data.tag == 9) { // font + bucket.font = data.string(); + } else if (data.tag == 10) { // font_size + bucket.font_size = data.float32(); + } else { + data.skip(); + } + } + + return { name, bucket }; +} + +LayerDescription Style::loadLayer(pbf data) { + LayerDescription layer; + + while (data.next()) { + if (data.tag == 1) { // name + layer.name = data.string(); + } else if (data.tag == 2) { // bucket_name + layer.bucket_name = data.string(); + } else if (data.tag == 3) { // child_layer + layer.child_layer.emplace_back(loadLayer(data.message())); + } else { + data.skip(); + } + } + + return layer; +} + +std::pair<std::string, ClassDescription> Style::loadClass(pbf data) { + ClassDescription klass; + std::string name; + + while (data.next()) { + if (data.tag == 1) { // name + name = data.string(); + } else if (data.tag == 2) { // layer_style + klass.insert(loadLayerStyle(data.message())); + } else { + data.skip(); + } + } + + return { name, klass }; +} + +std::pair<std::string, LayerStyleDescription> Style::loadLayerStyle(pbf data) { + LayerStyleDescription layerStyle; + std::string name; + + while (data.next()) { + if (data.tag == 1) { // name + name = data.string(); + } else if (data.tag == 2) { // color + uint32_t rgba = data.fixed<uint32_t, 4>(); + layerStyle.color = {{ + (float)((rgba >> 24) & 0xFF) / 0xFF, + (float)((rgba >> 16) & 0xFF) / 0xFF, + (float)((rgba >> 8) & 0xFF) / 0xFF, + (float)((rgba >> 0) & 0xFF) / 0xFF + }}; + } else if (data.tag == 3) { // antialias + layerStyle.antialias = data.boolean(); + } else if (data.tag == 4) { // width + layerStyle.width = loadWidth(data.message()); + } else { + data.skip(); + } + } + + return { name, layerStyle }; } -void Style::load(pbf data) { +WidthDescription Style::loadWidth(pbf data) { + WidthDescription width; + + while (data.next()) { + if (data.tag == 1) { // scaling + width.scaling = data.string(); + } else if (data.tag == 2) { // value + // read a packed float32 + pbf floats = data.message(); + while (floats) { + width.value.push_back(floats.float32()); + } + } else { + data.skip(); + } + } + + return width; +} + + +void Style::cascade() { + reset(); + + // Recalculate style + // Basic cascading + for (const auto& class_pair : classes) { + const std::string& class_name = class_pair.first; + const ClassDescription& sheetClass = class_pair.second; + + // Not enabled + if (appliedClasses.find(class_name) == appliedClasses.end()) continue; + + for (const auto& layer_pair : sheetClass) { + const std::string& layer_name = layer_pair.first; + const LayerStyleDescription& layer = layer_pair.second; + // Find out what type this layer style is. + computed.fills[layer_name].enabled = true; + computed.fills[layer_name].antialiasing = layer.antialias; + computed.fills[layer_name].fill_color = layer.color; + computed.fills[layer_name].stroke_color = layer.color; + } + } } diff --git a/src/style/value.cpp b/src/style/value.cpp new file mode 100644 index 0000000000..8da66966fc --- /dev/null +++ b/src/style/value.cpp @@ -0,0 +1,25 @@ +#include <llmr/style/value.hpp> + +llmr::Value llmr::parseValue(pbf data) { + while (data.next()) { + if (data.tag == 1) { // string_value + return data.string(); + } else if (data.tag == 2) { // float_value + return data.float32(); + } else if (data.tag == 3) { // double_value + return data.float64(); + } else if (data.tag == 4) { // int_value + return data.varint<int64_t>(); + } else if (data.tag == 5) { // uint_value + return data.varint<uint64_t>(); + } else if (data.tag == 6) { // sint_value + return data.svarint<int64_t>(); + } else if (data.tag == 7) { // bool_value + return data.boolean(); + } else { + data.skip(); + } + } + + return false; +} |