summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/build-style.js12
-rwxr-xr-xbin/convert-style.js98
-rw-r--r--bin/style.js11
-rw-r--r--include/llmr/map/transform.hpp2
-rw-r--r--include/llmr/style/class_description.hpp18
-rw-r--r--include/llmr/style/properties.hpp69
-rw-r--r--include/llmr/style/style.hpp14
-rw-r--r--proto/style.proto44
-rw-r--r--resources/style.pbfbin947 -> 936 bytes
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/map/map.cpp3
-rw-r--r--src/map/transform.cpp4
-rw-r--r--src/renderer/painter.cpp16
-rw-r--r--src/resources/style.cpp60
-rw-r--r--src/style/properties.cpp25
-rw-r--r--src/style/style.cpp138
16 files changed, 405 insertions, 110 deletions
diff --git a/bin/build-style.js b/bin/build-style.js
index 227c164a28..26445ab26c 100755
--- a/bin/build-style.js
+++ b/bin/build-style.js
@@ -30,8 +30,16 @@ 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';
+
+
+for (var i = 0; i < data.length; i += 16) {
+ if (i > 0) {
+ code += ',\n';
+ }
+ var part = data.slice(i, i + 16);
+ code += ' ' + Array.prototype.join.call(part, ', ');
+}
+code += '\n};\n';
code += 'const unsigned long resources::' + name + '_size = sizeof(resources::' + name + ');\n';
fs.writeFileSync('src/resources/' + name + '.cpp', code);
diff --git a/bin/convert-style.js b/bin/convert-style.js
index 78cc17d5a5..be38458eab 100755
--- a/bin/convert-style.js
+++ b/bin/convert-style.js
@@ -27,6 +27,13 @@ var join_type = {
bevel: 2
};
+// enum
+var property_type = {
+ 'null': 1,
+ constant: 2,
+ stops: 3
+};
+
function createValue(value) {
var pbf = new Protobuf();
@@ -83,45 +90,91 @@ function createStructure(structure) {
return pbf;
}
-function createWidth(width) {
+// function createWidth(width) {
+// var pbf = new Protobuf();
+// var values = [];
+// if (Array.isArray(width)) {
+// pbf.writeTaggedString(1 /* scaling */, width[0]);
+// for (var i = 1; i < width.length; i++) {
+// if (width[0] === 'stops') {
+// values.push(width[i].z, width[i].val);
+// } else {
+// values.push(width[i]);
+// }
+// }
+// } else {
+// values.push(width);
+// }
+// pbf.writePackedFloats(2 /* value */, values);
+
+// return pbf;
+// }
+
+function createProperty(type, values) {
var pbf = new Protobuf();
- var values = [];
- if (Array.isArray(width)) {
- pbf.writeTaggedString(1 /* scaling */, width[0]);
- for (var i = 1; i < width.length; i++) {
- if (width[0] === 'stops') {
- values.push(width[i].z, width[i].val);
- } else {
- values.push(width[i]);
- }
- }
- } else {
- values.push(width);
- }
- pbf.writePackedFloats(2 /* value */, values);
+ pbf.writeTaggedVarint(1 /* function */, property_type[type]);
+ pbf.writePackedFloats(2 /* value */, values.map(function(value) { return +value; }));
return pbf;
}
-function createLayer(layer, name) {
+function createFillClass(layer, name) {
var pbf = new Protobuf();
pbf.writeTaggedString(1 /* layer_name */, name);
+ if ('antialias' in layer) {
+ pbf.writeMessage(4 /* antialias */, createProperty('constant', [layer.antialias]));
+ }
+
if ('color' in layer) {
var color = layer.color.match(/^#([0-9a-f]{6})$/i);
if (!color) {
console.warn('invalid color');
} else {
- pbf.writeTaggedUInt32(2 /* color */, parseInt(color[1] + 'ff', 16));
+ pbf.writeTaggedUInt32(5 /* fill_color */, parseInt(color[1] + 'ff', 16));
}
}
- if ('antialias' in layer) {
- pbf.writeTaggedBoolean(3 /* antialias */, layer.antialias);
+ if ('opacity' in layer) {
+ if (typeof layer.opacity == 'number') {
+ pbf.writeMessage(7 /* opacity */, createProperty('constant', [layer.opacity]));
+ }
+ }
+
+ return pbf;
+}
+
+function createLineClass(layer, name) {
+ var pbf = new Protobuf();
+ pbf.writeTaggedString(1 /* layer_name */, name);
+
+ if ('color' in layer) {
+ var color = layer.color.match(/^#([0-9a-f]{6})$/i);
+ if (!color) {
+ console.warn('invalid color');
+ } else {
+ pbf.writeTaggedUInt32(3 /* color */, parseInt(color[1] + 'ff', 16));
+ }
}
if ('width' in layer) {
- pbf.writeMessage(4 /* width */, createWidth(layer.width));
+ var values = [];
+ var width = layer.width;
+ var type = 'constant';
+ if (Array.isArray(width)) {
+ type = width[0];
+ for (var i = 1; i < width.length; i++) {
+ if (width[0] === 'stops') {
+ values.push(width[i].z, width[i].val);
+ } else {
+ values.push(width[i]);
+ }
+ }
+ } else {
+ values.push(width);
+ }
+
+ pbf.writeMessage(4 /* width */, createProperty(type, values));
}
return pbf;
@@ -132,7 +185,10 @@ function createClass(klass) {
var pbf = new Protobuf();
pbf.writeTaggedString(1 /* name */, klass.name);
for (var name in klass.layers) {
- pbf.writeMessage(2 /* layer */, createLayer(klass.layers[name], name));
+ switch (klass.layers[name].type) {
+ case 'fill': pbf.writeMessage(2 /* fill */, createFillClass(klass.layers[name], name)); break;
+ case 'line': pbf.writeMessage(3 /* line */, createLineClass(klass.layers[name], name)); break;
+ }
}
return pbf;
}
diff --git a/bin/style.js b/bin/style.js
index d218e125c1..d9f9f36614 100644
--- a/bin/style.js
+++ b/bin/style.js
@@ -75,21 +75,27 @@ module.exports = {
"name": "default",
"layers": {
"background": {
+ "type": "background",
"color": "#FFFFFF"
},
"park": {
+ "type": "fill",
"color": "#c8df9f",
"antialias": true
},
"wood": {
+ "type": "fill",
"color": "#33AA66",
- "antialias": true
+ "antialias": true,
+ "opacity": 0.1
},
"water": {
+ "type": "fill",
"color": "#73b6e6",
"antialias": true
},
"road_limited": {
+ "type": "line",
"color": "#BBBBBB",
"width": [
"stops",
@@ -98,6 +104,7 @@ module.exports = {
]
},
"road_regular": {
+ "type": "line",
"color": "#999999",
"width": [
"stops",
@@ -108,6 +115,7 @@ module.exports = {
],
},
"road_large": {
+ "type": "line",
"color": "#666666",
"width": [
"stops",
@@ -119,6 +127,7 @@ module.exports = {
],
},
"alcohol": {
+ "type": "marker",
"image": "alcohol-shop"
}
}
diff --git a/include/llmr/map/transform.hpp b/include/llmr/map/transform.hpp
index 78c06e2a18..b6578b0926 100644
--- a/include/llmr/map/transform.hpp
+++ b/include/llmr/map/transform.hpp
@@ -39,7 +39,7 @@ public:
// Getters
void matrixFor(float matrix[16], const vec3<int32_t>& id) const;
- int32_t getZoom() const;
+ float getZoom() const;
double getScale() const;
double getAngle() const;
void getLonLat(double& lon, double& lat) const;
diff --git a/include/llmr/style/class_description.hpp b/include/llmr/style/class_description.hpp
index a63dc8d041..3130f8d78f 100644
--- a/include/llmr/style/class_description.hpp
+++ b/include/llmr/style/class_description.hpp
@@ -8,24 +8,12 @@
namespace llmr {
-
-class WidthDescription {
-public:
- std::string scaling;
- std::vector<float> value;
-};
-
-
-class LayerStyleDescription {
+class ClassDescription {
public:
- Color color = {{ 0, 0, 0, 0 }};
- bool antialias = false;
- WidthDescription width;
+ std::map<std::string, FillClass> fill;
+ std::map<std::string, StrokeClass> stroke;
};
-typedef std::map<std::string, LayerStyleDescription> ClassDescription;
-
-std::ostream& operator<<(std::ostream&, const ClassDescription& layer);
}
diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp
index 8eb0969c71..71b3b3aa95 100644
--- a/include/llmr/style/properties.hpp
+++ b/include/llmr/style/properties.hpp
@@ -2,12 +2,13 @@
#define LLMR_STYLE_PROPERTIES
#include <array>
+#include <vector>
namespace llmr {
typedef std::array<float, 4> Color;
-enum Winding {
+enum class Winding {
EvenOdd = 1,
NonZero = 2
};
@@ -22,19 +23,71 @@ enum Winding {
// };
+enum class Property {
+ Null = 1,
+ Constant = 2,
+ Stops = 3
+};
+
+namespace functions {
+
+float null(float z, const std::vector<float>&);
+bool null(float z, const std::vector<bool>&);
+
+float constant(float z, const std::vector<float>& values);
+bool constant(float z, const std::vector<bool>& values);
+
+}
+
+
+template <typename T>
+struct FunctionProperty {
+ typedef T (*fn)(float z, const std::vector<T>& values);
+
+ fn function;
+ std::vector<T> values;
+
+ inline FunctionProperty() : function(&functions::null) {}
+ inline FunctionProperty(T value) : function(&functions::constant), values(1, value) {}
+ inline T operator()(float z) const { return function(z, values); }
+};
+
+
+// StrokeClass is the information we parse from the stylesheet
+struct StrokeClass {
+ FunctionProperty<bool> hidden;
+ FunctionProperty<float> width;
+ FunctionProperty<float> offset;
+ Color color = {{ 0, 0, 0, 1 }};
+};
+
+// StrokeProperties is the one we resolve this to.
struct StrokeProperties {
- bool enabled = false;
- Color line_color = {{ 0, 0, 0, 1 }};
- float line_width = 1;
+ bool hidden = false;
+ float width = 0;
+ float offset = 0;
+ Color color = {{ 0, 0, 0, 1 }};
+};
+
+
+
+
+struct FillClass {
+ FunctionProperty<bool> hidden;
+ Winding winding = Winding::NonZero;
+ FunctionProperty<bool> antialias = true;
+ Color fill_color = {{ 0, 0, 0, 1 }};
+ Color stroke_color = {{ 0, 0, 0, std::numeric_limits<float>::infinity() }};
+ FunctionProperty<float> opacity = 1;
};
struct FillProperties {
- bool enabled = false;
- Winding winding = NonZero;
- bool antialiasing = true;
+ bool hidden = false;
+ Winding winding = Winding::NonZero;
+ bool antialias = true;
Color fill_color = {{ 0, 0, 0, 1 }};
Color stroke_color = {{ 0, 0, 0, 1 }};
- float stroke_width = 1;
+ float opacity = 1.0;
};
}
diff --git a/include/llmr/style/style.hpp b/include/llmr/style/style.hpp
index ee99ff2243..a690a31e56 100644
--- a/include/llmr/style/style.hpp
+++ b/include/llmr/style/style.hpp
@@ -21,14 +21,16 @@ public:
void reset();
void load(const uint8_t *const data, uint32_t bytes);
- void cascade();
+ void cascade(float z);
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);
+ static std::pair<std::string, BucketDescription> parseBucket(pbf data);
+ static LayerDescription parseLayer(pbf data);
+ static std::pair<std::string, ClassDescription> parseClass(pbf data);
+ static std::pair<std::string, FillClass> parseFillClass(pbf data);
+ static std::pair<std::string, StrokeClass> parseStrokeClass(pbf data);
+ template <typename T> static FunctionProperty<T> parseProperty(pbf data);
+ static Color parseColor(pbf& data);
public:
// This is static information parsed from the stylesheet.
diff --git a/proto/style.proto b/proto/style.proto
index d5f1c6c9f5..5a977d799c 100644
--- a/proto/style.proto
+++ b/proto/style.proto
@@ -2,6 +2,8 @@ enum bucket_type {
fill = 1;
line = 2;
point = 3;
+
+ background = 15;
}
enum cap_type {
@@ -13,6 +15,17 @@ enum join_type {
bevel = 2;
}
+enum winding_type {
+ evenodd = 1;
+ nonzero = 2;
+}
+
+enum property_type {
+ null = 1;
+ constant = 2;
+ stops = 3;
+}
+
message value {
// Exactly one of these values may be present in a valid message
optional string string_value = 1;
@@ -49,21 +62,38 @@ message layer {
repeated layer child_layer = 3;
}
-message width {
- optional string scaling = 1;
+message property {
+ required property_type function = 1;
repeated float value = 2 [ packed = true ];
}
-message layer_style {
+message fill_style {
+ required string layer_name = 1;
+ optional property hidden = 2;
+ optional winding_type winding = 3 [ default = nonzero ];
+ optional property antialias = 4;
+ optional fixed32 fill_color = 5 [ default = 0x000000FF ]; // rgba (=> rgb << 8 | 0xFF for opaque!)
+ optional fixed32 stroke_color = 6; // if none is specified, no stroke will be painted
+ optional property opacity = 7; // values from 0..1
+ // TODO: translate x/y
+}
+
+message stroke_style {
required string layer_name = 1;
- optional fixed32 color = 2; // rgba (=> rgb << 8 | 0xFF for opaque!)
- optional bool antialias = 3;
- optional width width = 4;
+ optional property hidden = 2;
+ optional fixed32 color = 3 [ default = 0x000000FF ]; // rgba (=> rgb << 8 | 0xFF for opaque!)
+ optional property width = 4;
+ optional property offset = 5;
+ // line join + line cap are already defined in the
+ // TODO: dasharray
+ // TODO: image/icon
+ // TODO: translate x/y
}
message class {
required string name = 1;
- repeated layer_style layer = 2;
+ repeated fill_style fill = 2;
+ repeated stroke_style stroke = 3;
}
// root level object
diff --git a/resources/style.pbf b/resources/style.pbf
index a916d4ed69..90b496b70b 100644
--- a/resources/style.pbf
+++ b/resources/style.pbf
Binary files differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6a6e7e4a9b..14a3e88125 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -17,6 +17,7 @@ SET(llmr_SOURCES
style/value.cpp
style/bucket_description.cpp
style/layer_description.cpp
+ style/properties.cpp
util/animation.cpp
util/mat4.cpp
)
diff --git a/src/map/map.cpp b/src/map/map.cpp
index 31c4f1d81f..2b008c2ccf 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -39,6 +39,7 @@ void Map::loadSettings() {
transform.setAngle(settings.angle);
transform.setScale(settings.scale);
transform.setLonLat(settings.longitude, settings.latitude);
+ style.cascade(transform.getZoom());
update();
}
@@ -60,6 +61,7 @@ void Map::moveBy(double dx, double dy) {
void Map::scaleBy(double ds, double cx, double cy) {
transform.scaleBy(ds, cx, cy);
+ style.cascade(transform.getZoom());
update();
transform.getLonLat(settings.longitude, settings.latitude);
@@ -87,6 +89,7 @@ void Map::resetPosition() {
transform.setAngle(0);
transform.setLonLat(0, 0);
transform.setZoom(0);
+ style.cascade(transform.getZoom());
update();
transform.getLonLat(settings.longitude, settings.latitude);
diff --git a/src/map/transform.cpp b/src/map/transform.cpp
index cf0139cb3b..7f8d9939d1 100644
--- a/src/map/transform.cpp
+++ b/src/map/transform.cpp
@@ -164,8 +164,8 @@ void Transform::matrixFor(float matrix[16], const vec3<int32_t>& id) const {
mat4::translate(matrix, matrix, 0, 0, -1);
}
-int32_t Transform::getZoom() const {
- return floor(log(scale) / M_LN2);
+float Transform::getZoom() const {
+ return log(scale) / M_LN2;
}
double Transform::getScale() const {
diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp
index 139e434820..84e8f95946 100644
--- a/src/renderer/painter.cpp
+++ b/src/renderer/painter.cpp
@@ -204,7 +204,13 @@ void Painter::renderLayers(const std::shared_ptr<Tile>& tile, const std::vector<
void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) {
const FillProperties& properties = style.computed.fills[layer_name];
- if (!properties.enabled) return;
+ if (properties.hidden) return;
+
+ Color fill_color = properties.fill_color;
+ fill_color[0] *= properties.opacity;
+ fill_color[1] *= properties.opacity;
+ fill_color[2] *= properties.opacity;
+ fill_color[3] *= properties.opacity;
// Draw the stencil mask.
{
@@ -219,7 +225,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) {
// orientation, while all holes (see below) are in CW orientation.
glStencilFunc(GL_NOTEQUAL, 0x80, 0x80);
- if (properties.winding == EvenOdd) {
+ if (properties.winding == Winding::EvenOdd) {
// When we draw an even/odd winding fill, we just invert all the bits.
glStencilOp(GL_INVERT, GL_KEEP, GL_KEEP);
} else {
@@ -252,7 +258,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) {
// Because we're drawing top-to-bottom, and we update the stencil mask
// below, we have to draw the outline first (!)
- if (properties.antialiasing) {
+ if (properties.antialias) {
switchShader(outlineShader);
glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix);
glLineWidth(2);
@@ -270,7 +276,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) {
// the current shape, some pixels from the outline stroke overlapped
// the (non-antialiased) fill.
glStencilFunc(GL_EQUAL, 0x80, 0xBF);
- glUniform4fv(outlineShader->u_color, 1, properties.fill_color.data());
+ glUniform4fv(outlineShader->u_color, 1, fill_color.data());
}
// Draw the entire line
@@ -307,7 +313,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) {
// Draw filling rectangle.
switchShader(fillShader);
glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix);
- glUniform4fv(fillShader->u_color, 1, properties.fill_color.data());
+ glUniform4fv(fillShader->u_color, 1, fill_color.data());
}
// Only draw regions that we marked
diff --git a/src/resources/style.cpp b/src/resources/style.cpp
index 69c0b10655..57bad8636f 100644
--- a/src/resources/style.cpp
+++ b/src/resources/style.cpp
@@ -4,6 +4,64 @@
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
+ 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, 128, 2, 10, 7, 100, 101, 102, 97, 117, 108,
+ 116, 18, 21, 10, 4, 112, 97, 114, 107, 34, 8, 8, 2, 18, 4, 0,
+ 0, 128, 63, 45, 255, 159, 223, 200, 18, 31, 10, 4, 119, 111, 111, 100,
+ 34, 8, 8, 2, 18, 4, 0, 0, 128, 63, 45, 255, 102, 170, 51, 58,
+ 8, 8, 2, 18, 4, 205, 204, 204, 61, 18, 22, 10, 5, 119, 97, 116,
+ 101, 114, 34, 8, 8, 2, 18, 4, 0, 0, 128, 63, 45, 255, 230, 182,
+ 115, 26, 41, 10, 12, 114, 111, 97, 100, 95, 108, 105, 109, 105, 116, 101,
+ 100, 29, 255, 187, 187, 187, 34, 20, 8, 3, 18, 16, 0, 0, 0, 0,
+ 0, 0, 128, 63, 0, 0, 160, 65, 0, 0, 128, 63, 26, 57, 10, 12,
+ 114, 111, 97, 100, 95, 114, 101, 103, 117, 108, 97, 114, 29, 255, 153, 153,
+ 153, 34, 36, 8, 3, 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, 26, 63, 10, 10, 114, 111, 97, 100, 95,
+ 108, 97, 114, 103, 101, 29, 255, 102, 102, 102, 34, 44, 8, 3, 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
};
const unsigned long resources::style_size = sizeof(resources::style);
diff --git a/src/style/properties.cpp b/src/style/properties.cpp
new file mode 100644
index 0000000000..0ea3fbfeef
--- /dev/null
+++ b/src/style/properties.cpp
@@ -0,0 +1,25 @@
+#include <llmr/style/properties.hpp>
+
+
+#include <cassert>
+
+using namespace llmr;
+
+
+float functions::null(float z, const std::vector<float>&) {
+ return 0;
+}
+
+bool functions::null(float z, const std::vector<bool>&) {
+ return false;
+}
+
+float functions::constant(float z, const std::vector<float>& values) {
+ assert(values.size() == 1);
+ return values.front();
+}
+
+bool functions::constant(float z, const std::vector<bool>& values) {
+ assert(values.size() == 1);
+ return values.front();
+} \ No newline at end of file
diff --git a/src/style/style.cpp b/src/style/style.cpp
index 0acce7c35b..dc60d93a88 100644
--- a/src/style/style.cpp
+++ b/src/style/style.cpp
@@ -18,20 +18,18 @@ void Style::load(const uint8_t *const data, uint32_t bytes) {
while (style.next()) {
if (style.tag == 1) { // bucket
- buckets.insert(loadBucket(style.message()));
+ buckets.insert(parseBucket(style.message()));
} else if (style.tag == 2) { // structure
- layers.push_back(loadLayer(style.message()));
+ layers.push_back(parseLayer(style.message()));
} else if (style.tag == 3) { // class
- classes.insert(loadClass(style.message()));
+ classes.insert(parseClass(style.message()));
} else {
style.skip();
}
}
-
- cascade();
}
-std::pair<std::string, BucketDescription> Style::loadBucket(pbf data) {
+std::pair<std::string, BucketDescription> Style::parseBucket(pbf data) {
BucketDescription bucket;
std::string name;
@@ -64,7 +62,7 @@ std::pair<std::string, BucketDescription> Style::loadBucket(pbf data) {
return { name, bucket };
}
-LayerDescription Style::loadLayer(pbf data) {
+LayerDescription Style::parseLayer(pbf data) {
LayerDescription layer;
while (data.next()) {
@@ -73,7 +71,7 @@ LayerDescription Style::loadLayer(pbf data) {
} 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()));
+ layer.child_layer.emplace_back(parseLayer(data.message()));
} else {
data.skip();
}
@@ -83,15 +81,17 @@ LayerDescription Style::loadLayer(pbf data) {
}
-std::pair<std::string, ClassDescription> Style::loadClass(pbf data) {
+std::pair<std::string, ClassDescription> Style::parseClass(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 if (data.tag == 2) { // fill_style
+ klass.fill.insert(parseFillClass(data.message()));
+ } else if (data.tag == 3) { // stroke_style
+ klass.stroke.insert(parseStrokeClass(data.message()));
} else {
data.skip();
}
@@ -100,55 +100,96 @@ std::pair<std::string, ClassDescription> Style::loadClass(pbf data) {
return { name, klass };
}
-std::pair<std::string, LayerStyleDescription> Style::loadLayerStyle(pbf data) {
- LayerStyleDescription layerStyle;
+std::pair<std::string, FillClass> Style::parseFillClass(pbf data) {
+ FillClass fill;
+ std::string name;
+
+ while (data.next()) {
+ if (data.tag == 1) { // name
+ name = data.string();
+ } else if (data.tag == 2) { // hidden
+ fill.hidden = parseProperty<bool>(data.message());
+ } else if (data.tag == 3) { // winding
+ fill.winding = (Winding)data.varint();
+ } else if (data.tag == 4) { // antialias
+ fill.antialias = parseProperty<bool>(data.message());
+ } else if (data.tag == 5) { // fill_color
+ fill.fill_color = parseColor(data);
+ if (fill.stroke_color[3] == std::numeric_limits<float>::infinity()) {
+ fill.stroke_color = fill.fill_color;
+ }
+ } else if (data.tag == 6) { // stroke_color
+ fill.stroke_color = parseColor(data);
+ } else if (data.tag == 7) { // opacity
+ fill.opacity = parseProperty<float>(data.message());
+ } else {
+ data.skip();
+ }
+ }
+
+ return { name, fill };
+}
+
+
+std::pair<std::string, StrokeClass> Style::parseStrokeClass(pbf data) {
+ StrokeClass stroke;
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 == 2) { // hidden
+ stroke.hidden = parseProperty<bool>(data.message());
+ } else if (data.tag == 3) { // color
+ stroke.color = parseColor(data);
} else if (data.tag == 4) { // width
- layerStyle.width = loadWidth(data.message());
+ stroke.width = parseProperty<float>(data.message());
+ } else if (data.tag == 5) { // opacity
+ stroke.offset = parseProperty<float>(data.message());
} else {
data.skip();
}
}
- return { name, layerStyle };
+ return { name, stroke };
}
-WidthDescription Style::loadWidth(pbf data) {
- WidthDescription width;
+
+Color Style::parseColor(pbf& data) {
+ uint32_t rgba = data.fixed<uint32_t, 4>();
+ return {{
+ (float)((rgba >> 24) & 0xFF) / 0xFF,
+ (float)((rgba >> 16) & 0xFF) / 0xFF,
+ (float)((rgba >> 8) & 0xFF) / 0xFF,
+ (float)((rgba >> 0) & 0xFF) / 0xFF
+ }};
+}
+
+template <typename T> FunctionProperty<T> Style::parseProperty(pbf data) {
+ FunctionProperty<T> property;
while (data.next()) {
- if (data.tag == 1) { // scaling
- width.scaling = data.string();
+ if (data.tag == 1) { // function
+ switch((Property)data.varint()) {
+ case Property::Null: property.function = &functions::null; break;
+ case Property::Constant: property.function = &functions::constant; break;
+ default: property.function = &functions::null; break;
+ }
} else if (data.tag == 2) { // value
// read a packed float32
pbf floats = data.message();
while (floats) {
- width.value.push_back(floats.float32());
+ property.values.push_back(floats.float32());
}
} else {
data.skip();
}
}
- return width;
+ return property;
}
-
-void Style::cascade() {
+void Style::cascade(float z) {
reset();
// Recalculate style
@@ -160,15 +201,30 @@ void Style::cascade() {
// 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;
+ // Cascade fill classes
+ for (const auto& fill_pair : sheetClass.fill) {
+ const std::string& layer_name = fill_pair.first;
+ const llmr::FillClass& layer = fill_pair.second;
+
+ llmr::FillProperties& fill = computed.fills[layer_name];
+ fill.hidden = layer.hidden(z);
+ fill.winding = layer.winding;
+ fill.antialias = layer.antialias(z);
+ fill.fill_color = layer.fill_color;
+ fill.stroke_color = layer.stroke_color;
+ fill.opacity = layer.opacity(z);
+ }
+
+ // Cascade line classes
+ for (const auto& stroke_pair : sheetClass.stroke) {
+ const std::string& layer_name = stroke_pair.first;
+ const llmr::StrokeClass& layer = stroke_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;
+ llmr::StrokeProperties& stroke = computed.strokes[layer_name];
+ stroke.hidden = layer.hidden(z);
+ stroke.width = layer.width(z);
+ stroke.offset = layer.offset(z);
+ stroke.color = layer.color;
}
}
}