make line drawing work

This commit is contained in:
Konstantin Käfer
2014-01-29 11:12:09 +01:00
parent e359d697fb
commit 04e16cf2ca
11 changed files with 127 additions and 83 deletions

View File

@@ -2,6 +2,7 @@
#define LLMR_RENDERER_FILLBUCKET
#include "bucket.hpp"
#include <llmr/style/bucket_description.hpp>
#include <vector>
@@ -15,15 +16,19 @@ struct pbf;
class FillBucket : public Bucket {
public:
FillBucket(const std::shared_ptr<FillBuffer>& buffer);
FillBucket(const std::shared_ptr<FillBuffer>& buffer, const BucketDescription& bucket_desc);
virtual void render(Painter& painter, const std::string& layer_name);
void addGeometry(pbf& data, const BucketDescription& bucket_desc);
void addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc);
void addGeometry(pbf& data);
void addGeometry(const std::vector<Coordinate>& line);
uint32_t size() const;
void drawElements(int32_t attrib);
void drawVertices(int32_t attrib);
public:
const BucketGeometryDescription geom_desc;
private:
std::shared_ptr<FillBuffer> buffer;

View File

@@ -15,18 +15,24 @@ struct pbf;
class LineBucket : public Bucket {
public:
LineBucket(const std::shared_ptr<LineBuffer>& buffer);
LineBucket(const std::shared_ptr<LineBuffer>& buffer, const BucketDescription& bucket_desc);
virtual void render(Painter& painter, const std::string& layer_name);
void addGeometry(pbf& data, const BucketDescription& bucket_desc);
void addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc);
void addGeometry(pbf& data);
void addGeometry(const std::vector<Coordinate>& line);
uint32_t size() const;
void bind();
char *vertexOffset() const;
public:
const BucketGeometryDescription geometry;
private:
std::shared_ptr<LineBuffer> buffer;
uint32_t start;
uint32_t length;
JoinType join;
};
}

View File

@@ -30,6 +30,16 @@ enum class JoinType {
};
class BucketGeometryDescription {
public:
CapType cap = CapType::None;
JoinType join = JoinType::None;
std::string font;
float font_size = 0.0f;
float miter_limit = 2.0f;
float round_limit = 1.0f;
};
class BucketDescription {
public:
BucketType type = BucketType::None;
@@ -41,12 +51,7 @@ public:
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;
float miter_limit = 2.0f;
float round_limit = 1.0f;
BucketGeometryDescription geometry;
};
std::ostream& operator<<(std::ostream&, const BucketDescription& bucket);

View File

@@ -20,10 +20,15 @@ void LineBuffer::add(int16_t x, int16_t y, float ex, float ey, int8_t tx, int8_t
array.push_back((x * 2) | tx);
array.push_back((y * 2) | ty);
array.push_back(linesofar);
array.push_back(
((int16_t)round(extrudeScale * ex) << 8) |
((int16_t)round(extrudeScale * ey) & 0xFF)
);
int16_t extrude = 0;
int8_t *extrude_x = ((int8_t *)&extrude) + 0;
int8_t *extrude_y = ((int8_t *)&extrude) + 1;
*extrude_x = round(extrudeScale * ex);
*extrude_y = round(extrudeScale * ey);
array.push_back(extrude);
if (!dirty) dirty = true;
};

View File

