summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2014-01-23 14:20:22 +0100
committerKonstantin Käfer <mail@kkaefer.com>2014-01-23 14:20:22 +0100
commit50021b730c6615d21aefa99f2f553640b43ff231 (patch)
tree0b23d06b12c2923881251cabdbe13c45f279e463 /src
parentb4a95be0b217ac8a73bdc57a0488865b2289d5f5 (diff)
downloadqtlocation-mapboxgl-50021b730c6615d21aefa99f2f553640b43ff231.tar.gz
move to layer system
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/geometry/fill_buffer.cpp16
-rw-r--r--src/map/layer.cpp3
-rw-r--r--src/map/tile.cpp192
-rw-r--r--src/renderer/fill_bucket.cpp103
-rw-r--r--src/renderer/painter.cpp257
6 files changed, 282 insertions, 290 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5e3aed9b2e..b4e3557643 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -10,6 +10,7 @@ SET(llmr_SOURCES
renderer/shader-line.cpp
renderer/shader-outline.cpp
renderer/shader.cpp
+ renderer/fill_bucket.cpp
shader/shaders.cpp
util/animation.cpp
util/mat4.cpp
diff --git a/src/geometry/fill_buffer.cpp b/src/geometry/fill_buffer.cpp
index 2f71bedc1d..4894361c36 100644
--- a/src/geometry/fill_buffer.cpp
+++ b/src/geometry/fill_buffer.cpp
@@ -4,14 +4,14 @@
using namespace llmr;
-fill_buffer::fill_buffer()
+FillBuffer::FillBuffer()
: vertex_buffer(0),
element_buffer(0),
dirty(true) {
}
-fill_buffer::~fill_buffer() {
+FillBuffer::~FillBuffer() {
if (vertex_buffer != 0) {
glDeleteBuffers(1, &vertex_buffer);
vertex_buffer = 0;
@@ -22,33 +22,33 @@ fill_buffer::~fill_buffer() {
}
}
-uint32_t fill_buffer::vertex_length() const {
+uint32_t FillBuffer::vertex_length() const {
// We store 2 coordinates per vertex
return vertices.size() / 2;
}
-uint32_t fill_buffer::elements_length() const {
+uint32_t FillBuffer::elements_length() const {
// A triangle has 3 indices
return elements.size() / 3;
}
-void fill_buffer::addDegenerate() {
+void FillBuffer::addDegenerate() {
vertices.push_back(32767);
vertices.push_back(0);
}
-void fill_buffer::addCoordinate(int16_t x, int16_t y) {
+void FillBuffer::addCoordinate(int16_t x, int16_t y) {
vertices.push_back(x);
vertices.push_back(y);
}
-void fill_buffer::addElements(uint16_t a, uint16_t b, uint16_t c) {
+void FillBuffer::addElements(uint16_t a, uint16_t b, uint16_t c) {
elements.push_back(a);
elements.push_back(b);
elements.push_back(c);
}
-void fill_buffer::bind() {
+void FillBuffer::bind() {
if (vertex_buffer == 0) {
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
diff --git a/src/map/layer.cpp b/src/map/layer.cpp
new file mode 100644
index 0000000000..56e907c0af
--- /dev/null
+++ b/src/map/layer.cpp
@@ -0,0 +1,3 @@
+#include <llmr/map/layer.hpp>
+
+using namespace llmr;
diff --git a/src/map/tile.cpp b/src/map/tile.cpp
index 4d744cb971..983ccff947 100644
--- a/src/map/tile.cpp
+++ b/src/map/tile.cpp
@@ -8,6 +8,7 @@
#include <llmr/util/pbf.hpp>
#include <llmr/util/string.hpp>
#include <llmr/geometry/geometry.hpp>
+#include <llmr/renderer/fill_bucket.hpp>
#include <cmath>
using namespace llmr;
@@ -41,6 +42,7 @@ std::forward_list<Tile::ID> Tile::children(const ID& id, int32_t z) {
Tile::Tile(ID id)
: id(id),
state(initial),
+ fillBuffer(std::make_shared<FillBuffer>()),
data(0),
bytes(0) {
@@ -92,23 +94,13 @@ bool Tile::parse() {
try {
while (tile.next()) {
if (tile.tag == 3) { // layer
- uint32_t bytes = (uint32_t)tile.varint();
- parseLayer(tile.data, bytes);
- tile.skipBytes(bytes);
+ parseLayer(tile.message());
} else {
tile.skip();
}
}
- } catch (const pbf::exception& ex) {
- fprintf(stderr, "[%p] parsing tile [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what());
- cancel();
- return false;
- } catch (const Tile::exception& ex) {
- fprintf(stderr, "[%p] parsing tile [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what());
- cancel();
- return false;
} catch (const std::exception& ex) {
- fprintf(stderr, "[%p] general exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what());
+ fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what());
cancel();
return false;
}
@@ -119,39 +111,23 @@ bool Tile::parse() {
state = ready;
}
- // int i = 0;
- // for (const fill_index& index : fillIndices) {
- // fprintf(stderr, "[%p] %d: vertex % 8d / % 8d\n", this, i, index.vertex_start, index.vertex_length);
- // fprintf(stderr, "[%p] %d: elements % 8d / % 8d\n", this, i, index.elements_start, index.elements_length);
- // i++;
- // }
-
return true;
}
-void Tile::parseLayer(const uint8_t *data, uint32_t bytes) {
- pbf layer(data, bytes);
- std::string name;
-
- uint32_t vertex_start = fillBuffer.vertex_length();
- uint32_t elements_start = fillBuffer.elements_length();
- fillIndices.emplace_back(vertex_start, elements_start);
-
+void Tile::parseLayer(const pbf data) {
+ pbf layer(data);
while (layer.next()) {
if (layer.tag == 1) {
- name = layer.string();
- fillIndices.back().name = name;
- } else if (layer.tag == 2) {
- uint32_t bytes = (uint32_t)layer.varint();
- parseFeature(layer.data, bytes);
- layer.skipBytes(bytes);
+ std::string name = layer.string();
+ if (name == "water") {
+ layers.emplace_front(name, createFillBucket(data));
+ }
} else {
layer.skip();
}
}
}
-
enum geom_type {
Unknown = 0,
Point = 1,
@@ -159,126 +135,46 @@ enum geom_type {
Polygon = 3
};
+std::shared_ptr<Bucket> Tile::createFillBucket(const pbf data) {
+ pbf layer(data);
+ std::shared_ptr<FillBucket> bucket = std::make_shared<FillBucket>(fillBuffer);
-void Tile::parseFeature(const uint8_t *data, uint32_t bytes) {
- pbf feature(data, bytes);
-
- geom_type type = Unknown;
- pbf geom;
-
- while (feature.next()) {
- if (feature.tag == 1) {
- /*uint32_t id =*/ feature.varint();
- } else if (feature.tag == 2) {
- const uint8_t *tag_end = feature.data + feature.varint();
- while (feature.data < tag_end) {
- /*uint32_t key =*/ feature.varint();
- /*uint32_t value =*/ feature.varint();
+ while (layer.next()) {
+ if (layer.tag == 2) { // feature
+ pbf feature = layer.message();
+ pbf geometry;
+ geom_type type = Unknown;
+
+ while (feature.next()) {
+ if (feature.tag == 3) { // geometry type
+ type = (geom_type)feature.varint();
+ } else if (feature.tag == 4) { // geometry
+ geometry = feature.message();
+ } else {
+ feature.skip();
+ }
}
- } else if (feature.tag == 3) {
- type = (geom_type)feature.varint();
- } else if (feature.tag == 4) {
- geom = feature.message();
- } else {
- feature.skip();
- }
- }
-
- if (geom) {
- if (type == LineString) {
- addLineGeometry(geom);
- } else if (type == Polygon) {
- addFillGeometry(geom);
- }
- }
-}
-
-void Tile::addFillGeometry(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();
- }
+ if (type == Polygon && geometry) {
+ bucket->addGeometry(geometry);
}
- line.emplace_back(x, y);
- }
- if (line.size()) {
- lines.push_back(line);
+ } else {
+ layer.skip();
}
}
- for (const std::vector<std::pair<int16_t, int16_t>>& line : lines) {
- uint32_t vertex_start = fillBuffer.vertex_length();
-
- fillBuffer.addDegenerate();
- for (const std::pair<int16_t, int16_t>& coord : line) {
- fillBuffer.addCoordinate(coord.first, coord.second);
- }
-
- uint32_t vertex_end = fillBuffer.vertex_length();
-
- if (vertex_end - vertex_start > 65535) {
- throw geometry_too_long_exception();
- }
-
- if (!fillIndices.size()) {
- // Create a new index because there is none yet.
- throw std::runtime_error("no index yet");
- }
-
- fill_index& index = fillIndices.back();
- if (!index.groups.size()) {
- throw std::runtime_error("no group yet");
- }
-
- uint32_t vertex_count = vertex_end - vertex_start;
- index.length += vertex_count;
-
- 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();
- }
-
- fill_index::group& group = index.groups.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;
-
- assert(firstIndex + vertex_count - 1 < 65536);
-
- uint32_t elements_start = fillBuffer.elements_length();
-
- for (uint32_t i = 2; i < vertex_count; i++) {
- fillBuffer.addElements(firstIndex, firstIndex + i - 1, firstIndex + i);
- }
-
- uint32_t elements_end = fillBuffer.elements_length();
- uint32_t elements_count = elements_end - elements_start;
- group.vertex_length += vertex_count;
- group.elements_length += elements_count;
- }
+ return bucket;
}
-void Tile::addLineGeometry(pbf& geom) {
- Geometry geometry(geom);
-
- Geometry::command cmd;
- int32_t x, y;
- while ((cmd = geometry.next(x, y)) != Geometry::end) {
- if (cmd == Geometry::move_to) {
- lineVertex.addDegenerate();
- }
- lineVertex.addCoordinate(x, y);
- }
-}
+// void Tile::addLineGeometry(pbf& geom) {
+// Geometry geometry(geom);
+
+// Geometry::command cmd;
+// int32_t x, y;
+// while ((cmd = geometry.next(x, y)) != Geometry::end) {
+// if (cmd == Geometry::move_to) {
+// lineVertex.addDegenerate();
+// }
+// lineVertex.addCoordinate(x, y);
+// }
+// }
diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp
new file mode 100644
index 0000000000..73e6d8d029
--- /dev/null
+++ b/src/renderer/fill_bucket.cpp
@@ -0,0 +1,103 @@
+#include <llmr/renderer/fill_bucket.hpp>
+#include <llmr/geometry/fill_buffer.hpp>
+#include <llmr/geometry/geometry.hpp>
+
+#include <llmr/renderer/painter.hpp>
+#include <llmr/style/style.hpp>
+
+#include <cassert>
+
+struct geometry_too_long_exception : std::exception {};
+
+using namespace llmr;
+
+FillBucket::FillBucket(const std::shared_ptr<FillBuffer>& buffer)
+ : buffer(buffer),
+ vertex_start(buffer->vertex_length()),
+ elements_start(buffer->elements_length()),
+ 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();
+ }
+ }
+ line.emplace_back(x, y);
+ }
+ if (line.size()) {
+ lines.push_back(line);
+ }
+ }
+
+ 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_end = buffer->vertex_length();
+
+ if (vertex_end - vertex_start > 65535) {
+ throw geometry_too_long_exception();
+ }
+
+ FillBucket& index = *this;
+ if (!index.groups.size()) {
+ index.groups.emplace_back();
+ }
+
+ uint32_t vertex_count = vertex_end - vertex_start;
+ index.length += vertex_count;
+
+ 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();
+ }
+
+ group& group = index.groups.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;
+
+ assert(firstIndex + vertex_count - 1 < 65536);
+
+ uint32_t elements_start = buffer->elements_length();
+
+ 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::draw(const Style& style, const std::string& layerName) {
+
+}
+
+void FillBucket::render(Painter& painter) {
+ // TODO: obtain the correct style information for this layer
+ FillStyle style;
+ style.fill_color = {{ 0, 0, 1, 0.5 }};
+ style.stroke_color = style.fill_color;
+
+ painter.renderFill(*this, style);
+}
diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp
index 53ffc79eb6..6b71b3031d 100644
--- a/src/renderer/painter.cpp
+++ b/src/renderer/painter.cpp
@@ -8,8 +8,11 @@
#include <llmr/platform/gl.hpp>
#include <llmr/map/settings.hpp>
-#include <cmath>
+#include <llmr/renderer/fill_bucket.hpp>
+#include <llmr/style/style.hpp>
+#include <cmath>
+#include <array>
#include <numeric>
using namespace llmr;
@@ -17,9 +20,14 @@ using namespace llmr;
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
GLshort tile_stencil_vertices[] = {
+ // top left triangle
0, 0,
4096, 0,
0, 4096,
+
+ // bottom right triangle
+ 4096, 0,
+ 0, 4096,
4096, 4096
};
@@ -124,7 +132,7 @@ void Painter::drawClippingMask() {
glBindBuffer(GL_ARRAY_BUFFER, tile_stencil_buffer);
glVertexAttribPointer(lineShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
glUniform4f(lineShader->u_color, 1.0f, 0.0f, 1.0f, 1.0f);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(tile_stencil_vertices));
+ glDrawArrays(GL_TRIANGLES, 0, sizeof(tile_stencil_vertices));
// glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x80, 0x80);
@@ -152,9 +160,8 @@ void Painter::render(const Tile::Ptr& tile) {
switchShader(outlineShader);
glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix);
- glStencilFunc(GL_EQUAL, 0x80, 0x80);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- // glDisable(GL_STENCIL_TEST);
+ // glStencilFunc(GL_EQUAL, 0x80, 0x80);
+ // glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// draw lines:
tile->lineVertex.bind();
@@ -164,12 +171,8 @@ void Painter::render(const Tile::Ptr& tile) {
glLineWidth(2.0f);
glDrawArrays(GL_LINE_STRIP, 0, tile->lineVertex.length());
- // draw fills:
-
- // TODO: expose this to the stylesheet
-
- for (const Tile::fill_index& index : tile->fillIndices) {
- renderFill(tile, index);
+ for (Layer& layer : tile->layers) {
+ layer.bucket->render(*this);
}
if (settings.debug) {
@@ -179,145 +182,131 @@ void Painter::render(const Tile::Ptr& tile) {
renderBackground();
}
-void Painter::renderFill(const std::shared_ptr<Tile>& tile, const Tile::fill_index& index) {
- float color[4] = { 1.0, 0.0, 0.0, 1.0 };
- float alpha = color[3];
-
- // TODO: expose this to the stylesheet.
- bool evenodd = false;
- bool background = false;
- bool antialiasing = true;
- bool stroke = false;
-
- if (!background) {
- // Draw the stencil mask.
- {
- // We're only drawing to the first seven bits (== support a maximum of
- // 127 overlapping polygons in one place before we get rendering errors).
- glStencilMask(0x3F);
- glClear(GL_STENCIL_BUFFER_BIT);
-
- // Draw front facing triangles. Wherever the 0x80 bit is 1, we are
- // increasing the lower 7 bits by one if the triangle is a front-facing
- // triangle. This means that all visible polygons should be in CCW
- // orientation, while all holes (see below) are in CW orientation.
- glStencilFunc(GL_NOTEQUAL, 0x80, 0x80);
-
- if (evenodd) {
- // When we draw an even/odd winding fill, we just invert all the bits.
- glStencilOp(GL_INVERT, GL_KEEP, GL_KEEP);
- } else {
- // When we do a nonzero fill, we count the number of times a pixel is
- // covered by a counterclockwise polygon, and subtract the number of
- // times it is "uncovered" by a clockwise polygon.
- glStencilOpSeparate(GL_FRONT, GL_INCR_WRAP, GL_KEEP, GL_KEEP);
- glStencilOpSeparate(GL_BACK, GL_DECR_WRAP, GL_KEEP, GL_KEEP);
- }
+void Painter::renderFill(const FillBucket& bucket, const FillStyle& style) {
+ // Draw the stencil mask.
+ {
+ // We're only drawing to the first seven bits (== support a maximum of
+ // 127 overlapping polygons in one place before we get rendering errors).
+ glStencilMask(0x3F);
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ // Draw front facing triangles. Wherever the 0x80 bit is 1, we are
+ // increasing the lower 7 bits by one if the triangle is a front-facing
+ // triangle. This means that all visible polygons should be in CCW
+ // orientation, while all holes (see below) are in CW orientation.
+ glStencilFunc(GL_NOTEQUAL, 0x80, 0x80);
+
+ if (style.winding == EvenOdd) {
+ // When we draw an even/odd winding fill, we just invert all the bits.
+ glStencilOp(GL_INVERT, GL_KEEP, GL_KEEP);
+ } else {
+ // When we do a nonzero fill, we count the number of times a pixel is
+ // covered by a counterclockwise polygon, and subtract the number of
+ // times it is "uncovered" by a clockwise polygon.
+ glStencilOpSeparate(GL_FRONT, GL_INCR_WRAP, GL_KEEP, GL_KEEP);
+ glStencilOpSeparate(GL_BACK, GL_DECR_WRAP, GL_KEEP, GL_KEEP);
+ }
- // When drawing a shape, we first draw all shapes to the stencil buffer
- // and incrementing all areas where polygons are
- glColorMask(false, false, false, false);
-
- // Draw the actual triangle fan into the stencil buffer.
- switchShader(fillShader);
- glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix);
-
- // Draw all groups
- char *vertex_index = BUFFER_OFFSET(index.vertex_start * 2 * sizeof(uint16_t));
- char *elements_index = BUFFER_OFFSET(index.elements_start * 3 * sizeof(uint16_t));
- tile->fillBuffer.bind();
- for (const Tile::fill_index::group& group : index.groups) {
- glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, vertex_index);
- glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index);
- vertex_index += group.vertex_length * 2 * sizeof(uint16_t);
- elements_index += group.elements_length * 3 * sizeof(uint16_t);
- }
+ // When drawing a shape, we first draw all shapes to the stencil buffer
+ // and incrementing all areas where polygons are
+ glColorMask(false, false, false, false);
+
+ // Draw the actual triangle fan into the stencil buffer.
+ switchShader(fillShader);
+ glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix);
- // Now that we have the stencil mask in the stencil buffer, we can start
- // writing to the color buffer.
- glColorMask(true, true, true, true);
+ // Draw all groups
+ char *vertex_index = BUFFER_OFFSET(bucket.vertex_start * 2 * sizeof(uint16_t));
+ char *elements_index = BUFFER_OFFSET(bucket.elements_start * 3 * sizeof(uint16_t));
+ bucket.buffer->bind();
+ for (const auto& group : bucket.groups) {
+ glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, vertex_index);
+ glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index);
+ vertex_index += group.vertex_length * 2 * sizeof(uint16_t);
+ elements_index += group.elements_length * 3 * sizeof(uint16_t);
}
- // From now on, we don't want to update the stencil buffer anymore.
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilMask(0x0);
-
- // Because we're drawing top-to-bottom, and we update the stencil mask
- // below, we have to draw the outline first (!)
- if (antialiasing) {
- switchShader(outlineShader);
- glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix);
- glLineWidth(2);
-
- if (stroke) {
- // If we defined a different color for the fill outline, we are
- // going to ignore the bits in 0x3F and just care about the global
- // clipping mask.
- glStencilFunc(GL_EQUAL, 0x80, 0x80);
- } else {
- // Otherwise, we only want to draw the antialiased parts that are
- // *outside* the current shape. This is important in case the fill
- // or stroke color is translucent. If we wouldn't clip to outside
- // the current shape, some pixels from the outline stroke overlapped
- // the (non-antialiased) fill.
- glStencilFunc(GL_EQUAL, 0x80, 0xBF);
- }
+ // Now that we have the stencil mask in the stencil buffer, we can start
+ // writing to the color buffer.
+ glColorMask(true, true, true, true);
+ }
- glUniform2f(outlineShader->u_world, transform.fb_width, transform.fb_height);
+ // From now on, we don't want to update the stencil buffer anymore.
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilMask(0x0);
+
+ // Because we're drawing top-to-bottom, and we update the stencil mask
+ // below, we have to draw the outline first (!)
+ if (style.antialiasing) {
+ switchShader(outlineShader);
+ glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix);
+ glLineWidth(2);
+
+ if (style.stroke_color != style.fill_color) {
+ // If we defined a different color for the fill outline, we are
+ // going to ignore the bits in 0x3F and just care about the global
+ // clipping mask.
+ glStencilFunc(GL_EQUAL, 0x80, 0x80);
+ const Color& color = style.stroke_color;
+ glUniform4f(outlineShader->u_color, color[0], color[1], color[2], color[3]);
+ } else {
+ // Otherwise, we only want to draw the antialiased parts that are
+ // *outside* the current shape. This is important in case the fill
+ // or stroke color is translucent. If we wouldn't clip to outside
+ // the current shape, some pixels from the outline stroke overlapped
+ // the (non-antialiased) fill.
+ glStencilFunc(GL_EQUAL, 0x80, 0xBF);
+ const Color& color = style.fill_color;
glUniform4f(outlineShader->u_color, color[0], color[1], color[2], color[3]);
-
- // Draw the entire line
- char *vertex_index = BUFFER_OFFSET(index.vertex_start * 2 * sizeof(uint16_t));
- glVertexAttribPointer(outlineShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, vertex_index);
- glLineWidth(2.0f);
- glDrawArrays(GL_LINE_STRIP, 0, index.length);
}
- }
+ glUniform2f(outlineShader->u_world, transform.fb_width, transform.fb_height);
- // var imagePos = layerStyle.image && imageSprite.getPosition(layerStyle.image, true);
+ // Draw the entire line
+ char *vertex_index = BUFFER_OFFSET(bucket.vertex_start * 2 * sizeof(uint16_t));
+ glVertexAttribPointer(outlineShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, vertex_index);
+ glLineWidth(2.0f);
+ glDrawArrays(GL_LINE_STRIP, 0, bucket.length);
+ }
- // if (imagePos) {
- // // Draw texture fill
-
- // var factor = 8 / Math.pow(2, painter.transform.zoom - params.z);
- // var mix = painter.transform.z % 1.0;
- // var imageSize = [imagePos.size[0] * factor, imagePos.size[1] * factor];
-
- // var offset = [
- // (params.x * 4096) % imageSize[0],
- // (params.y * 4096) % imageSize[1]
- // ];
-
- // glSwitchShader(painter.patternShader, painter.posMatrix, painter.exMatrix);
- // glUniform1i(painter.patternShader.u_image, 0);
- // glUniform2fv(painter.patternShader.u_pattern_size, imageSize);
- // glUniform2fv(painter.patternShader.u_offset, offset);
- // glUniform2fv(painter.patternShader.u_rotate, [1, 1]);
- // glUniform2fv(painter.patternShader.u_pattern_tl, imagePos.tl);
- // glUniform2fv(painter.patternShader.u_pattern_br, imagePos.br);
- // glUniform4fv(painter.patternShader.u_color, color);
- // glUniform1f(painter.patternShader.u_mix, mix);
- // imageSprite.bind(gl, true);
-
- // } else {
+ // var imagePos = layerStyle.image && imageSprite.getPosition(layerStyle.image, true);
+ bool imagePos = false;
+ if (imagePos) {
+ // // Draw texture fill
+
+ // var factor = 8 / Math.pow(2, painter.transform.zoom - params.z);
+ // var mix = painter.transform.z % 1.0;
+ // var imageSize = [imagePos.size[0] * factor, imagePos.size[1] * factor];
+
+ // var offset = [
+ // (params.x * 4096) % imageSize[0],
+ // (params.y * 4096) % imageSize[1]
+ // ];
+
+ // glSwitchShader(painter.patternShader, painter.posMatrix, painter.exMatrix);
+ // glUniform1i(painter.patternShader.u_image, 0);
+ // glUniform2fv(painter.patternShader.u_pattern_size, imageSize);
+ // glUniform2fv(painter.patternShader.u_offset, offset);
+ // glUniform2fv(painter.patternShader.u_rotate, [1, 1]);
+ // glUniform2fv(painter.patternShader.u_pattern_tl, imagePos.tl);
+ // glUniform2fv(painter.patternShader.u_pattern_br, imagePos.br);
+ // glUniform4fv(painter.patternShader.u_color, color);
+ // glUniform1f(painter.patternShader.u_mix, mix);
+ // imageSprite.bind(gl, true);
+ } else {
// Draw filling rectangle.
switchShader(fillShader);
glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix);
- glUniform4f(fillShader->u_color, color[0], color[1], color[2], color[3]);
- // }
-
- if (background) {
- glStencilFunc(GL_EQUAL, 0x80, 0x80);
- } else {
- // Only draw regions that we marked
- glStencilFunc(GL_NOTEQUAL, 0x0, 0x3F);
+ glUniform4f(fillShader->u_color, style.fill_color[0], style.fill_color[1], style.fill_color[2], style.fill_color[3]);
}
+ // Only draw regions that we marked
+ glStencilFunc(GL_NOTEQUAL, 0x0, 0x3F);
+
// Draw a rectangle that covers the entire viewport.
glBindBuffer(GL_ARRAY_BUFFER, tile_stencil_buffer);
glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
- glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(tile_stencil_vertices));
+ glDrawArrays(GL_TRIANGLES, 0, sizeof(tile_stencil_vertices));
glStencilMask(0x00);
glStencilFunc(GL_EQUAL, 0x80, 0x80);
@@ -359,8 +348,8 @@ void Painter::renderBackground() {
// Draw the clipping mask
glBindBuffer(GL_ARRAY_BUFFER, tile_stencil_buffer);
glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
- glUniform4f(fillShader->u_color, 1.0f, 1.0f, 1.0f, 1.0f);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(tile_stencil_vertices));
+ glUniform4f(fillShader->u_color, 0.5f, 0.5f, 0.5f, 1.0f);
+ glDrawArrays(GL_TRIANGLES, 0, sizeof(tile_stencil_vertices));
}