summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2014-01-28 17:17:00 +0100
committerKonstantin Käfer <mail@kkaefer.com>2014-01-28 17:17:00 +0100
commit918a68f5dd8ca768cc2dbd6c0ccf031f9f3bbf75 (patch)
tree2e61a0505e606809a4ebf2c805ce93f34f6efa38
parentf19d5c95dbc2784c53e47e869bef3bbde15c4c71 (diff)
downloadqtlocation-mapboxgl-918a68f5dd8ca768cc2dbd6c0ccf031f9f3bbf75.tar.gz
create line geometry
-rw-r--r--include/llmr/map/vector_tile.hpp22
-rw-r--r--include/llmr/renderer/fill_bucket.hpp5
-rw-r--r--include/llmr/renderer/line_bucket.hpp8
-rw-r--r--include/llmr/style/bucket_description.hpp7
-rw-r--r--include/llmr/style/properties.hpp3
-rw-r--r--include/llmr/util/math.hpp18
-rw-r--r--include/llmr/util/vec.hpp11
-rw-r--r--proto/style.proto3
-rw-r--r--src/map/tile.cpp4
-rw-r--r--src/map/vector_tile.cpp21
-rw-r--r--src/renderer/fill_bucket.cpp105
-rw-r--r--src/renderer/line_bucket.cpp239
-rw-r--r--src/renderer/painter.cpp2
-rw-r--r--src/style/style.cpp5
14 files changed, 375 insertions, 78 deletions
diff --git a/include/llmr/map/vector_tile.hpp b/include/llmr/map/vector_tile.hpp
index c0cfc9bfbc..14b497709f 100644
--- a/include/llmr/map/vector_tile.hpp
+++ b/include/llmr/map/vector_tile.hpp
@@ -14,6 +14,28 @@ class VectorTileLayer;
struct pbf;
+struct Coordinate {
+ Coordinate() : x(0), y(0) {}
+ Coordinate(int16_t x, int16_t y) : x(x), y(y) {}
+ int16_t x;
+ int16_t y;
+
+ inline bool operator==(const Coordinate& other) const {
+ return x == other.x && y == other.y;
+ }
+
+ inline operator bool() const {
+ return *this == null;
+ }
+
+ static const Coordinate null;
+};
+
+/*
+ * Allows iterating over the features of a VectorTileLayer using a
+ * BucketDescription as filter. Only features matching the descriptions will
+ * be returned (as pbf).
+ */
class FilteredVectorTileLayer {
public:
class iterator {
diff --git a/include/llmr/renderer/fill_bucket.hpp b/include/llmr/renderer/fill_bucket.hpp
index a64350a7ee..e4d813a95e 100644
--- a/include/llmr/renderer/fill_bucket.hpp
+++ b/include/llmr/renderer/fill_bucket.hpp
@@ -9,6 +9,8 @@ namespace llmr {
class Style;
class FillBuffer;
+class BucketDescription;
+struct Coordinate;
struct pbf;
class FillBucket : public Bucket {
@@ -17,7 +19,8 @@ public:
virtual void render(Painter& painter, const std::string& layer_name);
- void addGeometry(pbf& data);
+ void addGeometry(pbf& data, const BucketDescription& bucket_desc);
+ void addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc);
void drawElements(int32_t attrib);
void drawVertices(int32_t attrib);
diff --git a/include/llmr/renderer/line_bucket.hpp b/include/llmr/renderer/line_bucket.hpp
index 8feff69b3c..852f265e0d 100644
--- a/include/llmr/renderer/line_bucket.hpp
+++ b/include/llmr/renderer/line_bucket.hpp
@@ -9,6 +9,8 @@ namespace llmr {
class Style;
class LineBuffer;
+class BucketDescription;
+struct Coordinate;
struct pbf;
class LineBucket : public Bucket {
@@ -17,11 +19,13 @@ public:
virtual void render(Painter& painter, const std::string& layer_name);
- void addGeometry(pbf& data);
+ void addGeometry(pbf& data, const BucketDescription& bucket_desc);
+ void addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc);
private:
std::shared_ptr<LineBuffer> buffer;
-
+ uint32_t start;
+ uint32_t length;
};
}
diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp
index c8933d4190..fb72b7bb5a 100644
--- a/include/llmr/style/bucket_description.hpp
+++ b/include/llmr/style/bucket_description.hpp
@@ -18,12 +18,15 @@ enum class BucketType {
enum class CapType {
None = 0,
Round = 1,
+ Butt = 2,
+ Square = 3
};
enum class JoinType {
None = 0,
Butt = 1,
- Bevel = 2
+ Bevel = 2,
+ Round = 3
};
@@ -42,6 +45,8 @@ public:
JoinType join = JoinType::None;
std::string font;
float font_size = 0.0f;
+ float miter_limit = 2.0f;
+ float round_limit = 1.0f;
};
std::ostream& operator<<(std::ostream&, const BucketDescription& bucket);
diff --git a/include/llmr/style/properties.hpp b/include/llmr/style/properties.hpp
index 5b4f7d6275..66a1cebf4e 100644
--- a/include/llmr/style/properties.hpp
+++ b/include/llmr/style/properties.hpp
@@ -22,7 +22,6 @@ enum class Winding {
// Bevel = 2
// };
-
enum class Property {
Null = 1,
Constant = 2,
@@ -59,6 +58,7 @@ struct LineClass {
FunctionProperty<float> width;
FunctionProperty<float> offset;
Color color = {{ 0, 0, 0, 1 }};
+ FunctionProperty<float> opacity = 1;
};
// LineProperties is the one we resolve this to.
@@ -67,6 +67,7 @@ struct LineProperties {
float width = 0;
float offset = 0;
Color color = {{ 0, 0, 0, 1 }};
+ float opacity = 1.0;
};
diff --git a/include/llmr/util/math.hpp b/include/llmr/util/math.hpp
index 744a9d9473..8ea4a6b792 100644
--- a/include/llmr/util/math.hpp
+++ b/include/llmr/util/math.hpp
@@ -3,6 +3,8 @@
#include <cmath>
+#include "vec.hpp"
+
namespace llmr {
namespace util {
@@ -10,6 +12,22 @@ inline double angle_between(double ax, double ay, double bx, double by) {
return atan2((ax * by - ay * bx), ax * bx + ay * by);
}
+template <typename T, typename S1, typename S2>
+inline vec2<T> normal(const S1& a, const S2& b) {
+ T dx = b.x - a.x;
+ T dy = b.y - a.y;
+ T c = sqrt(dx * dx + dy * dy);
+ return { dx / c, dy / c };
+}
+
+template <typename T, typename S1, typename S2>
+inline T dist(const S1& a, const S2& b) {
+ T dx = b.x - a.x;
+ T dy = b.y - a.y;
+ T c = sqrt(dx * dx + dy * dy);
+ return c;
+};
+
}
}
diff --git a/include/llmr/util/vec.hpp b/include/llmr/util/vec.hpp
index 782573d7fd..8ef938faab 100644
--- a/include/llmr/util/vec.hpp
+++ b/include/llmr/util/vec.hpp
@@ -1,18 +1,29 @@
#ifndef llmr_util_vec2_
#define llmr_util_vec2_
+#include <limits>
+
namespace llmr {
template <typename T = double>
struct vec2 {
+ struct null {};
+
T x, y;
inline vec2() {}
+ inline vec2(null) : x(std::numeric_limits<T>::quiet_NaN()), y(std::numeric_limits<T>::quiet_NaN()) {}
+
inline vec2(const vec2& o) : x(o.x), y(o.y) {}
inline vec2(T x, T y) : x(x), y(y) {}
inline bool operator==(const vec2& rhs) const {
return x == rhs.x && y == rhs.y;
}
+
+ template<typename U = T, typename std::enable_if<std::numeric_limits<U>::has_quiet_NaN, int>::type = 0>
+ inline operator bool() const {
+ return isnan(x) || isnan(y);
+ }
};
template <typename T = double>
diff --git a/proto/style.proto b/proto/style.proto
index 5a977d799c..b2b103e6da 100644
--- a/proto/style.proto
+++ b/proto/style.proto
@@ -8,11 +8,14 @@ enum bucket_type {
enum cap_type {
round = 1;
+ butt = 2;
+ square = 3;
}
enum join_type {
butt = 1;
bevel = 2;
+ round = 3;
}
enum winding_type {
diff --git a/src/map/tile.cpp b/src/map/tile.cpp
index 71b01d15b8..cd4a9ba861 100644
--- a/src/map/tile.cpp
+++ b/src/map/tile.cpp
@@ -170,7 +170,7 @@ std::shared_ptr<Bucket> Tile::createFillBucket(const VectorTileLayer& layer, con
while (feature.next(4)) { // geometry
pbf geometry_pbf = feature.message();
if (geometry_pbf) {
- bucket->addGeometry(geometry_pbf);
+ bucket->addGeometry(geometry_pbf, bucket_desc);
}
}
}
@@ -186,7 +186,7 @@ std::shared_ptr<Bucket> Tile::createLineBucket(const VectorTileLayer& layer, con
while (feature.next(4)) { // geometry
pbf geometry_pbf = feature.message();
if (geometry_pbf) {
- bucket->addGeometry(geometry_pbf);
+ bucket->addGeometry(geometry_pbf, bucket_desc);
}
}
}
diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp
index e8ef7f05b4..df9043ac19 100644
--- a/src/map/vector_tile.cpp
+++ b/src/map/vector_tile.cpp
@@ -4,6 +4,11 @@
using namespace llmr;
+const Coordinate Coordinate::null(
+ std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::min()
+);
+
VectorTile::VectorTile() {}
VectorTile::VectorTile(pbf tile) {
@@ -151,19 +156,3 @@ bool FilteredVectorTileLayer::iterator::operator!=(const iterator& other) const
const pbf& FilteredVectorTileLayer::iterator:: operator*() const {
return feature;
}
-
-// class FilteredVectorTileLayer {
-// public:
-// class iterator {
-// public:
-// void operator++();
-// bool operator!=(const iterator& other) const;
-// const VectorTileFeature& operator*() const;
-
-// private:
-// iterator(const pbf& data);
-// VectorTileFeature feature;
-// pbf data;
-// };
-
-// };
diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp
index 07282a05ae..bd23ce6bdd 100644
--- a/src/renderer/fill_bucket.cpp
+++ b/src/renderer/fill_bucket.cpp
@@ -22,78 +22,77 @@ FillBucket::FillBucket(const std::shared_ptr<FillBuffer>& buffer)
length(0) {
}
-void FillBucket::addGeometry(pbf& geom) {
- std::vector<std::vector<std::pair<int16_t, int16_t>>> lines;
-
- {
- std::vector<std::pair<int16_t, int16_t>> line;
- Geometry::command cmd;
- int32_t x, y;
- Geometry geometry(geom);
- while ((cmd = geometry.next(x, y)) != Geometry::end) {
- if (cmd == Geometry::move_to) {
- if (line.size()) {
- lines.push_back(line);
- line.clear();
- }
+void FillBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
+ std::vector<Coordinate> line;
+ Geometry::command cmd;
+
+ Coordinate coord;
+ Geometry geometry(geom);
+ int32_t x, y;
+ while ((cmd = geometry.next(x, y)) != Geometry::end) {
+ if (cmd == Geometry::move_to) {
+ if (line.size()) {
+ addGeometry(line, bucket_desc);
+ line.clear();
}
- line.emplace_back(x, y);
- }
- if (line.size()) {
- lines.push_back(line);
}
+ line.emplace_back(x, y);
+ }
+ if (line.size()) {
+ addGeometry(line, bucket_desc);
}
+}
+void FillBucket::addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc) {
// 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();
-
- buffer.addDegenerate();
- for (const std::pair<int16_t, int16_t>& coord : line) {
- buffer.addCoordinate(coord.first, coord.second);
- }
+ uint32_t vertex_start = buffer.vertex_length();
- uint32_t vertex_end = buffer.vertex_length();
+ buffer.addDegenerate();
+ for (const Coordinate& coord : line) {
+ buffer.addCoordinate(coord.x, coord.y);
+ }
- if (vertex_end - vertex_start > 65535) {
- throw geometry_too_long_exception();
- }
+ uint32_t vertex_end = buffer.vertex_length();
- FillBucket& index = *this;
- if (!index.groups.size()) {
- index.groups.emplace_back();
- }
+ if (vertex_end - vertex_start > 65535) {
+ throw geometry_too_long_exception();
+ }
- uint32_t vertex_count = vertex_end - vertex_start;
- index.length += vertex_count;
+ FillBucket& index = *this;
+ if (!index.groups.size()) {
+ index.groups.emplace_back();
+ }
- if (index.groups.back().vertex_length + vertex_count > 65535) {
- // Move to a new group because the old one can't hold the geometry.
- index.groups.emplace_back();
- }
+ uint32_t vertex_count = vertex_end - vertex_start;
+ index.length += vertex_count;
- group& group = index.groups.back();
+ if (index.groups.back().vertex_length + vertex_count > 65535) {
+ // Move to a new group because the old one can't hold the geometry.
+ index.groups.emplace_back();
+ }
- // We're generating triangle fans, so we always start with the first
- // coordinate in this polygon.
- // The first valid index that is not a degenerate.
- uint16_t firstIndex = group.vertex_length + 1;
+ group& group = index.groups.back();
- assert(firstIndex + vertex_count - 1 < 65536);
+ // We're generating triangle fans, so we always start with the first
+ // coordinate in this polygon.
+ // The first valid index that is not a degenerate.
+ uint16_t firstIndex = group.vertex_length + 1;
- uint32_t elements_start = buffer.elements_length();
+ assert(firstIndex + vertex_count - 1 < 65536);
- for (uint32_t i = 2; i < vertex_count; i++) {
- buffer.addElements(firstIndex, firstIndex + i - 1, firstIndex + i);
- }
+ uint32_t elements_start = buffer.elements_length();
- uint32_t elements_end = buffer.elements_length();
- uint32_t elements_count = elements_end - elements_start;
- group.vertex_length += vertex_count;
- group.elements_length += elements_count;
+ for (uint32_t i = 2; i < vertex_count; i++) {
+ buffer.addElements(firstIndex, firstIndex + i - 1, firstIndex + i);
}
+
+ uint32_t elements_end = buffer.elements_length();
+ uint32_t elements_count = elements_end - elements_start;
+ group.vertex_length += vertex_count;
+ group.elements_length += elements_count;
+
}
void FillBucket::drawElements(int32_t attrib) {
diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp
index b4efa2f0b1..f3052242da 100644
--- a/src/renderer/line_bucket.cpp
+++ b/src/renderer/line_bucket.cpp
@@ -5,6 +5,7 @@
#include <llmr/renderer/painter.hpp>
#include <llmr/style/style.hpp>
+#include <llmr/util/math.hpp>
#include <llmr/platform/gl.hpp>
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
@@ -16,11 +17,245 @@ struct geometry_too_long_exception : std::exception {};
using namespace llmr;
LineBucket::LineBucket(const std::shared_ptr<LineBuffer>& buffer)
- : buffer(buffer) {
+ : buffer(buffer),
+ start(buffer->length()),
+ length(0) {
}
-void LineBucket::addGeometry(pbf& geom) {
+void LineBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
+ std::vector<Coordinate> line;
+ Geometry::command cmd;
+ Coordinate coord;
+ Geometry geometry(geom);
+ int32_t x, y;
+ while ((cmd = geometry.next(x, y)) != Geometry::end) {
+ if (cmd == Geometry::move_to) {
+ if (line.size()) {
+ addGeometry(line, bucket_desc);
+ line.clear();
+ }
+ }
+ line.emplace_back(x, y);
+ }
+ if (line.size()) {
+ addGeometry(line, bucket_desc);
+ }
+}
+
+void LineBucket::addGeometry(const std::vector<Coordinate>& vertices, const BucketDescription& bucket_desc) {
+ JoinType join = bucket_desc.join;
+ CapType cap = bucket_desc.cap;
+ float miterLimit = bucket_desc.miter_limit;
+ float roundLimit = bucket_desc.round_limit;
+
+ if (vertices.size() < 1) {
+ // alert('a line must have at least one vertex');
+ return;
+ }
+
+ // Point
+ if (vertices.size() == 1) {
+ Coordinate coord = vertices.front();
+ buffer->add(coord.x, coord.y, 1, 0, 0, 0);
+ return;
+ }
+
+ Coordinate firstVertex = vertices.front();
+ Coordinate lastVertex = vertices.back();
+ bool closed = firstVertex.x == lastVertex.x && firstVertex.y == lastVertex.y;
+
+ if (vertices.size() == 2 && closed) {
+ // alert('a line may not have coincident points');
+ return;
+ }
+
+ CapType beginCap = cap;
+ CapType endCap = closed ? CapType::Butt : cap;
+
+ Coordinate currentVertex = Coordinate::null,
+ prevVertex = Coordinate::null,
+ nextVertex = Coordinate::null;
+ vec2<double> prevNormal = vec2<double>::null(),
+ nextNormal = vec2<double>::null();
+
+ int8_t flip = 1;
+ double distance = 0;
+
+ if (closed) {
+ currentVertex = vertices[vertices.size() - 2];
+ nextNormal = util::normal<double>(currentVertex, lastVertex);
+ }
+
+ // Start all lines with a degenerate vertex
+ buffer->addDegenerate();
+
+ for (size_t i = 0; i < vertices.size(); i++) {
+ if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y };
+ if (currentVertex) prevVertex = currentVertex;
+
+ currentVertex = vertices[i];
+
+ if (prevVertex) distance += util::dist<double>(currentVertex, prevVertex);
+
+ // Find the next vertex.
+ if (i + 1 < vertices.size()) {
+ nextVertex = vertices[i + 1];
+ } else {
+ nextVertex = Coordinate::null;
+ }
+
+ bool segment = false;
+
+ if (closed && i >= 2 && (i + 1 < vertices.size())) {
+ segment = true;
+ }
+
+ // If the line is closed, we treat the last vertex like the first vertex.
+ if (!nextVertex && closed) {
+ nextVertex = vertices[1];
+ }
+
+
+ if (nextVertex) {
+ // if two consecutive vertices exist, skip one
+ if (currentVertex.x == nextVertex.x && currentVertex.y == nextVertex.y) continue;
+ }
+
+ // Calculate the normal towards the next vertex in this line. In case
+ // there is no next vertex, pretend that the line is continuing straight,
+ // meaning that we are just reversing the previous normal
+ if (nextVertex) {
+ nextNormal = util::normal<double>(currentVertex, nextVertex);
+ } else {
+ nextNormal = { -prevNormal.x, -prevNormal.y };
+ }
+
+ // If we still don't have a previous normal, this is the beginning of a
+ // non-closed line, so we're doing a straight "join".
+ if (!prevNormal) {
+ prevNormal = { -nextNormal.x, -nextNormal.y };
+ }
+
+ // Determine the normal of the join extrusion. It is the angle bisector
+ // of the segments between the previous line and the next line.
+ vec2<double> joinNormal = {
+ prevNormal.x + nextNormal.x,
+ prevNormal.y + nextNormal.y
+ };
+
+ // Cross product yields 0..1 depending on whether they are parallel
+ // or perpendicular.
+ double joinAngularity = nextNormal.x * joinNormal.y - nextNormal.y * joinNormal.x;
+ joinNormal.x /= joinAngularity;
+ joinNormal.y /= joinAngularity;
+ double roundness = fmax(abs(joinNormal.x), abs(joinNormal.y));
+
+
+ bool roundJoin = false;
+ // Determine whether we should actually draw a round/bevelled/butt line join. It looks
+ // better if we do, but we can get away with drawing a mitered join for
+ // joins that have a very small angle. For this, we have the "roundLimit"
+ // parameter. We do this to reduce the number of vertices we have to
+ // write into the line vertex buffer. Note that joinAngularity may be 0,
+ // so the roundness grows to infinity. This is intended.
+ if ((join == JoinType::Round || join == JoinType::Bevel || join == JoinType::Butt) && roundness > roundLimit) {
+ roundJoin = true;
+ }
+
+ // Close up the previous line for a round join
+ if (roundJoin && prevVertex && nextVertex) {
+ // Add first vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ flip * prevNormal.y, -flip * prevNormal.x, // extrude normal
+ 0, 0, distance); // texture normal
+
+ // Add second vertex.
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ -flip * prevNormal.y, flip * prevNormal.x, // extrude normal
+ 0, 1, distance); // texture normal
+
+ // Degenerate triangle
+ if (join == JoinType::Round || join == JoinType::Butt) {
+ buffer->addDegenerate();
+ }
+
+ if (join == JoinType::Round) prevVertex = Coordinate::null;
+
+ prevNormal = { -nextNormal.x, -nextNormal.y };
+ flip = 1;
+ }
+
+ // Add a cap.
+ if (!prevVertex && (beginCap == CapType::Round || beginCap == CapType::Square || (roundJoin && join == JoinType::Round))) {
+ int8_t tex = beginCap == CapType::Round || roundJoin ? 1 : 0;
+
+ // Add first vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.y), // extrude normal
+ tex, 0, distance); // texture normal
+
+ // Add second vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.y), // extrude normal
+ tex, 1, distance); // texture normal
+ }
+
+ if (roundJoin) {
+ // ROUND JOIN
+ // Add first vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ -flip * nextNormal.y, flip * nextNormal.x, // extrude normal
+ 0, 0, distance); // texture normal
+
+ // Add second vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ flip * nextNormal.y, -flip * nextNormal.x, // extrude normal
+ 0, 1, distance); // texture normal
+ } else if ((nextVertex || endCap != CapType::Square) && (prevVertex || beginCap != CapType::Square)) {
+ // MITER JOIN
+ if (fabs(joinAngularity) < 0.01) {
+ // The two normals are almost parallel.
+ joinNormal.x = -nextNormal.y;
+ joinNormal.y = nextNormal.x;
+ } else if (roundness > miterLimit) {
+ // If the miter grows too large, flip the direction to make a
+ // bevel join.
+ joinNormal.x = (prevNormal.x - nextNormal.x) / joinAngularity;
+ joinNormal.y = (prevNormal.y - nextNormal.y) / joinAngularity;
+ flip = -flip;
+ }
+
+ // Add first vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ flip * joinNormal.x, flip * joinNormal.y, // extrude normal
+ 0, 0, distance); // texture normal
+
+ // Add second vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ -flip * joinNormal.x, -flip * joinNormal.y, // extrude normal
+ 0, 1, distance); // texture normal
+ }
+
+ // Add the end cap, but only if this vertex is distinct from the begin
+ // vertex.
+ if (!nextVertex && (endCap == CapType::Round || endCap == CapType::Square)) {
+ int8_t capTex = endCap == CapType::Round ? 1 : 0;
+
+ // Add first vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ nextNormal.x - flip * nextNormal.y, flip * nextNormal.x + nextNormal.y, // extrude normal
+ capTex, 0, distance); // texture normal
+
+ // Add second vertex
+ buffer->add(currentVertex.x, currentVertex.y, // vertex pos
+ nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal
+ capTex, 1, distance); // texture normal
+ }
+ }
+
+ // Update the length.
+ length = buffer->length() - start;
}
void LineBucket::render(Painter& painter, const std::string& layer_name) {
diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp
index 3323ddcbb9..2e391b031e 100644
--- a/src/renderer/painter.cpp
+++ b/src/renderer/painter.cpp
@@ -330,6 +330,8 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name) {
void Painter::renderLine(LineBucket& bucket, const std::string& layer_name) {
const LineProperties& properties = style.computed.lines[layer_name];
+
+ // TODO
}
void Painter::renderDebug(const Tile::Ptr& tile) {
diff --git a/src/style/style.cpp b/src/style/style.cpp
index 6e468962b1..a3a73c2526 100644
--- a/src/style/style.cpp
+++ b/src/style/style.cpp
@@ -206,6 +206,8 @@ void Style::cascade(float z) {
const std::string& layer_name = fill_pair.first;
const llmr::FillClass& layer = fill_pair.second;
+ // TODO: This should be restricted to fill styles that have actual
+ // values so as to not override with default values.
llmr::FillProperties& fill = computed.fills[layer_name];
fill.hidden = layer.hidden(z);
fill.winding = layer.winding;
@@ -220,11 +222,14 @@ void Style::cascade(float z) {
const std::string& layer_name = line_pair.first;
const llmr::LineClass& layer = line_pair.second;
+ // TODO: This should be restricted to fill styles that have actual
+ // values so as to not override with default values.
llmr::LineProperties& stroke = computed.lines[layer_name];
stroke.hidden = layer.hidden(z);
stroke.width = layer.width(z);
stroke.offset = layer.offset(z);
stroke.color = layer.color;
+ stroke.opacity = layer.opacity(z);
}
}
}