diff --git a/src/renderer/fill_bucket.cpp b/src/renderer/fill_bucket.cpp index d63c28144..da066048a 100644 --- a/src/renderer/fill_bucket.cpp +++ b/src/renderer/fill_bucket.cpp @@ -35,25 +35,25 @@ FillBucket::FillBucket(const std::shared_ptr& vertexBuffer, const std::shared_ptr& lineElementsBuffer, const BucketDescription& bucket_desc) : geom_desc(bucket_desc.geometry), - allocator(new TESSalloc { - &alloc, - &realloc, - &free, - nullptr, // userData - 64, // meshEdgeBucketSize - 64, // meshVertexBucketSize - 32, // meshFaceBucketSize - 64, // dictNodeBucketSize - 8, // regionBucketSize - 128, // extraVertices allocated for the priority queue. - }), - tesselator(tessNewTess(allocator)), - vertexBuffer(vertexBuffer), - triangleElementsBuffer(triangleElementsBuffer), - lineElementsBuffer(lineElementsBuffer), - vertex_start(vertexBuffer->index()), - triangle_elements_start(triangleElementsBuffer->index()), - line_elements_start(lineElementsBuffer->index()) { + allocator(new TESSalloc { + &alloc, + &realloc, + &free, + nullptr, // userData + 64, // meshEdgeBucketSize + 64, // meshVertexBucketSize + 32, // meshFaceBucketSize + 64, // dictNodeBucketSize + 8, // regionBucketSize + 128, // extraVertices allocated for the priority queue. +}), +tesselator(tessNewTess(allocator)), +vertexBuffer(vertexBuffer), +triangleElementsBuffer(triangleElementsBuffer), +lineElementsBuffer(lineElementsBuffer), +vertex_start(vertexBuffer->index()), +triangle_elements_start(triangleElementsBuffer->index()), +line_elements_start(lineElementsBuffer->index()) { assert(tesselator); } @@ -101,65 +101,78 @@ void FillBucket::tessellate() { // First combine contours and then triangulate, this removes unnecessary inner vertices. if (tessTesselate(tesselator, TESS_WINDING_POSITIVE, TESS_BOUNDARY_CONTOURS, 0, 0, 0)) { const TESSreal *vertices = tessGetVertices(tesselator); - const int contour_element_count = tessGetElementCount(tesselator); - const TESSindex *contour_elements_p = tessGetElements(tesselator); - std::vector contour_elements = { contour_elements_p, contour_elements_p + contour_element_count * 2 }; + const int vertex_count = tessGetVertexCount(tesselator); + const int element_count = tessGetElementCount(tesselator); + const TESSindex *elements = tessGetElements(tesselator); - for (int i = 0; i < contour_element_count; ++i) { - const TESSindex group_start = contour_elements[i * 2]; - const TESSindex group_count = contour_elements[i * 2 + 1]; + if (vertex_count > 65536) { + throw geometry_too_long_exception(); + } + + for (int i = 0; i < vertex_count; ++i) { + vertexBuffer->add(vertices[i * 2], vertices[i * 2 + 1]); + } + + + if (!lineGroups.size() || (lineGroups.back().vertex_length + vertex_count > 65535)) { + // Move to a new group because the old one can't hold the geometry. + lineGroups.emplace_back(); + } + + // We're generating triangle fans, so we always start with the first + // coordinate in this polygon. + line_group_type& group = lineGroups.back(); + uint32_t index = group.vertex_length; + + + for (int i = 0; i < element_count; ++i) { + const TESSindex group_start = elements[i * 2]; + const TESSindex group_end = group_start + elements[i * 2 + 1]; + + for (int i = group_start; i < group_end; ++i) { + const TESSindex prevI = (i == group_start ? group_end : i) - 1; + lineElementsBuffer->add(index + prevI, index + i); + } + } + + // Add a line from the last vertex to the first vertex. + // lineElementsBuffer->add(index + vertex_count - 1, index); + + group.vertex_length += vertex_count; + group.elements_length += vertex_count; + + for (int i = 0; i < element_count; ++i) { + const TESSindex group_start = elements[i * 2]; + const TESSindex group_count = elements[i * 2 + 1]; const TESSreal *group_vertices = &vertices[group_start * 2]; tessAddContour(tesselator, 2, group_vertices, stride, group_count); } if (tessTesselate(tesselator, TESS_WINDING_POSITIVE, TESS_POLYGONS, vertices_per_group, 2, 0)) { - const TESSreal *vertices = tessGetVertices(tesselator); const TESSindex *vertex_indices = tessGetVertexIndices(tesselator); - const int vertex_count = tessGetVertexCount(tesselator); const TESSindex *elements = tessGetElements(tesselator); const int element_count = tessGetElementCount(tesselator); - - if (vertex_count > 65536) { - throw geometry_too_long_exception(); + if (!triangleGroups.size() || (triangleGroups.back().vertex_length + vertex_count > 65535)) { + // Move to a new group because the old one can't hold the geometry. + triangleGroups.emplace_back(); } - // Add vertices and create reverse index mapping for drawing the outline. - // std::map contour_vertices; - for (int i = 0; i < vertex_count; ++i) { - // contour_vertices[vertex_indices[i]] = i; - vertexBuffer->add(vertices[i * 2], vertices[i * 2 + 1]); + // We're generating triangle fans, so we always start with the first + // coordinate in this polygon. + triangle_group_type& group = triangleGroups.back(); + uint32_t index = group.vertex_length; + + for (int i = 0; i < element_count; ++i) { + const TESSindex *element_group = &elements[i * vertices_per_group]; + const TESSindex a = vertex_indices[element_group[0]]; + const TESSindex b = vertex_indices[element_group[1]]; + const TESSindex c = vertex_indices[element_group[2]]; + triangleElementsBuffer->add(index + a, index + b, index + c); } - { - if (!triangleGroups.size() || (triangleGroups.back().vertex_length + vertex_count > 65535)) { - // Move to a new group because the old one can't hold the geometry. - triangleGroups.emplace_back(); - } - - // We're generating triangle fans, so we always start with the first - // coordinate in this polygon. - triangle_group_type& group = triangleGroups.back(); - uint32_t index = group.vertex_length; - - - for (int i = 0; i < element_count; ++i) { - const TESSindex *element_group = &elements[i * vertices_per_group]; - - if (element_group[0] == TESS_UNDEF || element_group[1] == TESS_UNDEF || element_group[2] == TESS_UNDEF) { - throw std::runtime_error("element group is not a triangle"); - } - - triangleElementsBuffer->add( - index + element_group[0], - index + element_group[1], - index + element_group[2] - ); - } - - group.vertex_length += vertex_count; - group.elements_length += element_count; - } + group.vertex_length += vertex_count; + group.elements_length += element_count; } else { assert(false && "tesselation failed"); diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 87c212c5b..046acde87 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -180,50 +180,6 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons fill_color[2] *= properties.opacity; fill_color[3] *= properties.opacity; - // // 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 (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 { - // // 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. - // useProgram(plainShader->program); - // plainShader->setMatrix(matrix); - - // // Draw all groups - // bucket.drawElements(*plainShader); - - // // Now that we have the stencil mask in the stencil buffer, we can start - // // writing to the color buffer. - // glColorMask(true, true, true, true); - // } - - // 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 (properties.antialias) { @@ -252,9 +208,6 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons bucket.drawVertices(*outlineShader); } - // // Only draw regions that we marked - // glStencilFunc(GL_NOTEQUAL, 0x0, 0x3F); - if (false && properties.image.size() && *style.sprite) { // Draw texture fill ImagePosition imagePos = style.sprite->getPosition(properties.image, true); @@ -285,7 +238,6 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons // Draw a rectangle that covers the entire viewport. coveringPatternArray.bind(*patternShader, tileStencilBuffer, BUFFER_OFFSET(0)); glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.index()); - } else { // Draw filling rectangle. useProgram(plainShader->program); @@ -294,13 +246,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons // Draw the actual triangle fan into the stencil buffer. bucket.drawElements(*plainShader); - - // Draw a rectangle that covers the entire viewport. - // coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); - // glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.index()); } - - // glStencilFunc(GL_EQUAL, 0x80, 0x80); } void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id) {