cascade styles
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,27 +90,61 @@ 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(5 /* fill_color */, parseInt(color[1] + 'ff', 16));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -112,16 +153,28 @@ function createLayer(layer, name) {
|
||||
if (!color) {
|
||||
console.warn('invalid color');
|
||||
} else {
|
||||
pbf.writeTaggedUInt32(2 /* color */, parseInt(color[1] + 'ff', 16));
|
||||
pbf.writeTaggedUInt32(3 /* color */, parseInt(color[1] + 'ff', 16));
|
||||
}
|
||||
}
|
||||
|
||||
if ('antialias' in layer) {
|
||||
pbf.writeTaggedBoolean(3 /* antialias */, layer.antialias);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
11
bin/style.js
11
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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -8,25 +8,13 @@
|
||||
|
||||
namespace llmr {
|
||||
|
||||
|
||||
class WidthDescription {
|
||||
class ClassDescription {
|
||||
public:
|
||||
std::string scaling;
|
||||
std::vector<float> value;
|
||||
std::map<std::string, FillClass> fill;
|
||||
std::map<std::string, StrokeClass> stroke;
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 fixed32 color = 2; // rgba (=> rgb << 8 | 0xFF for opaque!)
|
||||
optional bool antialias = 3;
|
||||
optional width width = 4;
|
||||
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 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
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
25
src/style/properties.cpp
Normal file
25
src/style/properties.cpp
Normal file
@@ -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();
|
||||
}
|
||||
@@ -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) { // 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 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, layerStyle };
|
||||
return { name, fill };
|
||||
}
|
||||
|
||||
WidthDescription Style::loadWidth(pbf data) {
|
||||
WidthDescription width;
|
||||
|
||||
std::pair<std::string, StrokeClass> Style::parseStrokeClass(pbf data) {
|
||||
StrokeClass stroke;
|
||||
std::string name;
|
||||
|
||||
while (data.next()) {
|
||||
if (data.tag == 1) { // scaling
|
||||
width.scaling = data.string();
|
||||
if (data.tag == 1) { // name
|
||||
name = data.string();
|
||||
} 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
|
||||
stroke.width = parseProperty<float>(data.message());
|
||||
} else if (data.tag == 5) { // opacity
|
||||
stroke.offset = parseProperty<float>(data.message());
|
||||
} else {
|
||||
data.skip();
|
||||
}
|
||||
}
|
||||
|
||||
return { name, stroke };
|
||||
}
|
||||
|
||||
|
||||
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) { // 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;
|
||||
|
||||
// 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::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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user