Files
MapLibreParticleLab/src/mbgl/renderer/fill_bucket.cpp
2016-06-02 14:51:39 -07:00

168 lines
6.0 KiB
C++

#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/layer/fill_layer.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/outline_shader.hpp>
#include <mbgl/shader/outlinepattern_shader.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/platform/log.hpp>
#include <mapbox/earcut.hpp>
#include <cassert>
struct GeometryTooLongException : std::exception {};
using namespace mbgl;
namespace mapbox {
namespace util {
template <> struct nth<0, GeometryCoordinate> {
inline static int64_t get(const GeometryCoordinate& t) { return t.x; };
};
template <> struct nth<1, GeometryCoordinate> {
inline static int64_t get(const GeometryCoordinate& t) { return t.y; };
};
}
}
FillBucket::FillBucket() {
}
FillBucket::~FillBucket() {
}
void FillBucket::addGeometry(const GeometryCollection& geometry) {
for (auto& polygon : classifyRings(geometry)) {
// Optimize polygons with many interior rings for earcut tesselation.
limitHoles(polygon, 500);
std::size_t totalVertices = 0;
for (const auto& ring : polygon) {
totalVertices += ring.size();
if (totalVertices > 65535)
throw GeometryTooLongException();
}
for (const auto& ring : polygon) {
std::size_t nVertices = ring.size();
if (nVertices == 0)
continue;
if (lineGroups.empty() || lineGroups.back()->vertex_length + nVertices > 65535)
lineGroups.emplace_back(std::make_unique<LineGroup>());
LineGroup& lineGroup = *lineGroups.back();
GLsizei lineIndex = lineGroup.vertex_length;
vertexBuffer.add(ring[0].x, ring[0].y);
lineElementsBuffer.add(lineIndex + nVertices - 1, lineIndex);
for (uint32_t i = 1; i < nVertices; i++) {
vertexBuffer.add(ring[i].x, ring[i].y);
lineElementsBuffer.add(lineIndex + i - 1, lineIndex + i);
}
lineGroup.vertex_length += nVertices;
lineGroup.elements_length += nVertices;
}
std::vector<uint32_t> indices = mapbox::earcut(polygon);
std::size_t nIndicies = indices.size();
assert(nIndicies % 3 == 0);
if (triangleGroups.empty() || triangleGroups.back()->vertex_length + totalVertices > 65535) {
triangleGroups.emplace_back(std::make_unique<TriangleGroup>());
}
TriangleGroup& triangleGroup = *triangleGroups.back();
GLsizei triangleIndex = triangleGroup.vertex_length;
for (uint32_t i = 0; i < nIndicies; i += 3) {
triangleElementsBuffer.add(triangleIndex + indices[i],
triangleIndex + indices[i + 1],
triangleIndex + indices[i + 2]);
}
triangleGroup.vertex_length += totalVertices;
triangleGroup.elements_length += nIndicies / 3;
}
}
void FillBucket::upload(gl::ObjectStore& store) {
vertexBuffer.upload(store);
triangleElementsBuffer.upload(store);
lineElementsBuffer.upload(store);
// From now on, we're going to render during the opaque and translucent pass.
uploaded = true;
}
void FillBucket::render(Painter& painter,
const Layer& layer,
const UnwrappedTileID& tileID,
const mat4& matrix) {
painter.renderFill(*this, *layer.as<FillLayer>(), tileID, matrix);
}
bool FillBucket::hasData() const {
return !triangleGroups.empty() || !lineGroups.empty();
}
bool FillBucket::needsClipping() const {
return true;
}
void FillBucket::drawElements(PlainShader& shader, gl::ObjectStore& store) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
assert(group);
group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * triangleElementsBuffer.itemSize;
}
}
void FillBucket::drawElements(PatternShader& shader, gl::ObjectStore& store) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : triangleGroups) {
assert(group);
group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * triangleElementsBuffer.itemSize;
}
}
void FillBucket::drawVertices(OutlineShader& shader, gl::ObjectStore& store) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : lineGroups) {
assert(group);
group->array[0].bind(shader, vertexBuffer, lineElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_LINES, group->elements_length * 2, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * lineElementsBuffer.itemSize;
}
}
void FillBucket::drawVertices(OutlinePatternShader& shader, gl::ObjectStore& store) {
GLbyte* vertex_index = BUFFER_OFFSET(0);
GLbyte* elements_index = BUFFER_OFFSET(0);
for (auto& group : lineGroups) {
assert(group);
group->array[1].bind(shader, vertexBuffer, lineElementsBuffer, vertex_index, store);
MBGL_CHECK_ERROR(glDrawElements(GL_LINES, group->elements_length * 2, GL_UNSIGNED_SHORT, elements_index));
vertex_index += group->vertex_length * vertexBuffer.itemSize;
elements_index += group->elements_length * lineElementsBuffer.itemSize;
}
}