draw fills according to the style
This commit is contained in:
@@ -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")
|
||||
|
||||
38
bin/build-style.js
Executable file
38
bin/build-style.js
Executable file
@@ -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);
|
||||
|
||||
@@ -2,29 +2,33 @@
|
||||
#define LLMR_MAP_LAYER
|
||||
|
||||
#include <string>
|
||||
#include <forward_list>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
class Bucket;
|
||||
class Tile;
|
||||
// class Bucket;
|
||||
|
||||
class Layer {
|
||||
public:
|
||||
Layer(const std::string& name, const std::shared_ptr<Bucket>& bucket)
|
||||
: name(name),
|
||||
bucket(bucket) {}
|
||||
// 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;
|
||||
// Layer(const std::string& name)
|
||||
// : name(name) {}
|
||||
|
||||
private:
|
||||
// Make noncopyable
|
||||
Layer(const Layer&) = delete;
|
||||
Layer(const Layer&&) = delete;
|
||||
Layer& operator=(const Layer&) = delete;
|
||||
Layer& operator=(const Layer && ) = delete;
|
||||
};
|
||||
// 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;
|
||||
// };
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
15
include/llmr/resources/style.hpp
Normal file
15
include/llmr/resources/style.hpp
Normal file
@@ -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
|
||||
51
include/llmr/style/bucket_description.hpp
Normal file
51
include/llmr/style/bucket_description.hpp
Normal file
@@ -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
|
||||
32
include/llmr/style/class_description.hpp
Normal file
32
include/llmr/style/class_description.hpp
Normal file
@@ -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
|
||||
20
include/llmr/style/layer_description.hpp
Normal file
20
include/llmr/style/layer_description.hpp
Normal file
@@ -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
|
||||
42
include/llmr/style/properties.hpp
Normal file
42
include/llmr/style/properties.hpp
Normal file
@@ -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
|
||||
@@ -1,54 +1,52 @@
|
||||
#ifndef LLMR_STYLE_STYLE
|
||||
#define LLMR_STYLE_STYLE
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "../util/pbf.hpp"
|
||||
|
||||
#include "value.hpp"
|
||||
#include "properties.hpp"
|
||||
#include "bucket_description.hpp"
|
||||
#include "layer_description.hpp"
|
||||
#include "class_description.hpp"
|
||||
|
||||
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 {
|
||||
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;
|
||||
};
|
||||
|
||||
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
|
||||
15
include/llmr/style/value.hpp
Normal file
15
include/llmr/style/value.hpp
Normal file
@@ -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
|
||||
@@ -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,6 +102,22 @@ T pbf::svarint() {
|
||||
return (n >> 1) ^ -(T)(n & 1);
|
||||
}
|
||||
|
||||
template <typename T, int bytes>
|
||||
T pbf::fixed() {
|
||||
skipBytes(bytes);
|
||||
T result;
|
||||
memcpy(&result, data - bytes, bytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
float pbf::float32() {
|
||||
return fixed<float, 4>();
|
||||
}
|
||||
|
||||
double pbf::float64() {
|
||||
return fixed<double, 8>();
|
||||
}
|
||||
|
||||
std::string pbf::string() {
|
||||
uint32_t bytes = (uint32_t)varint();
|
||||
const char *string = (const char *)data;
|
||||
@@ -106,20 +125,6 @@ std::string pbf::string() {
|
||||
return std::string(string, bytes);
|
||||
}
|
||||
|
||||
float pbf::float32() {
|
||||
skipBytes(4);
|
||||
float result;
|
||||
memcpy(&result, data - 4, 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
double pbf::float64() {
|
||||
skipBytes(8);
|
||||
double result;
|
||||
memcpy(&result, data - 8, 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool pbf::boolean() {
|
||||
skipBytes(1);
|
||||
return *(bool *)(data - 1);
|
||||
|
||||
@@ -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}
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
153
proto/vector_tile.proto
Normal file
153
proto/vector_tile.proto
Normal file
@@ -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;
|
||||
}
|
||||
BIN
resources/style.pbf
Normal file
BIN
resources/style.pbf
Normal file
Binary file not shown.
@@ -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}
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
|
||||
171
src/map/tile.cpp
171
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,20 +114,67 @@ 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 {
|
||||
layer.skip();
|
||||
// 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 {
|
||||
tile.skip();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum geom_type {
|
||||
Unknown = 0,
|
||||
Point = 1,
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
9
src/resources/style.cpp
Normal file
9
src/resources/style.cpp
Normal file
@@ -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);
|
||||
19
src/style/bucket_description.cpp
Normal file
19
src/style/bucket_description.cpp
Normal file
@@ -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;
|
||||
}
|
||||
12
src/style/layer_description.cpp
Normal file
12
src/style/layer_description.cpp
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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(pbf data) {
|
||||
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 };
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
25
src/style/value.cpp
Normal file
25
src/style/value.cpp
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user