@@ -163,14 +163,14 @@ std::shared_ptr<Bucket> Tile::createBucket(const BucketDescription& bucket_desc)
}
std::shared_ptr<Bucket> Tile::createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) {
std::shared_ptr<FillBucket> bucket = std::make_shared<FillBucket>(fillBuffer);
std::shared_ptr<FillBucket> bucket = std::make_shared<FillBucket>(fillBuffer, bucket_desc);
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
for (pbf feature : filtered_layer) {
while (feature.next(4)) { // geometry
pbf geometry_pbf = feature.message();
if (geometry_pbf) {
bucket->addGeometry(geometry_pbf, bucket_desc);
bucket->addGeometry(geometry_pbf);
}
}
}
@@ -179,14 +179,14 @@ std::shared_ptr<Bucket> Tile::createFillBucket(const VectorTileLayer& layer, con
}
std::shared_ptr<Bucket> Tile::createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) {
std::shared_ptr<LineBucket> bucket = std::make_shared<LineBucket>(lineBuffer);
std::shared_ptr<LineBucket> bucket = std::make_shared<LineBucket>(lineBuffer, bucket_desc);
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
for (pbf feature : filtered_layer) {
while (feature.next(4)) { // geometry
pbf geometry_pbf = feature.message();
if (geometry_pbf) {
bucket->addGeometry(geometry_pbf, bucket_desc);
bucket->addGeometry(geometry_pbf);
}
}
}

View File

@@ -15,14 +15,15 @@ struct geometry_too_long_exception : std::exception {};
using namespace llmr;
FillBucket::FillBucket(const std::shared_ptr<FillBuffer>& buffer)
: buffer(buffer),
FillBucket::FillBucket(const std::shared_ptr<FillBuffer>& buffer, const BucketDescription& bucket_desc)
: geom_desc(bucket_desc.geometry),
buffer(buffer),
vertex_start(buffer->vertex_length()),
elements_start(buffer->elements_length()),
length(0) {
}
void FillBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
void FillBucket::addGeometry(pbf& geom) {
std::vector<Coordinate> line;
Geometry::command cmd;
@@ -32,18 +33,18 @@ void FillBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
while ((cmd = geometry.next(x, y)) != Geometry::end) {
if (cmd == Geometry::move_to) {
if (line.size()) {
addGeometry(line, bucket_desc);
addGeometry(line);
line.clear();
}
}
line.emplace_back(x, y);
}
if (line.size()) {
addGeometry(line, bucket_desc);
addGeometry(line);
}
}
void FillBucket::addGeometry(const std::vector<Coordinate>& line, const BucketDescription& bucket_desc) {
void FillBucket::addGeometry(const std::vector<Coordinate>& line) {
// Alias this.
FillBuffer& buffer = *this->buffer;
@@ -96,8 +97,8 @@ void FillBucket::addGeometry(const std::vector<Coordinate>& line, const BucketDe
}
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));
char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t));
char *elements_index = BUFFER_OFFSET(elements_start * 3 * sizeof(int16_t));
buffer->bind();
for (const auto& group : groups) {
glVertexAttribPointer(attrib, 2, GL_SHORT, GL_FALSE, 0, vertex_index);
@@ -109,7 +110,8 @@ void FillBucket::drawElements(int32_t attrib) {
void FillBucket::drawVertices(int32_t attrib) {
// Draw the entire line
char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(uint16_t));
char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t));
buffer->bind();
glVertexAttribPointer(attrib, 2, GL_SHORT, GL_FALSE, 0, vertex_index);
glDrawArrays(GL_LINE_STRIP, 0, length);
}
@@ -117,3 +119,8 @@ void FillBucket::drawVertices(int32_t attrib) {
void FillBucket::render(Painter& painter, const std::string& layer_name) {
painter.renderFill(*this, layer_name);
}
uint32_t FillBucket::size() const {
return length;
}

View File

@@ -16,15 +16,14 @@ struct geometry_too_long_exception : std::exception {};
using namespace llmr;
LineBucket::LineBucket(const std::shared_ptr<LineBuffer>& buffer)
: buffer(buffer),
LineBucket::LineBucket(const std::shared_ptr<LineBuffer>& buffer, const BucketDescription& bucket_desc)
: geometry(bucket_desc.geometry),
buffer(buffer),
start(buffer->length()),
length(0) {
}
void LineBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
join = bucket_desc.join;
void LineBucket::addGeometry(pbf& geom) {
std::vector<Coordinate> line;
Geometry::command cmd;
@@ -34,22 +33,22 @@ void LineBucket::addGeometry(pbf& geom, const BucketDescription& bucket_desc) {
while ((cmd = geometry.next(x, y)) != Geometry::end) {
if (cmd == Geometry::move_to) {
if (line.size()) {
addGeometry(line, bucket_desc);
addGeometry(line);
line.clear();
}
}
line.emplace_back(x, y);
}
if (line.size()) {
addGeometry(line, bucket_desc);
addGeometry(line);
}
}
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;
void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
const JoinType join = geometry.join;
const CapType cap = geometry.cap;
const float miterLimit = geometry.miter_limit;
const float roundLimit = geometry.round_limit;
if (vertices.size() < 1) {
// alert('a line must have at least one vertex');
@@ -169,13 +168,13 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices, const Buck
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
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
-flip * prevNormal.y, flip * prevNormal.x, // extrude normal
0, 1, distance); // texture normal
// Degenerate triangle
if (join == JoinType::Round || join == JoinType::Butt) {
@@ -194,26 +193,26 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices, const Buck
// 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
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
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
-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
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) {
@@ -230,13 +229,13 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices, const Buck
// Add first vertex
buffer->add(currentVertex.x, currentVertex.y, // vertex pos
flip * joinNormal.x, flip * joinNormal.y, // extrude normal
0, 0, distance); // texture normal
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
-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
@@ -246,13 +245,13 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices, const Buck
// 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
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
nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal
capTex, 1, distance); // texture normal
}
}
@@ -263,3 +262,15 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices, const Buck
void LineBucket::render(Painter& painter, const std::string& layer_name) {
painter.renderLine(*this, layer_name);
}
uint32_t LineBucket::size() const {
return length;
}
void LineBucket::bind() {
buffer->bind();
}
char *LineBucket::vertexOffset() const {
return BUFFER_OFFSET(start * 4 * sizeof(int16_t));
}

