summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2014-01-27 14:07:56 +0100
committerKonstantin Käfer <mail@kkaefer.com>2014-01-27 14:07:56 +0100
commite2dbcc95b5cf171e99e237513998d17a0c70f3ad (patch)
treebc7fc34b47402aaa9303c8d038d2158f1b7b7aa3 /src
parent2a6e4597e29d440e03416b0cf9d47da4eb2ff781 (diff)
downloadqtlocation-mapboxgl-e2dbcc95b5cf171e99e237513998d17a0c70f3ad.tar.gz
draw fills according to the style
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/map/map.cpp10
-rw-r--r--src/map/tile.cpp169
-rw-r--r--src/renderer/fill_bucket.cpp11
-rw-r--r--src/renderer/painter.cpp37
-rw-r--r--src/resources/style.cpp9
-rw-r--r--src/style/bucket_description.cpp19
-rw-r--r--src/style/layer_description.cpp12
-rw-r--r--src/style/style.cpp163
-rw-r--r--src/style/value.cpp25
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;
+}