diff options
29 files changed, 893 insertions, 125 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index de9d59ccf1..a51b47a1cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) project(llmr) +FIND_PACKAGE(Boost) set(VERSION_MAJOR "0") set(VERSION_MINOR "0") diff --git a/bin/build-style.js b/bin/build-style.js new file mode 100755 index 0000000000..227c164a28 --- /dev/null +++ b/bin/build-style.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node +'use strict'; + +var fs = require('fs'); + +var name = 'style'; +var data = fs.readFileSync('resources/style.pbf'); + +var length = data.length; + +var header = '// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.\n\n'; +header += '#ifndef LLMR_RESOURCE_' + name.toUpperCase() + '\n'; +header += '#define LLMR_RESOURCE_' + name.toUpperCase() + '\n'; +header += '\n'; +header += 'namespace llmr {\n'; +header += 'namespace resources {\n'; +header += '\n'; +header += 'extern const unsigned char ' + name + '[];\n'; +header += 'extern const unsigned long ' + name + '_size;\n'; +header += '\n'; +header += '}\n'; +header += '}\n'; +header += '\n'; +header += '#endif\n'; +fs.writeFileSync('include/llmr/resources/' + name + '.hpp', header); + +var code = '// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.\n'; +code += '#include <llmr/resources/' + name + '.hpp>\n'; +code += '\n'; +code += 'using namespace llmr;\n'; +code += '\n'; +code += 'const unsigned char resources::' + name + '[] = {\n'; +code += ' ' + Array.prototype.join.call(data, ', ') + '\n'; +code += '};\n'; +code += 'const unsigned long resources::' + name + '_size = sizeof(resources::' + name + ');\n'; + +fs.writeFileSync('src/resources/' + name + '.cpp', code); + diff --git a/include/llmr/map/layer.hpp b/include/llmr/map/layer.hpp index c6a10b9218..2e4db2997a 100644 --- a/include/llmr/map/layer.hpp +++ b/include/llmr/map/layer.hpp @@ -2,29 +2,33 @@ #define LLMR_MAP_LAYER #include <string> +#include <forward_list> namespace llmr { -class Bucket; -class Tile; - -class Layer { -public: - Layer(const std::string& name, const std::shared_ptr<Bucket>& bucket) - : name(name), - bucket(bucket) {} - -public: - std::string name; - std::shared_ptr<Bucket> bucket; - -private: - // Make noncopyable - Layer(const Layer&) = delete; - Layer(const Layer&&) = delete; - Layer& operator=(const Layer&) = delete; - Layer& operator=(const Layer && ) = delete; -}; +// class Bucket; + +// class Layer { +// public: +// Layer(const std::string& name, const std::shared_ptr<Bucket>& bucket) +// : name(name), +// bucket(bucket) {} + +// Layer(const std::string& name) +// : name(name) {} + +// public: +// std::string name; +// std::shared_ptr<Bucket> bucket; +// std::forward_list<Layer> child_layers; + +// private: +// // Make noncopyable +// // Layer(const Layer&) = delete; +// // Layer(const Layer&&) = delete; +// // Layer& operator=(const Layer&) = delete; +// // Layer& operator=(const Layer && ) = delete; +// }; } diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 512830713b..1007ca9871 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -25,7 +25,7 @@ public: Map &operator=(const Map&&) = delete; void setup(); - void loadStyle(const uint8_t *data, uint32_t bytes); + void loadStyle(const uint8_t *const data, uint32_t bytes); void loadSettings(); void resize(uint32_t width, uint32_t height, uint32_t fb_width, uint32_t fb_height); diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index 5cc8065994..86c56fe490 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -12,10 +12,15 @@ #include <mutex> #include <llmr/util/vec.hpp> #include <string> +#include <map> namespace llmr { struct pbf; +class Style; +class Bucket; +class LayerDescription; +class BucketDescription; class Tile { public: @@ -35,7 +40,7 @@ public: }; public: - Tile(ID id); + Tile(ID id, const Style& style); ~Tile(); // Make noncopyable @@ -47,9 +52,13 @@ public: // Other functions void setData(uint8_t *data, uint32_t bytes); bool parse(); - void parseLayer(const pbf layer); + void parseLayers(const pbf& tile, const std::vector<LayerDescription>& layers); + std::shared_ptr<Bucket> createBucket(const pbf& tile, const BucketDescription& bucket_desc); + // void parseLayer(const pbf layer); - std::shared_ptr<Bucket> createFillBucket(const pbf data); + // void (const std::vector<LayerDescription>& child_layers); + + std::shared_ptr<Bucket> createFillBucket(const pbf data, const BucketDescription& bucket_desc); void cancel(); @@ -61,12 +70,16 @@ public: public: const ID id; state state; - linevertexbuffer lineVertex; - debug_font_buffer debugFontVertex; - FillBuffer fillBuffer; + // Holds the actual geometries in this tile. + std::shared_ptr<linevertexbuffer> lineVertex; + std::shared_ptr<debug_font_buffer> debugFontVertex; + std::shared_ptr<FillBuffer> fillBuffer; - std::forward_list<Layer> layers; + // Holds the buckets of this tile. + // They contain the location offsets in the buffers stored above + std::map<std::string, std::shared_ptr<Bucket>> buckets; + // std::forward_list<Layer> layers; private: // Source data @@ -74,6 +87,8 @@ private: uint32_t bytes; std::mutex mtx; + + const Style& style; }; } diff --git a/include/llmr/renderer/fill_bucket.hpp b/include/llmr/renderer/fill_bucket.hpp index 71764af4fd..e90f51772c 100644 --- a/include/llmr/renderer/fill_bucket.hpp +++ b/include/llmr/renderer/fill_bucket.hpp @@ -13,7 +13,7 @@ struct pbf; class FillBucket : public Bucket { public: - FillBucket(FillBuffer& buffer); + FillBucket(const std::shared_ptr<FillBuffer>& buffer); virtual void render(Painter& painter, const std::string& layer_name); @@ -22,7 +22,7 @@ public: void drawVertices(int32_t attrib); private: - FillBuffer& buffer; + std::shared_ptr<FillBuffer> buffer; struct group { uint32_t vertex_length; diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 715098bd77..c2e7b8d614 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -12,6 +12,7 @@ namespace llmr { class Settings; class Transform; class Style; +class LayerDescription; class FillBucket; struct FillProperties; @@ -32,6 +33,7 @@ public: void clear(); void render(const std::shared_ptr<Tile>& tile); + void renderLayers(const std::shared_ptr<Tile>& tile, const std::vector<LayerDescription>& layers); void renderDebug(const std::shared_ptr<Tile>& tile); void renderBackground(); diff --git a/include/llmr/resources/style.hpp b/include/llmr/resources/style.hpp new file mode 100644 index 0000000000..684de3d546 --- /dev/null +++ b/include/llmr/resources/style.hpp @@ -0,0 +1,15 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#ifndef LLMR_RESOURCE_STYLE +#define LLMR_RESOURCE_STYLE + +namespace llmr { +namespace resources { + +extern const unsigned char style[]; +extern const unsigned long style_size; + +} +} + +#endif diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp new file mode 100644 index 0000000000..c8933d4190 --- /dev/null +++ b/include/llmr/style/bucket_description.hpp @@ -0,0 +1,51 @@ +#ifndef LLMR_STYLE_BUCKET_DESCRIPTION +#define LLMR_STYLE_BUCKET_DESCRIPTION + +#include <string> +#include <vector> + +#include "value.hpp" + +namespace llmr { + +enum class BucketType { + None = 0, + Fill = 1, + Line = 2, + Point = 3 +}; + +enum class CapType { + None = 0, + Round = 1, +}; + +enum class JoinType { + None = 0, + Butt = 1, + Bevel = 2 +}; + + +class BucketDescription { +public: + BucketType type = BucketType::None; + + // Specify what data to pull into this bucket + std::string source_name; + std::string source_layer; + std::string source_field; + std::vector<Value> source_value; + + // Specifies how the geometry for this bucket should be created + CapType cap = CapType::None; + JoinType join = JoinType::None; + std::string font; + float font_size = 0.0f; +}; + +std::ostream& operator<<(std::ostream&, const BucketDescription& bucket); + +} + +#endif diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp new file mode 100644 index 0000000000..a63dc8d041 --- /dev/null +++ b/include/llmr/style/class_description.hpp @@ -0,0 +1,32 @@ +#ifndef LLMR_STYLE_CLASS_DESCRIPTION +#define LLMR_STYLE_CLASS_DESCRIPTION + +#include <string> +#include <vector> +#include <map> +#include "properties.hpp" + +namespace llmr { + + +class WidthDescription { +public: + std::string scaling; + std::vector<float> value; +}; + + +class LayerStyleDescription { +public: + Color color = {{ 0, 0, 0, 0 }}; + bool antialias = false; + WidthDescription width; +}; + +typedef std::map<std::string, LayerStyleDescription> ClassDescription; + +std::ostream& operator<<(std::ostream&, const ClassDescription& layer); + +} + +#endif diff --git a/include/llmr/style/layer_description.hpp b/include/llmr/style/layer_description.hpp new file mode 100644 index 0000000000..405c884e52 --- /dev/null +++ b/include/llmr/style/layer_description.hpp @@ -0,0 +1,20 @@ +#ifndef LLMR_STYLE_LAYER_DESCRIPTION +#define LLMR_STYLE_LAYER_DESCRIPTION + +#include <string> +#include <vector> + +namespace llmr { + +class LayerDescription { +public: + std::string name; + std::string bucket_name; + std::vector<LayerDescription> child_layer; +}; + +std::ostream& operator<<(std::ostream&, const LayerDescription& layer); + +} + +#endif diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp new file mode 100644 index 0000000000..8eb0969c71 --- /dev/null +++ b/include/llmr/style/properties.hpp @@ -0,0 +1,42 @@ +#ifndef LLMR_STYLE_PROPERTIES +#define LLMR_STYLE_PROPERTIES + +#include <array> + +namespace llmr { + +typedef std::array<float, 4> Color; + +enum Winding { + EvenOdd = 1, + NonZero = 2 +}; + +// enum LineCap { +// Round = 1 +// }; + +// enum LineJoin { +// Butt = 1, +// Bevel = 2 +// }; + + +struct StrokeProperties { + bool enabled = false; + Color line_color = {{ 0, 0, 0, 1 }}; + float line_width = 1; +}; + +struct FillProperties { + bool enabled = false; + Winding winding = NonZero; + bool antialiasing = true; + Color fill_color = {{ 0, 0, 0, 1 }}; + Color stroke_color = {{ 0, 0, 0, 1 }}; + float stroke_width = 1; +}; + +} + +#endif diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp index 3324e01dc1..ee99ff2243 100644 --- a/include/llmr/style/style.hpp +++ b/include/llmr/style/style.hpp @@ -1,54 +1,52 @@ #ifndef LLMR_STYLE_STYLE #define LLMR_STYLE_STYLE -#include <array> #include <map> +#include <vector> +#include <set> #include "../util/pbf.hpp" -namespace llmr { - -typedef std::array<float, 4> Color; - -enum Winding { - EvenOdd = 1, - NonZero = 2 -}; +#include "value.hpp" +#include "properties.hpp" +#include "bucket_description.hpp" +#include "layer_description.hpp" +#include "class_description.hpp" -// enum LineCap { -// Round = 1 -// }; - -// enum LineJoin { -// Butt = 1, -// Bevel = 2 -// }; - - -struct StrokeProperties { - Color line_color = {{ 0, 0, 0, 1 }}; - float line_width = 1; -}; - -struct FillProperties { - Winding winding = NonZero; - bool antialiasing = true; - Color fill_color = {{ 0, 0, 0, 1 }}; - Color stroke_color = {{ 0, 0, 0, 1 }}; - float stroke_width = 1; -}; +namespace llmr { class Style { public: Style(); void reset(); - void load(pbf data); + void load(const uint8_t *const data, uint32_t bytes); + + void cascade(); + +private: + static std::pair<std::string, BucketDescription> loadBucket(pbf data); + static LayerDescription loadLayer(pbf data); + static std::pair<std::string, ClassDescription> loadClass(pbf data); + static std::pair<std::string, LayerStyleDescription> loadLayerStyle(pbf data); + static WidthDescription loadWidth(pbf data); public: - std::map<std::string, FillProperties> computedFills; - std::map<std::string, StrokeProperties> computedStrokes; + // This is static information parsed from the stylesheet. + std::map<std::string, BucketDescription> buckets; + std::vector<LayerDescription> layers; + std::map<std::string, ClassDescription> classes; + + + // This are applied settings. + std::set<std::string> appliedClasses; + struct { + std::map<std::string, FillProperties> fills; + std::map<std::string, StrokeProperties> strokes; + } computed; }; } + + #endif
\ No newline at end of file diff --git a/include/llmr/style/value.hpp b/include/llmr/style/value.hpp new file mode 100644 index 0000000000..f0d594b764 --- /dev/null +++ b/include/llmr/style/value.hpp @@ -0,0 +1,15 @@ +#ifndef LLMR_STYLE_VALUE +#define LLMR_STYLE_VALUE + +#include <boost/variant.hpp> +#include <llmr/util/pbf.hpp> + +namespace llmr { + +typedef boost::variant<std::string, double, int64_t, uint64_t, bool> Value; + +Value parseValue(pbf data); + +} + +#endif diff --git a/include/llmr/util/pbf.hpp b/include/llmr/util/pbf.hpp index 3fe851a7d4..fbf45e6a1f 100644 --- a/include/llmr/util/pbf.hpp +++ b/include/llmr/util/pbf.hpp @@ -31,9 +31,12 @@ struct pbf { inline bool next(); template <typename T = uint32_t> inline T varint(); template <typename T = uint32_t> inline T svarint(); - inline std::string string(); + + template <typename T = uint32_t, int bytes = 4> inline T fixed(); inline float float32(); inline double float64(); + + inline std::string string(); inline bool boolean(); inline pbf message(); @@ -99,25 +102,27 @@ T pbf::svarint() { return (n >> 1) ^ -(T)(n & 1); } -std::string pbf::string() { - uint32_t bytes = (uint32_t)varint(); - const char *string = (const char *)data; +template <typename T, int bytes> +T pbf::fixed() { skipBytes(bytes); - return std::string(string, bytes); + T result; + memcpy(&result, data - bytes, bytes); + return result; } float pbf::float32() { - skipBytes(4); - float result; - memcpy(&result, data - 4, 4); - return result; + return fixed<float, 4>(); } double pbf::float64() { - skipBytes(8); - double result; - memcpy(&result, data - 8, 8); - return result; + return fixed<double, 8>(); +} + +std::string pbf::string() { + uint32_t bytes = (uint32_t)varint(); + const char *string = (const char *)data; + skipBytes(bytes); + return std::string(string, bytes); } bool pbf::boolean() { diff --git a/macosx/CMakeLists.txt b/macosx/CMakeLists.txt index 2e41a7a5a5..6178f1c2a6 100644 --- a/macosx/CMakeLists.txt +++ b/macosx/CMakeLists.txt @@ -18,6 +18,7 @@ SET(macosx_HEADERS INCLUDE_DIRECTORIES( ../include ${GLFW_INCLUDE_DIRS} + ${Boost_INCLUDE_DIR} ) LINK_DIRECTORIES( @@ -55,4 +56,5 @@ TARGET_LINK_LIBRARIES(macosx ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY} ${GLFW_LIBRARIES} + ${Boost_LIBRARIES} ) diff --git a/proto/style.proto b/proto/style.proto index c8926c767c..d5f1c6c9f5 100644 --- a/proto/style.proto +++ b/proto/style.proto @@ -43,10 +43,10 @@ message bucket { optional float font_size = 10; } -message structure { +message layer { required string name = 1; optional string bucket_name = 2; - repeated structure child_layer = 3; + repeated layer child_layer = 3; } message width { @@ -54,7 +54,7 @@ message width { repeated float value = 2 [ packed = true ]; } -message layer { +message layer_style { required string layer_name = 1; optional fixed32 color = 2; // rgba (=> rgb << 8 | 0xFF for opaque!) optional bool antialias = 3; @@ -63,12 +63,12 @@ message layer { message class { required string name = 1; - repeated layer layer = 2; + repeated layer_style layer = 2; } // root level object message style { repeated bucket bucket = 1; - repeated structure structure = 2; + repeated layer layer = 2; repeated class class = 3; } diff --git a/proto/vector_tile.proto b/proto/vector_tile.proto new file mode 100644 index 0000000000..e982c1a018 --- /dev/null +++ b/proto/vector_tile.proto @@ -0,0 +1,153 @@ +// Protocol Version 1 + +package llmr.vector; + +option optimize_for = LITE_RUNTIME; + +enum geom_type { + Unknown = 0; + Point = 1; + LineString = 2; + Polygon = 3; +} + +// Variant type encoding +message value { + // Exactly one of these values may be present in a valid message + optional string string_value = 1; + optional float float_value = 2; + optional double double_value = 3; + optional int64 int_value = 4; + optional uint64 uint_value = 5; + optional sint64 sint_value = 6; + optional bool bool_value = 7; + + extensions 8 to max; +} + +message feature { + optional uint64 id = 1; + + // Tags of this feature. Even numbered values refer to the nth + // value in the keys list on the tile message, odd numbered + // values refer to the nth value in the values list on the tile + // message. + repeated uint32 tags = 2 [ packed = true ]; + + // The type of geometry stored in this feature. + optional geom_type type = 3 [ default = Unknown ]; + + // Contains a stream of commands and parameters (vertices). The + // repeat count is shifted to the left by 3 bits. This means + // that the command has 3 bits (0-15). The repeat count + // indicates how often this command is to be repeated. Defined + // commands are: + // - MoveTo: 1 (2 parameters follow) + // - LineTo: 2 (2 parameters follow) + // - ClosePath: 15 (no parameters follow) + // + // Ex.: MoveTo(3, 6), LineTo(8, 12), LineTo(20, 34), ClosePath + // Encoded as: [ 3 6 18 5 6 12 22 15 ] + // == command type 15 (ClosePath) + // ===== relative LineTo(+12, +22) == LineTo(20, 34) + // === relative LineTo(+5, +6) == LineTo(8, 12) + // == [00010 010] = command type 2 (LineTo), length 2 + // === relative MoveTo(+3, +6) + // = implicit command type 1 (MoveTo), length 1 + // Commands are encoded as uint32 varints, vertex parameters are + // encoded as sint32 varints (zigzag). Vertex parameters are + // also encoded as deltas to the previous position. The original + // position is (0,0) + repeated uint32 geometry = 4 [ packed = true ]; + + // A list of indices to the geometry array that specify a triangulation of + // this geometry. This must only exist if this feature is a polygon. + // These are the valid indices for the example above: + // 0 ==> (3/6) + // 1 ==> (8/12) + // 2 ==> (20/34) + // Indices beyond 2 are invalid, as the total number of vertices is 3. + repeated sint32 triangulation = 5 [ packed = true ]; + + // The total number of vertices encoded in the geometry field. This is can + // be deduced by manually iterating through the geometry field, but we can + // just as well store the number to avoid the overhead on parsing. + optional uint32 vertex_count = 6; +} + +// Stores a glyph with metrics and optional SDF bitmap information. +message glyph { + required uint32 id = 1; + + // A signed distance field of the glyph with a border of 3 pixels. + optional bytes bitmap = 2; + + // Glyph metrics. + required uint32 width = 3; + required uint32 height = 4; + required sint32 left = 5; + required sint32 top = 6; + required uint32 advance = 7; +} + +// Stores font face information and a list of glyphs. +message face { + required string family = 1; + required string style = 2; + repeated glyph glyphs = 5; +} + +// Stores the shaping information for the label with a given text +message label { + // The original value ID this shaping information is for. + required uint32 text = 1; + + // References the index of the font stack in the layer's fontstack array. + required uint32 stack = 2; + + // Parallel arrays of face ID, glyph ID and position. + repeated uint32 faces = 3 [packed = true]; + repeated uint32 glyphs = 4 [packed = true]; + repeated uint32 x = 5 [packed = true]; + repeated uint32 y = 6 [packed = true]; +} + +message layer { + // Any compliant implementation must first read the version + // number encoded in this message and choose the correct + // implementation for this version number before proceeding to + // decode other parts of this message. + required uint32 version = 15 [ default = 1 ]; + + required string name = 1; + + // The actual features in this tile. + repeated feature features = 2; + + // Dictionary encoding for keys + repeated string keys = 3; + + // Dictionary encoding for values + repeated value values = 4; + + // The bounding box in this tile spans from 0..4095 units + optional uint32 extent = 5 [ default = 4096 ]; + + // Total vertex count in this layer. + optional uint32 vertex_count = 6; + + // Shaping information for labels contained in this tile. + repeated string faces = 7; + repeated label labels = 8; + repeated string stacks = 9; + + extensions 16 to max; +} + +message tile { + repeated layer layers = 3; + + repeated face faces = 4; + + extensions 16 to 8191; +} diff --git a/resources/style.pbf b/resources/style.pbf Binary files differnew file mode 100644 index 0000000000..a916d4ed69 --- /dev/null +++ b/resources/style.pbf 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; +} |