View File

@@ -96,7 +96,9 @@ void Painter::changeMatrix(const Tile::Ptr& tile) {
mat4::multiply(matrix, projMatrix, matrix);
// The extrusion matrix.
mat4::copy(exMatrix, projMatrix);
mat4::identity(exMatrix);
mat4::multiply(exMatrix, projMatrix, exMatrix);
mat4::rotate_z(exMatrix, exMatrix, transform.getAngle());
}
@@ -196,6 +198,8 @@ 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];
// Abort early.
if (!bucket.size()) return;
if (properties.hidden) return;
Color fill_color = properties.fill_color;
@@ -323,6 +327,10 @@ 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];
// Abort early.
if (!bucket.size()) return;
if (properties.hidden) return;
double width = properties.width;
double offset = (properties.offset || 0) / 2;
double inset = fmax(-1, offset - width / 2 - 0.5) + 1;
@@ -354,6 +362,7 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name) {
}
// TODO: Move this to transform?
const double tilePixelRatio = transform.getScale() / (1 << transform.getIntegerZoom()) / 8;
glUniform2f(lineShader->u_linewidth, outset, inset);
@@ -369,23 +378,18 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name) {
// }
bucket.buffer->bind();
glUniform1f(lineShader->u_point, 0);
char *vertex_index = BUFFER_OFFSET(bucket.start * 2 * sizeof(uint16_t));
bucket.bind();
char *vertex_index = bucket.vertexOffset();
glVertexAttribPointer(lineShader->a_pos, 4, GL_SHORT, false, 8, vertex_index);
glVertexAttribPointer(lineShader->a_extrude, 2, GL_BYTE, false, 8, vertex_index + 6);
glVertexAttribPointer(lineShader->a_linesofar, 2, GL_SHORT, false, 8, vertex_index + 4);
glDrawArrays(GL_TRIANGLE_STRIP, 0, bucket.size());
uint32_t begin = bucket.start;
uint32_t count = bucket.length;
glUniform1f(lineShader->u_point, 0);
glDrawArrays(GL_TRIANGLE_STRIP, begin, count);
if (bucket.join == JoinType::Round) {
if (bucket.geometry.join == JoinType::Round) {
glUniform1f(lineShader->u_point, 1);
glDrawArrays(GL_POINTS, begin, count);
glDrawArrays(GL_POINTS, 0, bucket.size());
}
// statistics

View File

@@ -1,4 +1,5 @@
#version 120
// shared
uniform float u_debug;
uniform vec2 u_linewidth;

View File

@@ -11,9 +11,9 @@ std::ostream& llmr::operator<<(std::ostream& os, const BucketDescription& bucket
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;
os << " - cap: " << (uint32_t)bucket.geometry.cap << std::endl;
os << " - join: " << (uint32_t)bucket.geometry.join << std::endl;
os << " - font: " << bucket.geometry.font << std::endl;
os << " - font_size: " << bucket.geometry.font_size << std::endl;
return os;
}

View File

@@ -47,13 +47,13 @@ std::pair<std::string, BucketDescription> Style::parseBucket(pbf data) {
} 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();
bucket.geometry.cap = (CapType)data.varint();
} else if (data.tag == 8) { // join
bucket.join = (JoinType)data.varint();
bucket.geometry.join = (JoinType)data.varint();
} else if (data.tag == 9) { // font
bucket.font = data.string();
bucket.geometry.font = data.string();
} else if (data.tag == 10) { // font_size
bucket.font_size = data.float32();
bucket.geometry.font_size = data.float32();
} else {
data.skip();
}
@@ -226,7 +226,7 @@ void Style::cascade(float z) {
// 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.width = 2; //layer.width(z);
stroke.offset = layer.offset(z);
stroke.color = layer.color;
stroke.opacity = layer.opacity(z);