From bf1b409da13d508ac3b0f808a80ef6292aa3aa8b Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 21 Jun 2015 20:28:26 -0300 Subject: [PATCH] Smooth lines now draw the entire line in 1 OpenGL draw call, rather than 2. --- src/modules/graphics/opengl/Polyline.cpp | 90 +++++++++++++++++------- src/modules/graphics/opengl/Polyline.h | 15 ++-- 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/modules/graphics/opengl/Polyline.cpp b/src/modules/graphics/opengl/Polyline.cpp index de4ed478c..a55284beb 100644 --- a/src/modules/graphics/opengl/Polyline.cpp +++ b/src/modules/graphics/opengl/Polyline.cpp @@ -75,12 +75,40 @@ void Polyline::render(const float *coords, size_t count, size_t size_hint, float renderEdge(anchors, normals, s, len_s, ns, q, r, halfwidth); vertex_count = normals.size(); - vertices = new Vector[vertex_count]; + + size_t extra_vertices = 0; + + if (draw_overdraw) + { + calc_overdraw_vertex_count(is_looping); + + // When drawing overdraw lines using triangle strips, we want to add an + // extra degenerate triangle in between the core line and the overdraw + // line in order to break up the strip into two. This will let us draw + // everything in one draw call. + if (draw_mode == GL_TRIANGLE_STRIP) + extra_vertices = 2; + } + + // Use a single linear array for both the regular and overdraw vertices. + vertices = new Vector[vertex_count + extra_vertices + overdraw_vertex_count]; + for (size_t i = 0; i < vertex_count; ++i) vertices[i] = anchors[i] + normals[i]; if (draw_overdraw) + { + overdraw = vertices + vertex_count + extra_vertices; + overdraw_vertex_start = vertex_count + extra_vertices; render_overdraw(normals, pixel_size, is_looping); + } + + // Add the degenerate triangle strip. + if (extra_vertices) + { + vertices[vertex_count + 0] = vertices[vertex_count - 1]; + vertices[vertex_count + 1] = vertices[overdraw_vertex_start]; + } } void NoneJoinPolyline::renderEdge(std::vector &anchors, std::vector &normals, @@ -238,10 +266,13 @@ void BevelJoinPolyline::renderEdge(std::vector &anchors, std::vector &normals, float pixel_size, bool is_looping) +void Polyline::calc_overdraw_vertex_count(bool is_looping) { overdraw_vertex_count = 2 * vertex_count + (is_looping ? 0 : 2); - overdraw = new Vector[overdraw_vertex_count]; +} + +void Polyline::render_overdraw(const std::vector &normals, float pixel_size, bool is_looping) +{ // upper segment for (size_t i = 0; i + 1 < vertex_count; i += 2) { @@ -284,10 +315,13 @@ void Polyline::render_overdraw(const std::vector &normals, float pixel_s } } -void NoneJoinPolyline::render_overdraw(const std::vector &/*normals*/, float pixel_size, bool /*is_looping*/) +void NoneJoinPolyline::calc_overdraw_vertex_count(bool /*is_looping*/) { overdraw_vertex_count = 4 * (vertex_count-2); // less than ideal - overdraw = new Vector[overdraw_vertex_count]; +} + +void NoneJoinPolyline::render_overdraw(const std::vector &/*normals*/, float pixel_size, bool /*is_looping*/) +{ for (size_t i = 2; i + 3 < vertex_count; i += 4) { Vector s = vertices[i] - vertices[i+3]; @@ -322,8 +356,6 @@ Polyline::~Polyline() { if (vertices) delete[] vertices; - if (overdraw) - delete[] overdraw; } void Polyline::draw() @@ -331,13 +363,16 @@ void Polyline::draw() OpenGL::TempDebugGroup debuggroup("Line draw"); GLushort *indices = nullptr; + Color *colors = nullptr; + + size_t total_vertex_count = vertex_count; + if (overdraw) + total_vertex_count = overdraw_vertex_start + overdraw_vertex_count; // TODO: We should probably be using a reusable index buffer. if (use_quad_indices) { - size_t numindices = (vertex_count / 4) * 6; - if (overdraw) - numindices = std::max(numindices, (overdraw_vertex_count / 4) * 6); + size_t numindices = (total_vertex_count / 4) * 6; try { @@ -366,39 +401,40 @@ void Polyline::draw() gl.prepareDraw(); - // draw the core line gl.bindTexture(gl.getDefaultTexture()); glEnableVertexAttribArray(ATTRIB_POS); - glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, vertices); - - if (use_quad_indices) - gl.drawElements(draw_mode, (int) (vertex_count / 4) * 6, GL_UNSIGNED_SHORT, indices); - else - gl.drawArrays(draw_mode, 0, (int) vertex_count); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, vertices + vertex_start); if (overdraw) { - // prepare colors: - Color *colors = new Color[overdraw_vertex_count]; - fill_color_array(colors); + // Prepare colors. Set the core line's colors to white, and the overdraw + // line's colors to white on one side and transparent on the other. + colors = new Color[total_vertex_count]; + memset(colors, 255, overdraw_vertex_start * sizeof(Color)); + fill_color_array(colors + overdraw_vertex_start); glEnableVertexAttribArray(ATTRIB_COLOR); glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors); - glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, overdraw); + } - if (use_quad_indices) - gl.drawElements(draw_mode, (int) (overdraw_vertex_count / 4) * 6, GL_UNSIGNED_SHORT, indices); - else - gl.drawArrays(draw_mode, 0, (int) overdraw_vertex_count); + // Draw the core line and the overdraw in a single draw call. We can do this + // because the vertex array contains both the core line and the overdraw + // vertices. + if (use_quad_indices) + gl.drawElements(draw_mode, (int) (total_vertex_count / 4) * 6, GL_UNSIGNED_SHORT, indices); + else + gl.drawArrays(draw_mode, 0, (int) total_vertex_count); + glDisableVertexAttribArray(ATTRIB_POS); + + if (overdraw) + { glDisableVertexAttribArray(ATTRIB_COLOR); glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f); delete[] colors; } - glDisableVertexAttribArray(ATTRIB_POS); - if (indices) delete[] indices; } diff --git a/src/modules/graphics/opengl/Polyline.h b/src/modules/graphics/opengl/Polyline.h index 383d5925e..132002649 100644 --- a/src/modules/graphics/opengl/Polyline.h +++ b/src/modules/graphics/opengl/Polyline.h @@ -46,12 +46,14 @@ class Polyline { public: Polyline(GLenum mode = GL_TRIANGLE_STRIP, bool quadindices = false) - : vertices(NULL) - , overdraw(NULL) + : vertices(nullptr) + , overdraw(nullptr) , vertex_count(0) , overdraw_vertex_count(0) , draw_mode(mode) , use_quad_indices(quadindices) + , vertex_start(0) + , overdraw_vertex_start(0) {} virtual ~Polyline(); @@ -70,6 +72,7 @@ public: void draw(); protected: + virtual void calc_overdraw_vertex_count(bool is_looping); virtual void render_overdraw(const std::vector &normals, float pixel_size, bool is_looping); virtual void fill_color_array(Color *colors); @@ -94,6 +97,8 @@ protected: size_t overdraw_vertex_count; GLenum draw_mode; bool use_quad_indices; + size_t vertex_start; + size_t overdraw_vertex_start; }; // Polyline @@ -112,13 +117,13 @@ public: void render(const float *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw) { Polyline::render(vertices, count, 2 * count - 4, halfwidth, pixel_size, draw_overdraw); - // discard the first and last two vertices. (these are redundant) - for (size_t i = 0; i < vertex_count - 2; ++i) - this->vertices[i] = this->vertices[i+2]; + // discard the first two vertices. (these are redundant) + vertex_start = 2; vertex_count -= 2; } protected: + virtual void calc_overdraw_vertex_count(bool is_looping); virtual void render_overdraw(const std::vector &normals, float pixel_size, bool is_looping); virtual void fill_color_array(Color *colors); virtual void renderEdge(std::vector &anchors, std::vector &normals,